8

The DocuSign documentation goes through an easy to follow authorization flow for code grant. I'm able to get the "code" from the initial GET request to /oath/auth but getting the tokens gives me an error of "invalid_grant" when I try in postman. I've followed the steps and have a request that looks like this using account-d.docusign.com for host:

POST /oauth/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic MjMwNTQ2YTctOWM1NS00MGFkLThmYmYtYWYyMDVkNTQ5NGFkOjMwODc1NTVlLTBhMWMtNGFhOC1iMzI2LTY4MmM3YmYyNzZlOQ==

grant_type=authorization_code&code=ey2dj3nd.AAAA39djasd3.dkn4449d21d

Two other members of my team have also tried with their developer accounts and all are getting invalid_grant errors. Is this no longer supported or are there common errors associated with this error that we might be able to investigate?

Larry K
  • 47,808
  • 15
  • 87
  • 140
welc0199
  • 91
  • 1
  • 1
  • 5

7 Answers7

10

Re-check all of your values.

I was also getting the same invalid_grant response and could not figure out why at first. It turns out that I had a typo in the Content-Type header. I was using application/x-www-form-urlencode instead of application/x-www-form-urlencoded.

You may not be, but if you are submitting the exact Authorization Header as you've posted it here in your question (MjMwNTQ2YTctOWM1NS00MGFkLThmYmYtYWYyMDVkNTQ5NGFkOjMwODc1NTVlLTBhMWMtNGFhOC1iMzI2LTY4MmM3YmYyNzZlOQ==) it will fail with that message.

That is the base64 value for the sample integration key and sample secret key provided in their documentation. If you decode that string with an online base64decoder it will result in 230546a7-9c55-40ad-8fbf-af205d5494ad:3087555e-0a1c-4aa8-b326-682c7bf276e9. This is the same sample integration key and secret in the documentation.

Check the Authorization header you are submitting by encoding your integration key and secret (integrationKey:secret) using this online base64encoder. This will make sure the issue isn't with your base64 encoding of your integration key and secret. Once you have that value make sure your Authorization uses the word Basic before the value you got from this website. (Basic base64stringFromOnlineEncoder)

Check that the code your are submitting in the body of the post is not the sample code from their documentation. ey2dj3nd.AAAA39djasd3.dkn4449d21d is the sample code from their documentation. You may just be using that in your question as a placeholder but if you are submitting any of those values it will return invalid_grant. Make sure that the body of your post does not have any leading or trailing spaces.

  1. Have the correct Content-Type set application/x-www-form-urlencoded
  2. Have the correct Authorization header set Basic base64EncodedIntegrationKey:Secret
  3. Have the correct body using the valid code received from the GET request to /oauth/auth with no leading or trailing spaces, making sure you're not using the values from your question.

If you are still having trouble and you are not doing a user application but are doing a service integration you can use Legacy Authentication to get your oAuth2 token.

Alternative Method using Legacy Authentication for Service Integrations

This method does not use a grant code. You pass in the integration key, username and password into the X-DocuSign-Authentication header in JSON format.

Demo Server: demo.docusign.net

Production Server: www.docusign.net API

Version: v2

POST https://{server}/restapi/{apiVersion}/oauth2/token
Content-Type: application/x-www-form-urlencoded
X-DocuSign-Authentication: {"IntegratorKey":"your_integrator_key","Password":"docusign_account_password","Username":"docusign_account_username"}

grant_type=password&client_id=your_integrator_key&username=docusign_account_username&password=docusign_account_password&scope=api

If you are building a user application that requires the user enter their docusign credentials to generate the token, this alternative will not work for you.

billvsd
  • 254
  • 2
  • 12
  • 1
    Me and my 2 other teammates have double checked our values. We're not using the examples from the document - we're using our own generated integrator key and secret key from our developer accounts. Legacy Authentication is not an option for us. – welc0199 Oct 07 '16 at 15:31
  • 2
    In that case, you haven't posted enough of your code to provide you with help. Yes it is supported, and I have provided you with common errors to check for, as you have asked for. – billvsd Oct 07 '16 at 17:35
  • 2
    integrationKey:secret - it'd be nice if the documentation said that! – jleach Feb 27 '18 at 13:39
  • What if in my flow, I don't want to use the auth GET flow for the user to grant access? In that case my only option is the legacy Authentication API? For example in a customer portal where the customer is logging in, we want to the customer to sign the contract in place, there is no DocuSign user to login! – sam360 May 10 '18 at 00:30
