JWT Issue with Docusign API - docusignapi

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.

Related

On Access Token Expiry - JWT Authentication - DocuSign

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.

How to verify signature of refreshed id_token in Azure active directory

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.

Unable to generate a jwt token using DocuSign Python code

I am using docusign for digital signature , where I have to create a jwt token. For this I have been using code from git repo https://github.com/docusign/docusign-python-client.
docusign version 3.1.0 , python version 3.5 and 3.6 in sandbox mode .
getting following error
raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='https', port=443): Max retries exceeded with url http://account-d.docusign.com/oauth/token (Caused by NewConnectionError(': Failed to establish a new connection: [Errno -2] Name or service not known',))
i have followed the curl request using following url JSON Web Token (JWT) Grant
got an application token and while passing in auth giving me 401(401 UNAUTHORIZED
) error
postman
claim = {"iss": '4556e2f7-4a3d-41f9-a0c3-18535a28ab2a', "aud": 'account-d.docusign.com', "iat": now, "exp": later, "scope": " ".join(scopes)} token = jwt.encode(payload=claim, key=pkey, algorithm='RS256').decode("utf-8")
i getting application token using above code but when i pass all the required parameter i got {"error":"invalid_grant","error_description":"no_valid_keys_or_signatures"} but when i pasted my jwt token in jwt.io with my public and privte key its says signature verified.
I have added the links of screenshots, that might also help to understand more about the problem.
https://ibb.co/2yKXNCW https://ibb.co/cFTk6R1 https://ibb.co/t3YMkr2
The concept is to generate a key with 3 elements (Header RS256 Algorith, the Payload Data that contains the application date and token validity and the private and public key. On the site jwt.io we will put all this information and the site will retour an Base64 Key we can further entered on
Open the JWT.IO site jwt.io
Choose Algorithm RS256 on the top
For the second Pane : “Payload: Data”
https://admindemo.docusign.com/apps-and-keys
iss :
The integration key (also known as client ID) of the application.
sub : The User ID of the user to be impersonated.
(The person granting permission must have a DocuSign user account.)
The provided User ID must be in GUID (not email) format. You can look up a user’s GUID from their email using the users.list method.
Note: If you don’t already have the User ID of the user to act on behalf of, you can obtain it by completing the Authorization Code Grant flow begun in the Request the authorization code step.
https://admindemo.docusign.com/apps-and-keys -> Apps and Keys ->
aud : The URI of the authentication service instance to be used.
For demo environments, use account-d.docusign.com.
For production environments, use account.docusign.com.
Important: Do not include https:// in the aud value!
iat : The date-time when the JWT was issued
in Unix epoch format. You must include an iat value when creating a JWT, typically set to the current time.
You can convert a date to linux epoch format with the following link : https://www.epochconverter.com/
exp: The date-time when the JWT assertion will expire
in Unix epoch format. Defaults to one hour from the value of iat and cannot be set to a greater value. You must include an exp value when creating a JWT.
Use the epoch https://www.epochconverter.com/
⚠ Please note that this value must not be too far in time, in our example we are using 14 years of validity.
scope : The scopes to request. In our example “signature impersonation”.
All the scopes are defined on the following site https://developers.docusign.com/platform/auth/reference/scopes/
{
"iss":"ea670856-0422-4d8e-99bd-80560d323639",
"sub":"917c9fc5-d615-43bb-8a28-87e7ede3b8ac",
"aud":"account-d.docusign.com",
"iat": 1628496664,
"exp":1912493464,
"scope":"signature impersonation"
}
For the Pane “Verify Signature”
https://admindemo.docusign.com/apps-and-keys -> Actions -> Edit
… -> Click on “Generate RSA”
Select the Public and Paste it on the section
And make the same for the public key. If everything is OK, you must have the Tag “Signature Verified” at the left of the document, see the picture bellow.
For the final step, you obtain the key for stating using the API
Go to Postman
https://www.postman.com/use-cases/api-testing-automation/
Sign in (for me with my google account)
You must fille the following values
Select “Post”
Put the API Value : https://account-d.docusign.com/oauth/token
Click on the “Body” section
Add the key “grant_type”
Add the value “urn:ietf:params:oauth:grant-type:jwt-bearer” for the key “grant_type”
Add the key “assertion”
Add the generate value from the site jwt on the previous steps
Finally Click on Send for obtain the “access_token” necessary the the further call.
[enter image description here][1]
Here are the things that you must ensure:
You have an Integration key (clientID) that is configured correctly.
You have an RSA Private key. that key was copied/pasted exactly as given to your configuration file. New lines must be preserved
Your URLs are matching the environment. Meaning you use account-d and demo.docusign.net for the sandbox env endpoints.
You need the userId which is a GUid for the user that would be impersonated. That user must consent to the application. You have to ensure you pass userId and not accountId and that it is for the same account that you would be using.
If you confirm all of this and still get an error - I would consider to use our code example to start. I don't see code in your question, but our code example should be a good way to start.

"Bad Request" message in JWT OAuth authentication flow

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

PARTNER_AUTHENTICATION failed for Docusign.esign.dll

I am writing code to use docusign demo machine through Docusign.esign.dll . I have tried using Oauth process for connecting the docusign.
I have used the code similar to the code motioned in here.
https://github.com/docusign/docusign-csharp-client/blob/master/test/SdkTests/JwtAuthUnitTests.cs
But I have used my demo machine Integetor key and private key. But I am getting the below error. So do I need to change any setup in my demo machine? Or how do I get valid Integotor key.
I hope my PEM key is causing the issue. So let me know how to preparte that pEM KEy.
I just copied by Private key and created the PEM file using notepad application.
Please let me know do I miss any thing?
Error calling Login: {\r\n \"errorCode\": \"PARTNER_AUTHENTICATION_FAILED\",\r\n \"message\": \"The specified Integrator Key was not found or is disabled. An Integrator key was not specified.\"\r\n}"}
BY default, the API points to their live/production servers. After creating an instance of the ApiClient, set it to point at the demo server:
apiClient.RestClient.BaseUrl = new Uri("https://demo.docusign.net/restapi");
Edit: That was for legacy authentication. For OAuth, please check to make sure you're pointing to account-d.docusign.com (notice the -d).
I too found this to be the issue, in the response the bearer token is missing
<br/><br/>string host = "https://demo.docusign.net/restapi/v2";
// Note with or without v2 their supplied credentials work<br/>
string oauthBasePath = "account-d.docusign.com";<br/>
ApiClient apiClient = new ApiClient(host);<br/>
apiClient.ConfigureJwtAuthorizationFlow(integratorKey, userId, oauthBasePath, privateKeyFilename, expiresInHours);
When you use the credentials from the JwtAuthUnitTests - TestConfig all works
Steps followed should be:
Created demo machine
Created IK
Created Secret key
Created RSA pair key
Copy the private key in to notepad and save that file in location
Missing steps are:
Granting Consent either using User Consent or Admin Consent, check
Service Integration for details.
Configure Redirect URI in the Integrator Key, only needed for User
Consent via Authorization Code Grant
You can use Admin Consent only if you can claim email domain in DocuSign else you need to use User Consent. With User Consent, normally using Authorization Code Grant, you need to get consent with scopes of Impersonation Signature. Once you have user's consent, then you can get new AccessToken for that user using JWT.
Also you need to point to correct host for Demo and Prod,
account-d.docusign.com is required for Demo
account.docusign.com is required for Prod
Above host is used to get access token from DocuSign Account Server (/oauth/token), and you will use above host also for getting the baseUri from /oauth/userinfo endpoint. Other than these two call, I don't think you will use above host.
In response for /oauth/userinfo endpoint call, you will get base_uri and account_id like below
"account_id": "fe0b61a3-3b9b-cafe-b7be-4592af32aa9b"
"base_uri": "https://demo.docusign.net"
You will use above base_uri and account_id for any other API calls, like for creating envelope etc
<base_uri>/restapi/v2/accounts/<account_Id>/envelopes

Resources