Working with OAuth refresh tokens
OAuth 2.0 authentication is a secure way for users to let an app access their Zendesk data without sharing their password. As an app developer, you can use OAuth to safely access Zendesk data on behalf of your users.
Because OAuth tokens expire for security reasons, Zendesk supports the refresh token flow so your integration can maintain access without repeatedly interrupting users. When an access token expires, your app can use a refresh token to obtain a new access token without requiring the user to log in again. If you don’t use refresh tokens, your app must redirect the user through the authorization code flow again whenever the access token expires, prompting the user to grant access again.
Your app should also handle token expiration gracefully. If the access token is expired, refresh it, and if the refresh token is expired or invalid, send the user through the authorization flow again. For more information, see Replacing expired access tokens in Zendesk help. For an example, see Using OAuth to authenticate Zendesk API requests in a web app.
When implementing the authorization code grant flow in your application, your app receives both an access token (for making API requests) and a refresh token (to request a new access token when needed).
If your integration does not use the refresh token flow, you will need to perform the authorization code grant exchange each time a user's token expires. This may result in interrupting users with repeated permission prompts. All OAuth apps should be designed to handle both expired access tokens and, if used, expired refresh tokens gracefully, to avoid unnecessary user interruptions.
This article walks you through an example of using refresh tokens.
Setting up OAuth and refresh tokens
To use refresh tokens with Zendesk, you'll first need to create an OAuth client in your Zendesk account. Follow the instructions in Registering your application with Zendesk in Zendesk help. You must be signed in as a Zendesk Support admin to create an OAuth client.
When registering the app:
-
For the Client name and Unique identifier fields, provide any name and identifier you want.
-
For the Redirect URLs field, specify
http://127.0.0.1:5000/auth. You'll create this URL later in the tutorial. -
For the Client kind field, select Confidential.
After you create the client, securely save the client's Identifier and Secret values. These credentials are also called the client id and secret. You'll use these credentials later in the tutorial.
Setting up the redirect server
To complete the OAuth authorization flow on your local machine, you'll need a small web server to receive the authorization code. You can quickly set this up using Flask, a lightweight web framework for Python. You'll also need a recent version of Python if you don't already have one installed.
-
If Flask is not already installed, run the following to install it:
pip install flask -
In your project folder, create a file named redirect-server.py and paste the following Python script into it.
from flask import Flask, requestapp = Flask(__name__)@app.route('/auth')def oauth_callback():code = request.args.get('code')return f"Received code: {code}"if __name__ == "__main__":app.run(host="127.0.0.1", port=5000) -
Start your server by entering:
python3 redirect-server.py
Directing the user for approval
Now that your server is running, you can start the OAuth flow.
Enter the following URL in your browser window:
https://{mycompany}.zendesk.com/oauth/authorizations/new?response_type=code&redirect_uri=http://127.0.0.1:5000/auth&client_id={YOUR_CLIENT_ID}&scope=read+write
You should receive something similar to this:
Received code: 9a62f9a7f8357e3a0426eb06ae2255785cf2c4be1e0abcda617ddd1c3bd0bcf1
Exchanging the authorization code for tokens
Now that you've received your authorization code from Zendesk, the next step is to exchange it for access and refresh tokens. These tokens will allow your app to authenticate future API requests and refresh the access token when needed.
To do this, make a POST request to the Create Token for Grant Type endpoint with your code, client credentials, and redirect URI.
curl https://{subdomain}.zendesk.com/oauth/tokens \-X POST \-H "Content-Type: application/json" \-d '{"grant_type": "authorization_code","code": "{THE_CODE_YOU_RECEIVED}","client_id": "{YOUR_CLIENT_ID}","client_secret": "{YOUR_CLIENT_SECRET}","redirect_uri": "{YOUR_REDIRECT_URI}"}'
Zendesk will respond with an access token and a refresh token. Save both tokens as you’ll use them in the next steps.
You can optionally specify custom expiration times in seconds for your tokens by including the expires_in or refresh_token_expires_in parameters in your /oauth/tokens request. For example, you might want your access token to last only 5 minutes instead of the default. Zendesk will use the provided values or apply default values if not specified.
{"access_token":"1c0e4d0f0b76367c8ccbdc61225239f973795d7d164cd1a077838e75af4b5703","expires_in":600,"refresh_token":"650647ca55d659976176257ae6c420bb2d7ebaa8900f5a59758054d850459bc5","token_type":"bearer","scope":"read write","refresh_token_expires_in":2592000}
The expires_in and refresh_token_expires_in values are seconds.
Your app should use expires_in to track when the access token will expire and refresh in advance or on a 401 error.
Making an API call with your access token
After you’ve obtained your access token, you can use it to make API requests to Zendesk.
Include the access token in the Authorization header as follows:
curl https://{subdomain}.zendesk.com/api/v2/users/me.json \-H "Authorization: Bearer {YOUR_ACCESS_TOKEN}"
When your access token expires or becomes invalid, your app must use the refresh token to obtain a new access token.
Refreshing the token
To ensure continuous API access, your integration must implement logic that uses the refresh token flow whenever an access token expires or becomes invalid. This allows your integration to stay connected to Zendesk without requiring users to reauthorize each time.
To test your refresh logic, you can simulate an expired access token by using an invalid or revoked access token in an API call to /api/v2/users/me. You can create an invalid token by simply deleting or changing a character in an existing token string.
curl https://{subdomain}.zendesk.com/api/v2/users/me.json \-H "Authorization: Bearer {FAKE_OR_EXPIRED_ACCESS_TOKEN}"
You'll see an error like this:
{"error":"invalid_token","error_description":"The access token provided is expired, revoked, malformed or invalid for other reasons."}
When this happens, use your refresh token to request a new access token with the Create Token for Grant Type endpoint:
curl https://{subdomain}.zendesk.com/oauth/tokens \-X POST \-H "Content-Type: application/json" \-d '{"grant_type": "refresh_token","refresh_token": "{YOUR_REFRESH_TOKEN}","client_id": "{YOUR_CLIENT_ID}","client_secret": "{YOUR_CLIENT_SECRET}"}'
Zendesk will respond with a new access token and refresh token. Always replace both your access token and refresh token with the new values returned by Zendesk as the previous ones are now invalid.
Example response:
{"access_token":"cc41d1b67cddf51e123445a6f47a4f870f00b5db55e9e740754eb9112d3467d8","expires_in":600,"refresh_token":"7e1bea15123d22c8e0370c24f2a164b4423ec5449e878ee2496a39d4a384773ae","token_type":"bearer","scope":"read write","refresh_token_expires_in":2592000}
What if the refresh fails
If reauthorization is required, your app should direct the user back through the OAuth approval flow, starting from the authorization URL.
If the refresh token has already expired or is invalid, any attempt to use it to obtain a new access token will fail. In this case, your app must restart the OAuth flow and prompt the user to reauthorize.
Common questions
I received an invalid grant error
If you receive an invalid grant error, check the following:
-
Make sure your request is sent to the Create Token for Grant Type endpoint.
-
Make sure the client secret and tokens you’re sending are correct and that your request includes the required parameters for the grant type you’re using.
-
If you’re using the refresh token grant, confirm you aren’t reusing a refresh token. Refresh tokens are single-use. After you exchange a refresh token for a new access token, you must store and use the new refresh token returned in the response.
If you’ve confirmed the endpoint and parameters are correct and the issue persists, open a support ticket and include a HAR file that captures you reproducing the issue.
Do I have to adopt the refresh token flow
No. If you choose to not adopt the refresh token flow, your users will be required to re-authorize the app every time their access token expires. However, if you adopt the refresh token flow and ensure your OAuth apps handle expired tokens, it provides a more seamless experience for your users.
I don't get a refresh token for my client credentials app
This is expected. The client credentials grant is designed for server-to-server authentication and typically does not issue refresh tokens.
When the client credentials token expires, request a new access token by running the client credentials flow again.
If I pass expires_in:null, will I get a token that doesn't expire
Passing expires_in: null is effectively the same as omitting expires_in. Once token expiration is enforced, token lifetimes will be required and expires_in: null will no longer be supported.
Why does my refresh token look short
If you’re using GET /api/v2/oauth/tokens to inspect tokens (rather than create them), token values (including refresh_token) are truncated for security reasons. Securely store the refresh token when it's first returned (at creation time) as it cannot be retrieved by an API.
Why is my token created through the client credentials flow linked to my admin user
In Zendesk, OAuth tokens must be associated with a Zendesk user. Because client credentials are for server-to-server communication, Zendesk uses the OAuth client creator as the associated user.
OAuth tokens are still limited by the scopes given to it. For example, if you only allow the ticket:read scope, the OAuth token will only be able to read ticket data despite the user potentially having full permissions to view, create, edit, and delete tickets.
If you're using the OAuth token to access endpoints that only admins have access to and the original creator is downgraded to an agent for example, the OAuth application may not function correctly even if the token has full write permissions.
How do user permissions and scopes work together
OAuth tokens are tied to a user and a given scope:
-
User-level access: Some endpoints are limited by role. See Endpoint access.
-
Scope-level access: Some endpoints also require specific scopes, such as
users:readandtickets:write.
If either the user or the required scope is missing, the API request is rejected.
How do I get a refresh token for my existing token
You can't convert an existing token into one that has a refresh token. You must request a new token through the authorization code grant flow to get a refresh token. See Exchanging the authorization code for tokens.
My refresh token request failed and my access token isn't working
This is likely due to an expired refresh token or a network error. To ensure your users aren't disrupted by these situations, your OAuth app should:
- gracefully handle these errors
- fall back to starting the authorization code flow again to obtain a fresh set of tokens
How do I know if my client is public or confidential
- Public client: The client (for example, Single Page Applications (SPAs) and native mobile apps) cannot safely store a
client_secret. Mark the client as public so PKCE is required forauthorization_code. PKCE provides an additional layer of security in place of passing theclient_secret. - Confidential client: The client (for example, backend services) can securely store and use a
client_secretto complete the authorization code grant. You can still pass the necessary PKCE parameters and they will be validated.
How do I create an OAuth token for my backend or daemon-like app
If you cannot prompt a user for permission, you can use the client credentials grant to create an OAuth token. Note the following:
- The OAuth client must be confidential to use the client credentials flow.
- The resulting token is associated with the creator of the OAuth client.
Will token expiration break my Marketplace or external app
OAuth apps are generally maintained by third-party developers. It's up to them to ensure that their app can handle token expirations. Zendesk can’t update third-party apps on your behalf.
- If you develop the integration (including Marketplace apps using a global OAuth client), update your app to handle token expiration and refresh properly.
- If you’re an admin using a third-party app, contact the app provider to confirm they support expiring access tokens and refresh flows before the rollout.