4

For anyone who is facing this error, I'd like to point out this note in the documentation:

Note: The obtained authorization code is only viable for 2 minutes. If more then two minutes pass between obtaining the authorization code and attempting to exchange it for an access token, the operation will fail.

I was struggling with the same error until I spotted the note and sped up my typing to meet the 2 minutes.

Hope it helps someone else.

ocbit
  • 63
  • 6
  • Hi @ocbit You are correct. But if the authorization code expires for every 2 minutes do i need to generate authorization code for every two minutes manually by constructing url with redirect url. Do you have any idea on how to generate authorization code programatically. – ramesh m May 28 '21 at 08:05
  • No @rameshm, I only did it once and never tried it in code. – ocbit Jun 23 '21 at 20:37
1

In my case the problem was related to having set a wrong value for Content-Type header, namely "application/x-www-form-URIencoded" instead of the correct "application/x-www-form-urlencoded". Note though that in my case the problem was not a "typo" but an excessive trust in DocuSign documentation.

Indeed the wrong Content-Type is, at the time of writing, suggested directly into the documentation page where they describe the Authorization Code Grant workflow, see the image below for the relevant part.

enter image description here

Hopefully they will fix the documentation soon but for the time being be careful not to blindly copy & paste the code from their examples without thinking, as I initially did.

Sal Borrelli
  • 2,201
  • 19
  • 19
1

anyone have an idea what is wrong here I am getting a BadRequest with the following

{"error":"invalid_grant","error_description":"unauthorized_client"}
var client = new RestClient(ESIGNURL);
            var request = new RestRequest("/oauth/token");
            request.Method = Method.POST;
            request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
            request.AddHeader("Authorization", "Basic " + Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(integrationkey+ ":" + secret)));

            string body = "grant_type=authorization_code&code=" + code;
            request.Parameters.Clear();
            request.AddParameter("application/x-www-form-urlencoded", body, ParameterType.RequestBody);

            var response = client.Execute(request);
Jared Forth
  • 1,577
  • 6
  • 17
  • 32
Brice
  • 11
  • 3
0

I was getting this error as well. What I realized is I was appending the state at the end of the code before passing it to the oauth token endpoint.

This snippet is from Docusign explaining what are some other reasons for getting that error.

Invalid-error explanation

DeeP
  • 79
  • 2
  • 6
0

I just spent a day doing this (in NodeJS). I'll add a couple of things to the answers from before. First, I had to put:

"Content-Type": "application/x-www-form-urlencoded"

in the header. Otherwise it gave me the message:

{
     "error": "invalid_grant",
     "error_description": "unsupported_grant_type"
}

Second, the base64 encoding:

I used this in NodeJS and it worked

const integration_key = process.env.INTEGRATION_KEY;
const secret_key = process.env.SECRET_KEY;
const authinfo =
     integration_key.toString("utf8") + ":" + secret_key.toString("utf8");
const buff2 = Buffer(authinfo, "utf8").toString("base64");

If you use "base64url" it dosen't work because it strips the == off of the end of the string. The = symbol is used as padding and apparently it's needed. You see a similar difference on this site https://www.base64encode.org/ when you toggle the url safe encoding option. If you don't have the padding on the end of your base64 encoded string (or if it's generally incorrect) you get this message:

{
     "error": "invalid_grant",
     "error_description": "unauthorized_client"
}

Finally, if you're using Postman (I'm using DocuSign's Postman Collection) remember to reset and save the codeFromUrl variable after you update it. Otherwise it doesn't update and you get the message:

{
    "error": "invalid_grant",
    "error_description": "expired_client_token"
}

This means the old URL code has expired and your new one didn't save.

cokeman19
  • 2,405
  • 1
  • 25
  • 40
0

For folks trying the DocuSign - 01 Authorize Code Grant Access Token from Postman, If you have configured the codeFromUrl in your postman using URL - https://www.example.com/callback as the Redirect URIs, then while using it consecuievely it gives invalid_grant error. You can use another site such as webhook.site which dynamically generates a unique URL. But you have to always register the webhook URL in docusign under allowed Redirect URIs everytime you generate a different webhook.site url.