I'm working on the project that consume data from WSO2AM. I'm following steps from https://docs.wso2.com/display/AM210/apidocs/publisher/#guide and everything is OK.
I want to change the token expired duration for the logged in user (not application subscription token). The only think I know to achieve this is by changing the configuration on the WSO2 application itself.
Is there any other way to dat from the consumer end? maybe by putting the expiration duration as query string?
This is the curl command to get the token:
curl -k -d "grant_type=password&username=admin&password=admin&scope=apim:api_view" -H "Authorization: Basic SGZFbDFqSlBkZzV0YnRyeGhBd3liTjA1UUdvYTpsNmMwYW9MY1dSM2Z3ZXpIaGM3WG9HT2h0NUFh" https://localhost:8243/token
This is the response:
{
"scope":"apim:api_view",
"token_type":"Bearer",
"expires_in":3600,
"refresh_token":"33c3be152ebf0030b3fb76f2c1f80bf8",
"access_token":"292ff0fd256814536baca0926f483c8d"
}
Basically I want the value of expires_in from the response to be last longer.
As per the OAuth2 spec, users aren't allowed to request for token expiry time. Therefore, it's a server-side configuration.
However, WSO2 provides this capability for client credentials grant type for the ease of developers to test their apps with different token expiry times.
You can simply increase the expiration time of your OAuth token and Refresh tokens generally by changing the following configuration in "conf/identity/identity.xml"
<!-- Default validity period for Authorization Code in seconds -->
<AuthorizationCodeDefaultValidityPeriod>300</AuthorizationCodeDefaultValidityPeriod>
<!-- Default validity period for application access tokens in seconds -->
<AccessTokenDefaultValidityPeriod>3600</AccessTokenDefaultValidityPeriod>
<!-- Default validity period for user access tokens in seconds -->
<UserAccessTokenDefaultValidityPeriod>3600</UserAccessTokenDefaultValidityPeriod>
<!-- Validity period for refresh token -->
<RefreshTokenValidityPeriod>84600</RefreshTokenValidityPeriod>
<!-- Timestamp skew in seconds -->
<TimestampSkew>300</TimestampSkew>
You have the ability to change the validity time/expiration time for each application also by changing the validity period for the generated OAuth token per each application with relevant value in API Manager.
Related
After googling we came to know that invalid_grant which means refresh token is invalid.
Link to google oauth doc
We don't have any of these issues mentioned by google. Is this error related to something else rather than a refresh token.
More Info
We have access to read, write spreadsheet and send gmail
We fetch an access token for each request
Any help would be appreciated.
We're already in production and verified by google
Without seeing the full error message that being
Invalid_grant {Message here}
It is hard to help but from my experience is most often caused by one of the following.
Refresh token expire, app not in production.
There are serval reasons why a refresh token can expire the most common one currently is as follows.
A Google Cloud Platform project with an OAuth consent screen configured for an
external user type and a publishing status of "Testing" is issued a refresh token expiring in 7 days.
The fix is to go to google developer console on the consent screen and set your application to production, then your refresh token will stop expiring.
invalid_grant: Invalid JWT
{ “error”: “invalid_grant”, “error_description”: “Invalid JWT: Token must be a short-lived token (60 minutes) and in a reasonable timeframe. Check your iat and exp values and use a clock with skew to account for clock differences between systems.” }
Your server’s clock is not in sync with NTP. (Solution: check the server time if its incorrect fix it. )
invalid_grant: Code was already redeemed
Means that you are taking an authentication code that has already been used and trying to get another access token / refresh token for it. Authentication code can only be used once and they do expire so they need to be used quickly.
Invalid_grant: bad request
Normally means that the client id and secrete you are using to refresh the access token. Was not the one that was use to create the refresh token you are using.
Always store most recent refresh token.
Remember to always store the most recent refresh token. You can only have 50 out standing refresh tokens for a single user and the oldest one will expire. Depending upon the language you are using a new refresh token may be returned to you upon a refresh of the access token. Also if you request consent of the user more then once you will get a different refresh token.
User revoked access
If the user revoked your access in their google account, your refresh token will no longer work.
user changed password with gmail scope.
If your refresh token was created with a gmail scope and the user changed their password. your refresh token will be expired.
Links
Oauth2 Rfc docs for invalid_grant error rfc6749
invalid_grant
The provided authorization grant (e.g., authorization
code, resource owner credentials) or refresh token is
invalid, expired, revoked, does not match the redirection
URI used in the authorization request, or was issued to
another client.
I developed my Django based webapp with token authentication by following this tutorial of Brad Traversy (https://www.youtube.com/watch?v=0d7cIfiydAc) using Knox for authentication and React/Redux for the frontend. Login/logout works fine (here is Brad's code: https://github.com/bradtraversy/lead_manager_react_django/blob/master/leadmanager/frontend/src/actions/auth.js --> logout using a POST request), besides one issue: When the user stays away from the computer for a long time, the token expires in the meanwhile. So when the user returns he is still in the logged in zone of the website, but as soon as he opens a React component with data loading from the DB a 401 error is thrown in the console ("Failed to load resource: the server responded with a status of 401 (Unauthorized)"). Then the user has to go on "logout" and login again.
This is not optimal, I would prefer that after the user returns, the system realizes the token expiry and logs the user automatically out. I have thought of the following approaches, but I am not sure how to implement it or which one is best:
1) For every API request: if the answer is 401 --> logout (this might also log the user out in case the token has not expired, but if there is some other permission problem) - seems not optimal to me.
2) Instead one could also create a testing route e.g. api/auth/check with a Django view including the typical check
permission_classes = [permissions.IsAuthenticated]
and if 401 returned --> logout. So that would mean for every database request I have another rather unspecific database request before.
3) Check at every API request specifically if the token has expired --> how to do it? In the docs (https://james1345.github.io/django-rest-knox/) I couldn't find a method to check token validity. I see in the database table "knox_authtoken" an expiry date and a huge code in the column "digest", but this is obviously encrypted data and cannot be compared with the token value that one has in the browser under local storage.
I would be glad to receive recommendations on how to best implement this!
This can be done in multiple ways.
I dont see the reason kicking a user out automatically, but if you want to do that you can either:
Create an URL which will be only for checking if the authentication is valid every 5 secs or so
Use web sockets to send a realtime message once the token has expired.
Put the logic in the frontend, for example store how long the token is valid, and run a timeout, after the timeout is finished relocate him to login.
Jazzy's answer - option 3 - brought me on the right way (thank you!), but working with timers on the frontend side, was initially not successful, since starting a timer within a React component would only run as long as this component is visible. I have no component that is visible all the time of the user session. I changed the expiry duration of the token within Django settings from default value of 8 hours to 72 hours and implemented an idle check on the frontend with this package: https://www.npmjs.com/package/react-idle-timer . So as soon as my application is not used for 2 hours I call the logout action (api/auth/logout). With this approach I don't need to care about the expiry time of the token on Django side, since no user will be active throughout 72 hours. As soon as he logs in again, he will receive a new token.
New solution:
I decided to not bother users too often with logging in and found this nice strategy:
we choose to never expire Knox tokens
we set expiry date for Django session to 90 days from last login
if user does not log in for > 90 days, he will make at some point a request to the backend (e.g. data requests), there we include a check if the session data is available
if 'some_session_variable' in request.session:
# whatever logic you need
else:
return HttpResponse("logout")
Since session variable will not be available after the expiry the 'logout' string is returned. On the frontend we check every response for 'logout' string. If it is being returned we initiate the logout process. The idle timer is not used anymore (as it is not so reliable in my experience).
I am using django rest frameworks JWT library
http://getblimp.github.io/django-rest-framework-jwt/
There are two settings on JWT token expiration
JWT_EXPIRATION_DELTA which is in seconds
The docs on it:
You can turn off expiration time verification by setting JWT_VERIFY_EXPIRATION to False. Without expiration verification, JWTs will last forever meaning a leaked token could be used by an attacker indefinitely.
This is an instance of Python's datetime.timedelta. This will be added to datetime.utcnow() to set the expiration time.
Default is datetime.timedelta(seconds=300)(5 minutes).
and JWT_REFRESH_EXPIRATION_DELTA
Docs:
mit on token refresh, is a datetime.timedelta instance. This is how much time after the original token that future tokens can be refreshed from.
Default is datetime.timedelta(days=7) (7 days).
Im not sure on the different use cases. I set the jwt token expiration delta to 20 seconds.
Then got a token saved it to local waited 20 seconds closed my browser window and re navigated to the site
expecting to not be logged in because the token would of expired but I was logged in.
So then what is the difference between JWT token expiration delta
and JWT Refresh Expiration Delta?
JWT_EXPIRATION_DELTA is the actual time till your JWT token will work. After the time mention in JWT_EXPIRATION_DELTA, whenever you will use this token to access a secure endpoint(that has JWT Auth enabled), it will return a error with message that Your JWT Token has been expired. So you need to keep refreshing JWT Token before it get expired. According to documentation:
Refresh with tokens can be repeated (token1 -> token2 -> token3), but this chain of token stores the time that the original token (obtained with username/password credentials), as orig_iat. You can only keep refreshing tokens up to JWT_REFRESH_EXPIRATION_DELTA
It means that no matter how many times you refresh your tokens, it will always keep the record of the original time when your 1st token was generated(First Time you logged in your user). So if JWT_REFRESH_EXPIRATION_DELTA is set to 1 day, you can't keep refreshing your JWT token after 1 day from when your original token was generated (means your 1st token generated time).
Don't know what mechanism you are using to check in the frontend if the user is authenticated or not. But if you use to check it on the backend (DRF-JWT provides some ready endpoints to verify and refresh tokens), you will find it will not work.
Using WSO2AM 2.1.0 we'd like to use the JWT token to pass api, user and application information to the backend service for authorization. The problem is with the JWT validation as the expiration timestamp is set to the current timestamp
reading other resources did not help much:
https://wso2.org/jira/browse/APIMANAGER-4575
https://wso2.org/jira/browse/APIMANAGER-3493
WSO2 Api Manager - How to change the expiration time of JWT?
Content of the api-manager.xml
<CacheConfigurations>
<EnableGatewayTokenCache>true</EnableGatewayTokenCache>
<EnableGatewayResourceCache>true</EnableGatewayResourceCache>
<JWTClaimCacheExpiry>900</JWTClaimCacheExpiry>
...
<APIKeyValidator>
...
<JWTExpiryTime>900</JWTExpiryTime>
<SecurityContextTTL>900</SecurityContextTTL>
</APIKeyValidator>
(even according to the resources the JWTExpiryTime has no effect when KM or GW cache is enabled)
It looks like the JWTExpiryTime is in effect if the token cache is disabled (to be validated), but we would like to cache the access tokens for performance reasons..
Edit: seems if either (Gateway or KeyManager) token cache is enabled, the JWT expiration is simply set to current timestamp (making JWT token unusable without some agreement on backend services about the token leeway/skew time). The token is cached for cache-lifetime (15mins by default), so the backend must allow expired tokens for 15 minutes. Or am I missing something?
It looks like the JWTExpiryTime is in effect if the token cache is disabled (to be validated)
You are correct here. You can set the JWT expiration Timestamp using JWTExpiryTime in {APIM_HOME}/repository/conf/api-manager.xml only when both Gateway and Key Manager cache are disabled.
But if you want the token cache to be kept enabled while preventing your JWT from expiring at the time of JWT generation, you can set the TokenCacheExpiry property in api-manager.xml under CacheConfigurations section as follows.
<CacheConfigurations>
...
<TokenCacheExpiry>900</TokenCacheExpiry>
...
</CacheConfigurations>
With this property you define the cache expiry time duration for the Gateway or the Key Manager, the default being 900(seconds).
For more information, refer the following documentation.
https://docs.wso2.com/display/AM210/Configuring+Caching
https://docs.wso2.com/display/AM210/Passing+Enduser+Attributes+to+the+Backend+Using+JWT#PassingEnduserAttributestotheBackendUsingJWT-ExpirytimeoftheJWT
From WSO2 APIM document here Access Token, there are configurations for default expiration time of access token and refresh token. However, can we set different expiration time of them separately for each applications?
Thank you very much.
You can't configure different expiration time for different application through configuration. But, through the API Store when generating new token, you can provide the expiration time through UI.
Refer this link[1] to see how to set the validity time for an application access token from the API Store UI.
[1] - https://docs.wso2.com/display/AM1100/Working+with+Access+Tokens#WorkingwithAccessTokens-Renewingapplicationaccesstokens