React-Native: Can I store JWT in AsyncStorage because the tokens expire anyway? - reactjs

In my server I can set the JWT tokens to expire after a given period of time.
Can I simply have this in my app?
async function getUserDetails() {
const token = await AsyncStorage.getItem('token') //got this token from successful login
const data = await axios.get(apiurl+'&JWT='+token)
console.log(data)
}
By the time the attacker physically gets a hold of the phone, jailbreak it and connect it to her computer, the JWT must have expired? Or am I not understanding something here?

AsyncStorage can not expire data. you have to use a trick. when you are setting your token. just set another key as date equal to new Date(). then in the root of your project setup a function which get date from AsyncStorage and checks the time passed from now to the time you saved token. if its bigger than your desired time just remve token from AsyncStorage

By the way AsyncStorage is not secure. for saving your sensetive information you can use react-native-keychain

Related

How to manage JWT properly using React?

I am builing a member system with a lot of function like memo or post system...etc, so I think it's more safe to use JWT token, so I let my api return jwt token every time I sign in like below
{
"status": 200,
"message": "",
"data": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MGViYzI0MDRhNmVkNDU2NzUwOTk4YjEiLCJ1c2VybmFtZSI6ImpvaG4iLCJleHAiOjE2MjY5NTgwMzEuMjA3LCJpYXQiOjE2MjYzNTMyMzF9.3t_YzKPq4jk6UuIkzTgFaLoXD0Pq5ktmRFp7xg6dFYU"
}
And it contains userID and userName , but here's the problem , every time I have to use something else like userProfilePicture ,userFriend...etc , I have to make an API request, it's really meaningless to do
eventually I manage it like I used axio.interceptor to verify and before I assign my data to context state I fetch user's all data using this token and assign the data to state , Is'nt it the same way to just return all user's data without JWT?.
It seems to me that JWT Token is kind of useless, can anyone tell me that what's the real ,effiecent way to use JWT Token and what's the common managment?
Use can save your token JWT in localstorage... and call it in header of request (or fetch) when you call api...
But dont forget to set expired token of JWT to one week (or one month, or one year... its up to you)...
Or you can set configuration if your JWT, if your token is expired, it will still send the response to your app....

How to decode access token from Microsoft OAuth2

I am building a web application using CakePHP 4.1.
And it has authorization from Microsoft Active Directory(OAuth2).
What I am going to do is to decode the access token and redirect to Microsoft login page when it is expired.
So I can get token from authorization like this.
https://login.microsoftonline.com/TENANT_ID/oauth2/v2.0/authorize?client_id=CLIENT_ID&response_type=token&redirect_uri=LOGIN_REDIRECT_URI&response_mode=form_post&scope=offline_access https://graph.microsoft.com/.default'
I tried to decode using firebase/jwt, but I am not sure what should be $key.
JWT::decode($accessToken, $key, array('RS256'))
I can get the decoded result if I enter the token in jwt.ms
I don't have any special claims, so $key should be plain.
And I want to know if there is another way to decode jwt.
Firebase JWT only supports decoding with signature validation, so a key is always required.
You can manually decode the token, it's just JSON as base64, however without validation there's no way to know whether the information hasn't been forged, so I wouldn't trust any information obtained that way, not even the expiration time.
Usually OAuth APIs return an expiration time in the response for access token requests (and so does Microsofts Identity Platform API), which your app can store alongside the token and use for checking for possible token expiration.
Refreshing upon receiving invalid token errors from the API is usually an option too, then you don't need to care about the expiration time yourself at all.
I would certainly suggest any of those options over trusting arbitrary client data.
That being said, if you still want the unvalidated expiration time from the token, just do what Firebase JWT does internally:
$tks = \explode('.', $accessToken);
if (\count($tks) != 3) {
throw new \UnexpectedValueException('Wrong number of segments');
}
list($headb64, $bodyb64, $cryptob64) = $tks;
if (null === ($header = JWT::jsonDecode(JWT::urlsafeB64Decode($headb64)))) {
throw new \UnexpectedValueException('Invalid header encoding');
}
if (null === $payload = JWT::jsonDecode(JWT::urlsafeB64Decode($bodyb64))) {
throw new \UnexpectedValueException('Invalid claims encoding');
}
if (false === ($sig = JWT::urlsafeB64Decode($cryptob64))) {
throw new \UnexpectedValueException('Invalid signature encoding');
}
https://github.com/firebase/php-jwt/blob/v5.2.0/src/JWT.php#L81-L94

CompactToken validation failed 80049228

