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 ?
- 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"
}
- 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:
-
Set up an ran this example oauth app node-oauth-demo
-
Open up the app in my browser (i.e., went to http://localhost:3000/ → clicks on the “Authenticate with Asana” button)
EX:
-
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'
}
- 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
Hi John!
thanks for your help! now I now why it’s not working 
but… it’s totally misleading!
in a single endpoint once you expect “x-www-form-urlencoded” for code exchange and for refreshing you expect “form-data”

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 
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? 
Hi @Donnie_MacEntire,
Thank you for your feedback. I can update the docs to be more clear. For context both options work:
Content-Type: application/x-www-form-urlencoded
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.