Referencing video: https://www.youtube.com/watch?v=ebwN2HWpDQA
Environment: Node.js
In the video they show how to get an access_token using the JWT. Documentation says the lifetime of the access_token can only be 1 hour so what do we do once the token expires? Can we simply use the JWT again with an updated date-time in UNIX epoch format for the iat and exp values to get a new access_token?
If I do update the iat and exp I get the following error
{
"error": "invalid_grant",
"error_description": "no_valid_keys_or_signatures"
}
How should we get a new access token?
When an access token expires, you will need to generate a new JWT assertion, sign it, and use it to request a new access token.
Reusing the old assertion with modified IAT and EXP values won't work without also generating a new signature using your RSA Private Key.
Related
We are using Azure active directory Oauth code flow to authenticate the user.
We got the access_token, id_token and refresh_token using code(got it on redirect URL).
We are using id_token to authorization each request after successful authentication and we can verify JWT using the public key which we got from /discovery/v2.0/keys api.
Now, JWT will expire after 1 hour. so we need to refresh this id_token.
I am refreshing id_token using below cURL
curl --request POST \
--url https://login.microsoftonline.com/{tenant_id}/oauth2/token \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data 'client_id=client%20id&refresh_token=refesh%20token%20&grant_type=refresh_token&client_secret=client_secret&scope=openid
In the response of this API, we got the access_token, refresh_token, id_token, but if you observe id_token, it does not contain JWT signature (the third part of JWT), without signature we can not verify JWT
We can not find any document reference why id_token is not having a signature part.
Is there any other way to refresh id_token?
Is there any workaround if id_token can not be refreshed?
In some cases an Id token may be returned without a signature, especially if it is acquired through a back-channel with a client secret.
You already are getting the token through an encrypted channel, from the authority.
If someone was able to inject something there, they would be able to direct your app's requests for OpenID metadata as well, replacing the signing keys your app expects.
Thus the signature would not add much value here.
In addition, you won't send the Id token to any API as Id tokens should not be used for authorization.
That's what access tokens are for :)
The OpenID Connect spec has this to say: https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
If the ID Token is received via direct communication between the Client and the Token Endpoint (which it is in this flow), the TLS server validation MAY be used to validate the issuer in place of checking the token signature. The Client MUST validate the signature of all other ID Tokens according to JWS [JWS] using the algorithm specified in the JWT alg Header Parameter. The Client MUST use the keys provided by the Issuer.
But then, interestingly mentions this as well: https://openid.net/specs/openid-connect-core-1_0.html#IDToken
ID Tokens MUST be signed using JWS and optionally both signed and then encrypted using JWS and JWE respectively, thereby providing authentication, integrity, non-repudiation, and optionally, confidentiality, per Section 16.14. If the ID Token is encrypted, it MUST be signed then encrypted, with the result being a Nested JWT, as defined in [JWT]. ID Tokens MUST NOT use none as the alg value unless the Response Type used returns no ID Token from the Authorization Endpoint (such as when using the Authorization Code Flow) and the Client explicitly requested the use of none at Registration time.
So.. it could be that Azure AD is not compliant with spec?
EDIT: The v1 endpoint of Azure AD is not compliant in this regard. The newer v2 endpoint is fully OpenID Connect compliant.
We generated JWT using docusign given private key and validated by Docusign public key in jwt.io site. It generated valid signature.
Using same signature we called Docusign demo server for access token
POST https://account-d.docusign.com/oauth/token
with
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
assertion=Signature generated
but getting error "Invalid Grant".
What could be the possible reason? If signature is already verified in jwt.io with public key, Docusign should accept the assertion value.
As documented, you also need to supply the following claims:
iss--The integration key (also known as client ID) of the application.
sub--The user ID of the user to be impersonated.
iat--The DateTime when the JWT was issued, in Unix epoch format.
exp--The DateTime when the JWT assertion will expire, in Unix epoch format. Use 1 hour after iat or less.
aud--domain name of the authentication service instance to be used. For demo environments, use account-d.docusign.com For production environments, use account.docusign.com. Note: Do not include https:// in the aud value!
scope--The scopes being requested. For the JWT bearer grant, the requested scope should be signature.
See the docs and also see the DocuSign JWT code examples, the repos named eg-01-*
Ask a new question if you'd like further help.
i've followed all the instructions at the doc for generate JWT Token, but only receive "Bad Request" as response...
when i try to run eg-01-php-jwt the same occurs. i'm using DocuSign demo environment and simulating requests using Postman and curl
the steps i'm doing are:
generating authorization uri as https://account-d.docusign.com/oauth/auth?response_type=code&scope=signature%20impersonation&client_id=c0c3e3b4-87ec-46e6-afad-9f8cf9dda84c&redirect_uri=http://example.com/api/docusign/obtain-consent/callback
fill login and password for different docusign sandbox account
at the redirected uri i get the code parameter and decode at jwt.io, getting kid value from header
use kid value at sub to generate a new jwt token
sign jwt token with my private key
try to obtain access token and receive "Bad Request" as response message
my (updated) generated token is
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJjMGMzZTNiNC04N2VjLTQ2ZTYtYWZhZC05ZjhjZjlkZGE4NGMiLCJzdWIiOiI2ODE4NWZmMS00ZTUxLTRjZTktYWYxYy02ODk4MTIyMDMzMTciLCJpYXQiOjE1NTExMDA0MDksImV4cCI6MTU1MjEwMDQwOSwiYXVkIjoiYWNjb3VudC1kLmRvY3VzaWduLmNvbSIsInNjb3BlIjoic2lnbmF0dXJlIGltcGVyc29uYXRpb24ifQ.I1LhY77Rd0-op6UE3zUQvA5UxXIBzHUMyhhrwSN_TBv9ghiNAOr2aVz8Glf16bulkqSrE6A67h3DvL_VDm5NpNzcDQttjlf-CtlnBrjyt2w1niZkYnlmrUXW3SofDJkNHEj9-zQOa2XBrzTOLIhD6g2V0adBe45mwwGpMpOu0oPameUseDVEBeQ50mCZcyiMGYazEA0qeE9Ws9Rb7GxZxmOIZXaWirohmJhNfic5wHprJvA6tTwxai5-4xAwnhrjpsOWKoQRxXRkCKKcIIrKf8SEz4KOH2RCUBqMZRGys81CIDtowtLoDUeMCRKTaxnbrCFax4blJSZ8X3ptyneVpw
UPDATE # 2019-02-26:
to achieve what i want i needed to complete the authorization code flow, get the user account id from step 4 (retrieve user data) and finally generate the jwt token with that info as sub at payload!
That assertion previously only included the signature scope. JWT Authentication requires signature impersonation.
Now that that has been updated, there are a couple of other possible issues:
Invalid user ID. The JWT assertion requires an active User ID in the
sub field. If the user is closed or the ID is incorrect this will
fail.
Invalid signature. The JWT assertion must be signed with an RSA
private key associated with the iss / Client ID in use. If there
are any invalid/encoding characters or trailing spaces, the signature
may not be valid.
I'd recommend opening a case with DocuSign Support. On your side, you'll only receive the error invalid_grant. Support-side logging will have a more specific error. To assist with resolution, when opening a case please provide the following:
Integrator key
Demo account ID
JWT Assertion
x-DocuSign-TraceToken header value
I have been reading about JWT and i am trying to implement it in my server. I already have a API that receive an user and send back a JWT with an expire time. Well... then i have other method that verify the token.
Is there any method that i can use to expand the expiration time of a normal Access token? i read that there is other type of token called Refresh Token... but it is more than i need... i just want increase the expire time, thats all
jwt.sign({ user }, SECRET , { expiresIn: '5m'} ); // HOW I CREATE THE TOKEN
jwt.verify(req.token, SECRET , (error, data) => {} <---- // HERE IS WHERE I WOULD LIKE TO INCREASE
As you said, the expiry time in a JTW is set when the JWT is generated and signed. You cannot change an existing token, e.g. by changing the expiry time, because after the change, the signature would not be correct anymore. Being able to make such changes would invalidate the security that JWT utilizes.
I suggest you read up on how the JWT works. Check out the Signature part of the following article: Introduction to Json Web Tokens - jwt.io
What can you do about it? Just issue a new JWT.
You will have to recreate the token again. Token is signed which makes it unique. It defeats the purpose of the token if you change the expiry time and magically becomes valid.
Can I try to understand what is stopping you from generating a new token at the place where you want to increase the exp time?
I am using the Easy Auth feature of Azure App Service and I am trying to refresh a token with the Google provider.
I followed the Chris Gillum article and correctly called .auth/login/google with the access_type=offline parameter. Then I called .auth/refreshwhich return me a 200 OK with a new authenticationToken. However, when I check the claims of this ZUMO token by calling .auth/me, I can see that the Google token is in fact not refreshed despite the previous successful response. The exp claims (corresponding to Expiration Time) is the same as the previous token.
I tried several scenario : refresh the token immediately after receiving it, 10 minutes before the expiration time and after the expiration time (when the token is no longer valid) but in every scenario, Easy Auth return me a new ZUMO token but the Google token associated is always the same.
Is it normal for the .auth/refresh endpoint to always return the same token (same exp claims) with the Google provider ?
As Exchange authorization code for refresh and access tokens states about the refresh_token:
A token that you can use to obtain a new access token. Refresh tokens are valid until the user revokes access. Note that refresh tokens are always returned for installed applications.
And the response from Refreshing an access token only contains the access_token,expires_in (The remaining lifetime of the access token in seconds),token_type.
Is it normal for the .auth/refresh endpoint to always return the same token (same exp claims) with the Google provider ?
Using the Log stream under the MONITORING section of your app service, you could find the detailed log when calling .auth/refresh as follows:
Moreover, the exp claim when calling .auth/me represents the expire time for the authenticationToken instead of the refresh_token.
And you could leverage jwt.io to decode your authenticationToken and compare it with the exp user claim.