Some users are getting this error back when trying to sign in using Microsoft Sign In in order to access mail via MS Graph. I've had both corporate users and personal (Hotmail.com) users both showing this error number but it works fine for most users.
This is the call:
https://login.microsoftonline.com/common/oauth2/v2.0/token
This is the error returned:
Code: InvalidAuthenticationToken
Message: CompactToken validation failed with reason code: 80049228
Any pointers? Where can I find a reference to this error number?
This means the token expired and it need to be refreshed. If you want to refresh it without user interaction you'll need a refresh_token which is returned when you obtain a token initially.
Here is how you can refresh it:
function refreshTokenIfNeeded(tokenObj){
let accessToken = oauth2.accessToken.create(tokenObj);
const EXPIRATION_WINDOW_IN_SECONDS = 300;
const { token } = accessToken;
const expirationTimeInSeconds = token.expires_at.getTime() / 1000;
const expirationWindowStart = expirationTimeInSeconds - EXPIRATION_WINDOW_IN_SECONDS;
const nowInSeconds = (new Date()).getTime() / 1000;
const shouldRefresh = nowInSeconds >= expirationWindowStart;
let promise = Promise.resolve(accessToken)
if (shouldRefresh) {
console.log("outlook365: token expired, refreshing...")
promise = accessToken.refresh()
}
return promise
}
Where tokenObj is the token object you store in your database.
Make sure it also has expires_at or otherwise oauth2.accessToken.create() will create it and calculate from the current moment in time.
More details can be found in this tutorial and in this github repo (this is where the code above was taken from)
Found a Solution To This
In my case, I was refreshing the token before using the access_token with Microsoft Graph API even once.
Once you successfully call https://login.microsoftonline.com/common/oauth2/v2.0/token You will get a refresh_token and an access_token, my guess is that you have been refreshing the token before using the first access token from the URL mentioned above.
Steps to Fix:
Call https://login.microsoftonline.com/common/oauth2/v2.0/token as you did before
Copy the access_token from the response and use it at least once with your Microsoft Graph API
Now you can copy the refresh_token (or once the access_token is expired) and exchange for a new access token
Enjoy your API integration
Smile :)
Reference:
Microsoft Authentication (Tokens) Docs - Including Refresh Token
OneDrive Refresh Token Answer

ADAL v3 - How to properly get rid of refresh token code?

In ADAL v2, we were doing this:
// Common parameter:
_clientCredential = new ClientAssertionCertificate(clientId, certificate);
// Get the token for the first time:
var userAssertion = new UserAssertion(accessToken, "urn:ietf:params:oauth:grant-type:jwt-bearer", userName);
_authResult = await authContext.AcquireTokenAsync(resource, _clientCredential, userAssertion);
// Refresh the token (when needed):
_authResult = await authContext.AcquireTokenByRefreshTokenAsync(authResult.RefreshToken, _clientCredential);
Note that in order to refresh the token, we only need the previous authentication result and the common client credential (_authResult and _clientCredential). This is very convenient.
ADAL v3 lacks AcquireTokenByRefreshTokenAsync, and here is the explanation. But that doesn't say, in concrete terms, what kind of change is needed.
Do we have to replay the first AcquireTokenAsync (and therefore keep resource, accessToken and userName stored somewhere in the program state)?
Or is there some way of getting an up-to-date token with only the common elements (_authResult and _clientCredential)?
The mechanism to use a refresh token is now provided by AcquireTokenSilentAsync. See AcquireTokenSilentAsync using a cached token using a cached token for patterns to use this.
Are you utilizing the [ADAL token Cache] (http://www.cloudidentity.com/blog/2013/10/01/getting-acquainted-with-adals-token-cache/)? It saves you from managing the underlying implementation details of using refresh tokens in your code and the issue you are facing.
The recommended approach for the on-behalf-of flow in ADAL 3.x is to use:
try
{
result = await ac.AcquireTokenSilentAsync(resource, clientId);
}
catch (AdalException adalException)
{
if (adalException.ErrorCode == AdalError.FailedToAcquireTokenSilently ||
adalException.ErrorCode == AdalError.InteractionRequired)
{
result = await ac. AcquireTokenAsync (resource, clientCredentials, userAssertion);
}
}
For more details see https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/wiki/Service-to-service-calls-on-behalf-of-the-user
Note that there are scenarios where you could have cached a refresh token acquired with ADAL.NET v2.x, and to help migrating from ADAL 2.x to MSAL.NET, we plan to re-introduce the AcquireTokenByRefreshToken in MSAL.NET (but not in ADAL 4.x)

How do I return the id property of the user object in Apollo?

When I place the below in a React component that queries the user model I am able to get the entire user object as queried by graphQL including the id property:
console.log(this.props.data.user)
But when I try to access the id property from code:
console.log(this.props.data.user) // undefined
console.log(this.props.data.user.id)
// error cannot get property of undefined
My first guess is that this is a security feature; I am using Auth0 and Graphcool.
But I may just be going about this in a backwards way. If so, any help on accessing the user id in the correct manner would be appreciated.
Thanks
This is covered in the FAQ article on the logged in user.
Obtaining a Signed JWT with Auth0
The user query returns the currently authenticated user. So first we have to think about how the authenticated user is determined.
The current state-of-the-art is using verified JWT and passing them as the Authorization header.
After entering valid credentials in Auth0 Lock, it returns a JWT that is signed with your secret Auth0 key. This signed JWT is sent to the GraphQL server where we'll use your Auth0 key to verify it and if it belongs to a valid user, the request is authenticated.
Setting the Authorization Header with Apollo Client
So I suspect that you're simply not passing a valid Authorization header. With Apollo, you can use this to ensure passing the token if it is present. Note that we'll use local storage for storing the token from Auth0 Lock:
const networkInterface = createNetworkInterface({ uri: 'https://api.graph.cool/simple/v1/__PROJECT_ID__' })
// use the auth0IdToken in localStorage for authorized requests
networkInterface.use([{
applyMiddleware (req, next) {
if (!req.options.headers) {
req.options.headers = {}
}
// get the authentication token from local storage if it exists
if (localStorage.getItem('auth0IdToken')) {
req.options.headers.authorization = `Bearer ${localStorage.getItem('auth0IdToken')}`
}
next()
},
}])
const client = new ApolloClient({ networkInterface })
Check this Auth0 example code or the live demo to see how it works.
You might also be interested in this answer on authorization (permissions).

Resources