Token Exchange Endpoint - "The `refresh_token` parameter was missing."

Hi team!

I trying to add mechanizm to refresh access_token by passing refresh_token but unfortunately I’m getting an error:

“The refresh_token parameter was missing.”

with 400 HTTP code.

Those are steps which I’m did - can someone verify it and tell me if I did something wrong or something stopped working after recent changes Changes to API token formats ?

  1. Obtain initial access by code exchange:
POST https://app.asana.com/-/oauth_token
        ?grant_type=authorization_code
        &client_id=1234567890
        &client_secret=client_secret_123
        &redirect_uri=https://my-redirect-uri.com
        &code=2/code
        HTTP/1.1

response which I got:

HTTP/1.1 200
{
  "access_token": "access_token_123"",
  "token_type": "bearer",
  "expires_in": 3600,
  "data": {
    "id": 123,
    "gid": "123",
    "name": "me me",
    "email": "me@gmail.com"
  },
  "refresh_token": "2\refresh_token_123"
}
  1. Obtain a new token by passing refresh token
POST https://app.asana.com/-/oauth_token
        ?grant_type=refresh_token
        &refresh_token=2\refresh_token_123
        &client_id=1234567890
        &client_secret=client_secret_123
        HTTP/1.1

response which I got:

HTTP/1.1 400 Bad Request
{
  "error": "invalid_request",
  "error_uri": "https:\u002F\u002Fasana.com\u002Fdevelopers\u002Fdocumentation\u002Fgetting-started\u002Fauthentication",
  "error_description": "The `refresh_token` parameter was missing."
}

Hi @Donnie_MacEntire,

One thing I can see is you’re missing the redirect_uri parameter in your refresh call:

Hi @Phil_Seeman! Thanks for replying!

Sorry, I was trying all possible combinations and by mistake I added a one w/o redirect_uri but also when I’m adding it I’m getting this error.

What is quite interesting, when I removed ‘client_secret’ I got an different error:

{
  "error": "invalid_grant",
  "error_uri": "https:\u002F\u002Fasana.com\u002Fdevelopers\u002Fdocumentation\u002Fgetting-started\u002Fauthentication",
  "error_description": "The `refresh_token` provided was invalid."
}

I think at this point you’ll need some Asana engineering help! @John_Vu @John_Baldo ?

Hi @Donnie_MacEntire,

Are you sending your request in a form-encoded POST body” (OAuth)?

Here’s a template cURL command that makes this request with a form-encoded POST body:

Example Request:

curl --location 'https://app.asana.com/-/oauth_token' \
--form 'grant_type="refresh_token"' \
--form 'refresh_token="<YOUR_REFRESH_TOKEN>"' \
--form 'client_id="<YOUR_CLIENT_ID>"' \
--form 'client_secret="<YOUR_CLIENT_SECRET>"' \
--form 'redirect_uri="<YOUR_REDIRECT_URI>"'

Example Response:

{
    "access_token": "<ACCESS_TOKEN>",
    "token_type": "bearer",
    "expires_in": 3600,
    "data": {
        "id": 123,
        "gid": "456",
        "name": "John",
        "email": "user@example.com"
    }
}

Here’s how I tested:

  1. Set up an ran this example oauth app node-oauth-demo

  2. Open up the app in my browser (i.e., went to http://localhost:3000/ → clicks on the “Authenticate with Asana” button)
    EX:

  3. Look at the output in the console and take note of the refresh_token
    EX:

***** Response from the token exchange request:

{
  access_token: '123456789',
  token_type: 'bearer',
  expires_in: 3600,
  data: {
    id: 123,
    gid: '456',
    name: 'John',
    email: 'user@example.com'
  },
  refresh_token: '2/120'
}
  1. Went into Postman → “Body” tab → “form-data” radio button → fill out the information for grant_type, client_id, ‘client_secret’, refresh_token, redirect_uri. Click on “Send” button and see results.
    EX:

NOTE: although we say redirect_uri is required in our docs I tested this without passing in a redirect_uri and the request still succeeds. I believe the required redirect_uri is meant for the POST https://app.asana.com/-/oauth_authorize request not the POST https://app.asana.com/-/oauth_token endpoint

1 Like

Hi John!
thanks for your help! now I now why it’s not working :confused:

but… it’s totally misleading! :cry: in a single endpoint once you expect “x-www-form-urlencoded” for code exchange and for refreshing you expect “form-data” :frowning_face: :exploding_head:

also in the docs, and here you mentioning “form-encoded POST body” which isn’t specific enough… even ChatGPT would fall in to the same problem like me :stuck_out_tongue:

me > which header I should use form-data or x-www-form-urlencoded when docs says form-encoded?
chatgpt 3.5 > If the API documentation specifies “form-encoded” without explicitly mentioning either form-data or x-www-form-urlencoded , it might be a bit ambiguous. However, in many cases, “form-encoded” refers to x-www-form-urlencoded

can you maybe at least update the docs to be more specific? :pray:

Hi @Donnie_MacEntire,

Thank you for your feedback. I can update the docs to be more clear. For context both options work:

  1. Content-Type: application/x-www-form-urlencoded
  2. Content-Type: multipart/form-data;boundary="boundary"

In my previous reply, I shared a screenshot using form-data here’s a screenshot of making that request using x-www-form-urlencoded in Postman:

Here’s what the cURL looks like for making a request with x-www-form-urlencoded:

curl --location 'https://app.asana.com/-/oauth_token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=refresh_token' \
--data-urlencode 'refresh_token=<YOUR_REFRESH_TOKEN>' \
--data-urlencode 'client_id=<YOUR_CLIENT_ID>' \
--data-urlencode 'client_secret=<YOUR_CLIENT_SECRET>'

Looking through some posts on Stack Overflow it looks like the key difference between x-www-form-urlencoded and form-data is that:

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

  • Use this for simple text/ ASCII data
  • Used more generally to send text data to the server

Content-Type: multipart/form-data;boundary="boundary"

  • Use this for non-ASCII text or large binary data
  • Used to send binary data, most notably for uploading files to the server

Sources:


Going from what we learned above, it seems like application/x-www-form-urlencoded is sufficient on making the request.

Applying this learning to our Upload an attachment endpoint it makes sense why this endpoint requires multipart/form-data since this endpoint can take in binary data from an attachment.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.