Using OAuth authentication with your application

<body>
<p id="docs-hc-snippet" style="display: none;">You can useOAuth 2to authenticate all your application's API requests to Zendesk. OAuth provides a secure way for your application to access Zendesk data without having to store and use the passwords of Zendesk users. For added security, OAuth tokens have expiration times, and Zendesk supports refresh tokens to renew access without requiring user re-authentication.</p>
<div class="article-banners">
<div id="docs-wmp-link">
<a href="https://support.zendesk.com/hc/en-us/articles/5411234991258-plan" rel="noopener" target="_blank">What's my plan?</a>
</div>

<div class="article-banner" id="suite_all">
<table>
<tbody>
<tr>
<td>
<strong>All Suites</strong>
</td>
<td>Team, Growth, Professional, Enterprise, or Enterprise Plus</td>
</tr>
</tbody>
</table>
</div>

<div class="article-banner" id="support_all">
<table>
<tbody>
<tr>
<td>
<strong>Support</strong>
</td>
<td>Team, Professional, or Enterprise</td>
</tr>
</tbody>
</table>
</div>

</div>
<div id="docs-ai-summary">
<p id="docs-ai-summary-toggle">Summary: <span id="up-triangle">◀</span><span id="down-triangle">▼</span></p>
<p id="docs-ai-summary-content">You can use OAuth 2 to authenticate your application's API requests securely without storing user passwords. Register your app to get OAuth credentials, implement the authorization code flow with token expiration and refresh tokens, and handle token renewal when expired. OAuth supports scopes to control access levels, and PKCE enhances security for public clients. This setup helps manage secure API access and token lifecycle effectively.</p>
</div>

<div class="body">

<div class="note fastpath">
<span class="fastpathtitle">Location: </span> <span class="ph">Admin Center &gt; Apps and integrations &gt; APIs &gt; Oauth
clients</span>
</div>
<p class="p">You can use <a class="xref" href="http://oauth.net/2/" target="_blank">OAuth 2</a>
to authenticate all your application's API requests to Zendesk. OAuth provides a secure way
for your application to access Zendesk data without having to store and use the passwords of
Zendesk users. For added security, OAuth tokens have expiration times, and Zendesk supports
refresh tokens to renew access without requiring user re-authentication.</p>
<p class="p">To use OAuth authentication, you need to register your application with Zendesk. You also
need to add some functionality to your application to support the OAuth authorization code
flow and refreshing expired access tokens.</p>
<p class="p">Zendesk also supports the client credentials grant type flow, which lets you create an access
token using only an OAuth client’s secret. This grant type is intended for confidential
clients only and is not covered in this article. For more information, see <a class="xref" href="https://developer.zendesk.com/api-reference/ticketing/oauth/grant_type_tokens/#client-credentials-grant-type" target="_blank">Client credentials grant type</a> in the API
reference.</p>
<p class="p">Topics covered in this article:</p>
<ul class="ul" id="zug_oauth__ul_znb_jfs_qk">
<li class="li"><a class="xref" href="#topic_s21_lfs_qk">Registering your application with Zendesk</a></li>
<li class="li"><a class="xref" href="#topic_jkc_dcm_dcc">Implementing an OAuth authorization flow in your application</a></li>
<li class="li"><a class="xref" href="#topic_p1c_xjf_52c">Replacing expired access tokens</a></li>
</ul>
<p class="p">Related topics:</p>
<ul class="ul" id="zug_oauth__ul_msm_pfw_sy">
<li class="li">For a tutorial on building a web application that implements an OAuth authorization flow,
see <a class="xref" href="https://developer.zendesk.com/documentation/api-basics/authentication/using-oauth-to-authenticate-zendesk-api-requests-in-a-web-app/" target="_blank">Using OAuth to authenticate Zendesk API requests in a web app</a>.</li>
<li class="li">To implement an OAuth authorization flow in Zendesk apps, see <a class="xref" href="https://developer.zendesk.com/documentation/apps/build-an-app/adding-third-party-oauth-to-a-support-app/" target="_blank">Adding third-party OAuth to a Support app</a>.</li>
<li class="li">If you don't need users to grant your application access to their accounts, you can still
use OAuth tokens to authenticate API requests. See <a class="xref" href="https://developer.zendesk.com/documentation/ticketing/working-with-oauth/creating-and-using-oauth-tokens-with-the-api" target="_blank">Creating and using OAuth access tokens with the API</a>.</li>
</ul>
</div>
<div aria-labelledby="ariaid-title2" class="topic nested1" id="topic_s21_lfs_qk">
<h2 class="title topictitle2" id="ariaid-title2">Registering your application with Zendesk</h2>
<div class="body">
<p class="p">You must register your application to generate OAuth credentials that your application can
use to authenticate API calls to Zendesk.</p>
<div class="note">
<span class="notetitle">Note:</span> This section describes how to set up an OAuth client for users of one Zendesk account.
If your application will interact not only with one Zendesk account but with lots of them,
you can request a <em class="ph i">global</em> OAuth client. A global OAuth client is a secure, cleaner way
of doing API authentication with multiple Zendesk instances. For more information, see <a class="xref" href="https://developer.zendesk.com/documentation/apps/publish-your-app-or-theme/global_oauth_intro/" target="_blank">Set up a global OAuth client</a>.</div>
<p class="p"><strong class="ph b">To register your application</strong></p>
<ol class="ol" id="topic_s21_lfs_qk__ol_ckz_rfs_qk">
<li class="li"><span class="ph">In <a class="xref" href="https://support.zendesk.com/hc/en-us/articles/4581766374554#topic_hfg_dyz_1hb" target="_blank">Admin Center</a>, click <img class="image" id="topic_s21_lfs_qk__image_zk3_bj4_g2c" src="https://zen-marketing-documentation.s3.amazonaws.com/docs/en/ac_apps_integrations_icon.png">
<strong class="ph b">Apps and integrations</strong> in the sidebar, then select <strong class="ph b">APIs &gt; OAuth
clients</strong>.</span></li>
<li class="li">Click <strong class="ph b">Add OAuth client</strong> on the right side of the OAuth client list. </li>
<li class="li">Complete the following fields to create a client:<ul class="ul" id="topic_s21_lfs_qk__ul_q51_yfs_qk">
<li class="li">
<strong class="ph b">Name</strong> - Enter a name for your app. This is the name that users will see when
asked to grant access to your application, and when they check the list of third-party
apps that have access to their Zendesk.</li>
<li class="li">
<strong class="ph b">Description</strong> - Optional. This is a short description of your app that users
will see when asked to grant access to it.</li>
<li class="li">
<strong class="ph b">Company</strong> - Optional. This is the company name that users will see when asked
to grant access to your application. The information can help them understand who
they're granting access to.</li>
<li class="li">
<strong class="ph b">Logo</strong> - Optional. This is the logo that users will see when asked to grant
access to your application. The image can be a JPG, GIF, or PNG. For best results,
upload a square image. It will be resized for the authorization page. </li>
<li class="li">
<strong class="ph b">Identifier</strong> - The field is auto-populated with a reformatted version of the
name you entered for your app. You can change it if you want.</li>
<li class="li">
<strong class="ph b">Client kind</strong> - Public or Confidential. Public OAuth clients are applications
that run in environments where credentials cannot be securely stored, such as mobile
and web apps. These clients are required to use PKCE. Confidential OAuth clients run
on secure servers where their credentials can be kept secure. These clients can use
PKCE, client secret, or both. See <a class="xref" href="#topic_ycb_ztl_m2c">Understanding client kinds</a>.</li>
<li class="li">
<strong class="ph b">Redirect URLs</strong> - Enter the URL or URLs that Zendesk should use to send the
user's decision to grant access to your application. The URLs must be absolute and not
relative, https (unless localhost or 127.0.0.1), and newline-separated.</li>
<li class="li">
<strong class="ph b">Scopes</strong> - Select the scopes this client can request. Leave this field empty to
allow all scopes. See <a class="xref" href="#topic_qkc_dcm_dcc">Setting the
scope</a>.<div class="note" id="topic_s21_lfs_qk__note_zkk_cdv_3kc">
<span class="notetitle">Note:</span> Scope restrictions apply only to new access
tokens generated through an authorization or client-credentials flow. Existing
active tokens and refreshed tokens are not retroactively affected.</div>
</li>
<li class="li">
<strong class="ph b">Expire tokens</strong>: When enabled, all tokens issued by this OAuth client will be
assigned a default expiration date, including existing tokens that don't already have
one. This setting is permanent and cannot be turned off once enabled.<p class="p">For OAuth
clients created after April 30, 2026, this checkbox will be disabled since these
clients already have expirations set by default.</p>
</li>
</ul>
</li>
<li class="li">Click <strong class="ph b">Save</strong>.<p class="p">After the page refreshes, a new pre-populated <strong class="ph b">Secret</strong> field
appears on the lower side. This is the "client_secret" value specified in the <a class="xref" href="http://tools.ietf.org/html/rfc6749" target="_blank">OAuth 2.0
spec</a>.</p>
</li>
<li class="li">Copy the <strong class="ph b">Secret</strong> value to your clipboard and save it somewhere safe. Note: The
characters may extend past the width of the text box, so make sure to select everything
before copying.<div class="note important">
<span class="importanttitle">Important:</span> For security reasons, your secret is displayed fully
only once. After clicking <strong class="ph b">Save</strong>, you'll only have access to the first nine
characters.</div>
</li>
<li class="li">Click <strong class="ph b">Save</strong>.</li>
</ol>
<p class="p">Use the unique identifier and the secret value in your application as described in this
following topic.</p>
</div>
<div aria-labelledby="ariaid-title3" class="topic nested2" id="topic_dqw_n2f_fkc">
<h3 class="title topictitle3" id="ariaid-title3">Understanding the effect on tokens when an OAuth client creator loses access</h3>
<div class="body">
<p class="p">If the admin who created an OAuth client is deleted, downgraded, or otherwise loses the
permissions required to create and manage OAuth clients, the OAuth client remains
active.</p>
<p class="p">The effect on existing tokens depends on the grant type used to issue them.</p>
<div class="tablenoborder">
<table border="1" cellpadding="4" cellspacing="0" class="table" frame="border" id="topic_dqw_n2f_fkc__table_bd3_52f_fkc" rules="all" summary="">
<colgroup>
<col style="width:38.02281368821293%">
<col style="width:61.97718631178707%">
</colgroup>
<thead class="thead" style="text-align:left;">
<tr class="row">
<th class="entry cellrowborder" id="d91e271" style="vertical-align:top;">Grant type</th>
<th class="entry cellrowborder" id="d91e274" style="vertical-align:top;">Effect</th>
</tr>
</thead>
<tbody class="tbody">
<tr class="row">
<td class="entry cellrowborder" headers="d91e271" style="vertical-align:top;"><code class="ph codeph">client_credentials</code></td>
<td class="entry cellrowborder" headers="d91e274" style="vertical-align:top;">Tokens stop working. These tokens act on behalf of the admin who created the
OAuth client. After that admin loses the required access, API requests made using
these tokens fail.</td>
</tr>
<tr class="row">
<td class="entry cellrowborder" headers="d91e271" style="vertical-align:top;"><code class="ph codeph">authorization_code</code></td>
<td class="entry cellrowborder" headers="d91e274" style="vertical-align:top;">Tokens continue working. These tokens act on behalf of the individual user
who authorized the application, not the admin who created the OAuth client. Other
users can also continue to authorize the application and obtain new
tokens.</td>
</tr>
</tbody>
</table>
</div>
<p class="p">A confidential OAuth client can issue both types of tokens, so if the admin loses their
required access then it will break the client_credentials tokens while its
authorization_code tokens continue working. </p>
</div>
</div>
<div aria-labelledby="ariaid-title4" class="topic nested2" id="topic_ycb_ztl_m2c">
<h3 class="title topictitle3" id="ariaid-title4">Understanding client kinds</h3>
<div class="body">
<p class="p">OAuth clients have a <code class="ph codeph">kind</code> property that can have one of the following
values:</p>
<ul class="ul" id="topic_ycb_ztl_m2c__ul_zcb_ztl_m2c">
<li class="li">Confidential: Confidential OAuth clients run on secure servers where their credentials
can be kept secure. These clients can use PKCE, <a class="xref" href="https://developer.zendesk.com/api-reference/ticketing/oauth/grant_type_tokens/" target="_blank">client secret</a>, or both.</li>
<li class="li">Public: Public OAuth clients are applications that run in environments where
credentials cannot be securely stored, such as mobile and web apps. These clients must
use <a class="xref" href="https://developer.zendesk.com/documentation/ticketing/working-with-oauth/oauth-pkce/" target="_blank">PKCE</a>. </li>
</ul>
<p class="p">Examples of confidential clients include server-side web applications. Once the
authorization server provides the tokens or the credentials to the web application, those
credentials will not be exposed to the outside.</p>
<p class="p">Examples for public clients include mobile applications and JavaScript applications that
run on user-agent clients such as web browsers. Credentials are easily accessible (and
often visible) in these clients.</p>
<p class="p">Client kinds are also known as client types in the OAuth spec. For more information, see
<a class="xref" href="https://datatracker.ietf.org/doc/html/rfc6749#section-2.1" target="_blank">Client Types</a> in the OAuth 2.0 spec.</p>
<p class="p">This property applies only to the Zendesk Support ticketing system. It is not supported
in Chat or Conversations.</p>
<p class="p">Existing Zendesk OAuth clients currently have the <code class="ph codeph">kind</code> property set to
<code class="ph codeph">unknown</code>. These clients remain unaffected until the
<code class="ph codeph">kind</code> property is updated to either <code class="ph codeph">public</code> or
<code class="ph codeph">confidential</code>. New OAuth clients created in Admin Center must set the
<code class="ph codeph">kind</code> property during creation.</p>
<div class="note" id="topic_ycb_ztl_m2c__note_adb_ztl_m2c">
<span class="notetitle">Note:</span> If you are using an existing Zendesk OAuth client and plan to
change the <code class="ph codeph">kind</code> property to <code class="ph codeph">public</code>, you must first
implement PKCE. Failure to do so will result in the client not working, as PKCE will be
immediately required.</div>
<p class="p">Setting the <code class="ph codeph">kind</code> property is mandatory for all new OAuth clients created
in Admin Center. While the <code class="ph codeph">kind</code> property is not required for OAuth
clients created with the <code class="ph codeph">api/v2/oauth/clients endpoint</code>, Zendesk
recommends including it.</p>
</div>
</div>
</div>
<div aria-labelledby="ariaid-title5" class="topic nested1" id="topic_jkc_dcm_dcc">
<h2 class="title topictitle2" id="ariaid-title5"><strong class="ph b">Implementing an OAuth authorization flow in your application</strong></h2>
<div class="body">
<p class="p">Zendesk supports the authorization code grant flow to get access tokens. This flow is
called the authorization code grant flow because you have to get an authorization code
before you can request an access token.</p>
<p class="p"><img class="image img-screenshot" id="topic_jkc_dcm_dcc__image_kkc_dcm_dcc" src="https://zen-marketing-documentation.s3.amazonaws.com/docs/en/oauth_authorization_flow.png"></p>
<p class="p">The flow uses refresh tokens, which allow you to generate new access tokens without
requiring user re-authorization. To use refresh tokens, your access tokens must expire. </p>
<p class="p">If you created OAuth clients before Zendesk added refresh token support, you must include
<code class="ph codeph">expires_in</code> in your authorization requests. Otherwise, access tokens won’t
expire and refresh tokens won’t work. You can assign a default expiration date for all
tokens issued by an OAuth client by selecting <strong class="ph b">Expire tokens</strong> when <a class="xref" href="#topic_s21_lfs_qk">registering your application with
Zendesk</a>.</p>
<p class="p">Refresh tokens also expire, as indicated by the <code class="ph codeph">refresh_token_expires_in</code>
property. If a refresh token expires or is invalid, your app must send the user through the
full OAuth authorization flow again.</p>
<p class="p">You can customize how long tokens are valid by setting the <code class="ph codeph">expires_in</code> and
<code class="ph codeph">refresh_token_expires_in</code> parameters in seconds when you request
tokens.</p>
<p class="p">The default, minimum, and maximum expiration times are:</p>
<div class="tablenoborder">
<table border="1" cellpadding="4" cellspacing="0" class="table" frame="border" id="topic_jkc_dcm_dcc__table_oauth_token_ttl" rules="all" summary="">
<colgroup>
<col>
<col>
<col>
<col>
</colgroup>
<thead class="thead" style="text-align:left;">
<tr class="row">
<th class="entry cellrowborder" id="d91e467" style="vertical-align:top;">Token type</th>
<th class="entry cellrowborder" id="d91e470" style="vertical-align:top;">Default TTL</th>
<th class="entry cellrowborder" id="d91e473" style="vertical-align:top;">Minimum TTL</th>
<th class="entry cellrowborder" id="d91e476" style="vertical-align:top;">Maximum TTL</th>
</tr>
</thead>
<tbody class="tbody">
<tr class="row">
<td class="entry cellrowborder" headers="d91e467" style="vertical-align:top;">Access token</td>
<td class="entry cellrowborder" headers="d91e470" style="vertical-align:top;">30 minutes</td>
<td class="entry cellrowborder" headers="d91e473" style="vertical-align:top;">5 minutes</td>
<td class="entry cellrowborder" headers="d91e476" style="vertical-align:top;">48 hours</td>
</tr>
<tr class="row">
<td class="entry cellrowborder" headers="d91e467" style="vertical-align:top;">Refresh token</td>
<td class="entry cellrowborder" headers="d91e470" style="vertical-align:top;">30 days</td>
<td class="entry cellrowborder" headers="d91e473" style="vertical-align:top;">7 days</td>
<td class="entry cellrowborder" headers="d91e476" style="vertical-align:top;">90 days</td>
</tr>
</tbody>
</table>
</div>
<p class="p">The deadline for existing local (non-global) OAuth clients to adopt the refresh token flow
is April 1, 2027.</p>
<p class="p">To implement the authorization code grant flow, you need to add the following functionality
to your application:</p>
<ul class="ul" id="topic_jkc_dcm_dcc__ul_lkc_dcm_dcc">
<li class="li"><a class="xref" href="#topic_mkc_dcm_dcc">Step 1 - Send the user to the Zendesk authorization page</a></li>
<li class="li"><a class="xref" href="#topic_ykc_dcm_dcc">Step 2 - Handle the user's authorization decision</a></li>
<li class="li"><a class="xref" href="#topic_blc_dcm_dcc">Step 3 - Get an access token from Zendesk</a></li>
<li class="li"><a class="xref" href="#topic_hlc_dcm_dcc">Step 4 - Use the access token in API calls</a></li>
</ul>
<p class="p">For a tutorial on building a web application that implements an OAuth authorization code
flow, see <a class="xref" href="https://developer.zendesk.com/documentation/api-basics/authentication/using-oauth-to-authenticate-zendesk-api-requests-in-a-web-app/" target="_blank">Using OAuth to authenticate Zendesk API requests in a web
app</a>.</p>
<p class="p">The authorization code grant method supports <a class="xref" href="https://www.oauth.com/oauth2-servers/pkce/" target="_blank">Proof Key
for Code Exchange (PKCE)</a>, which adds an additional layer of security. For more
information, see <a class="xref" href="https://developer.zendesk.com/documentation/ticketing/working-with-oauth/oauth-pkce" target="_blank">Using PKCE to make Zendesk OAuth access tokens more
secure</a> in the developer documentation.</p>
</div>
<div aria-labelledby="ariaid-title6" class="topic nested2" id="topic_mkc_dcm_dcc">
<h3 class="title topictitle3" id="ariaid-title6">Step 1 - Send the user to the Zendesk authorization page</h3>
<div class="body">
<p class="p">First, your application has to send the user to the Zendesk authorization page. The page
asks the user to authorize your application to access Zendesk on their behalf. After the
user makes a choice, Zendesk sends the choice and a few other bits of information back to
your application.</p>
<p class="p"><strong class="ph b">To send the user to the Zendesk authorization page</strong></p>
<p class="p">Add a link or button in your application that sends the user to the following URL:</p>
<div class="p">
<pre class="pre codeblock" id="topic_mkc_dcm_dcc__codeblock_nkc_dcm_dcc"><code>https://{subdomain}.zendesk.com/oauth/authorizations/new</code></pre>
</div>
<p class="p">where <code class="ph codeph">{subdomain}</code> is your Zendesk core subdomain, not a host-mapped
subdomain.</p>
<p class="p">You can use either a POST or a GET request. Include the following parameters:</p>
<ul class="ul" id="topic_mkc_dcm_dcc__ul_okc_dcm_dcc">
<li class="li">
<strong class="ph b">response_type</strong> - Required. Zendesk returns an authorization code in the
response, so specify <code class="ph codeph">code</code> as the response type. Example:
<code class="ph codeph">response_type=code</code>.</li>
<li class="li">
<strong class="ph b">redirect_uri</strong> - Required. The URL that Zendesk should use to send the user's
decision to grant access to your application. The URL has to be absolute and not
relative. It also has to be secure (https) unless you're using localhost or
127.0.0.1.</li>
<li class="li">
<strong class="ph b">client_id</strong> - Required. The unique identifier you obtained when you registered
your application with Zendesk. See the section above.</li>
<li class="li">
<strong class="ph b">scope</strong> - Required. A space-separated list of scopes that control access to the
Zendesk resources. You can request <em class="ph i">read</em>, <em class="ph i">write</em>, or <em class="ph i">impersonate</em>
access to all resources or to specific resources. See <a class="xref" href="#topic_qkc_dcm_dcc">Setting the scope</a>.</li>
<li class="li">
<strong class="ph b">state</strong> - An arbitrary string included in the response from Zendesk after the
user decides whether or not to grant access. You can use the parameter to guard against
cross-site request forgery (<a class="xref" href="http://en.wikipedia.org/wiki/Cross-site_request_forgery" target="_blank">CSRF</a>) attacks. In a CSRF attack, the end user is tricked into clicking a link
that performs an action in a web application where the end user is still authenticated.
To guard against this kind of attack, add some value to the <code class="ph codeph">state</code>
parameter and validate it when it comes back.</li>
<li class="li">
<strong class="ph b">code_challenge</strong> - Required if using PKCE. A string representing a code challenge
derived from a code verifier. See <a class="xref" href="https://developer.zendesk.com/documentation/ticketing/working-with-oauth/oauth-pkce#generating-the-code_challenge-value" target="_blank">Generating the code_challenge value</a> in the
developer documentation.</li>
<li class="li">
<strong class="ph b">code_challenge_method</strong> - Required if using PKCE. The method used to derive the
code challenge. Specify <strong class="ph b">"S256"</strong> as the value.</li>
</ul>
<p class="p">Make sure to URL-encode the parameters.</p>
<p class="p"><strong class="ph b">Example GET request</strong></p>
<div class="p">
<pre class="pre codeblock" id="topic_mkc_dcm_dcc__codeblock_pkc_dcm_dcc"><code>https://{subdomain}.zendesk.com/oauth/authorizations/new?response_type=code&amp;redirect_uri={your_redirect_url}&amp;client_id={your_unique_identifier}&amp;scope=read%20write</code></pre>
</div>
<p class="p">The Zendesk authorization page opens in the end user's browser. After the user makes a
decision, Zendesk sends the decision to the redirect URL you specified in the request.</p>
</div>
<div aria-labelledby="ariaid-title7" class="topic nested3" id="topic_qkc_dcm_dcc">
<h4 class="title topictitle4" id="ariaid-title7">Setting the scope</h4>
<div class="body">
<p class="p">You must <a class="xref" href="#topic_qkc_dcm_dcc">specify a scope</a> to
control the app's access to Zendesk resources. The  <em class="ph i">read</em>  scope gives an app
access to GET endpoints. It includes permission to sideload related resources. The
<em class="ph i">write</em>  scope gives an app access to POST, PUT, and DELETE endpoints for
creating, updating, and deleting resources.</p>
<p class="p">For more on the scope, see <a class="xref" href="https://developer.zendesk.com/rest_api/docs/support/grant_type_tokens#scope" target="_blank">OAuth Tokens for Grant Types</a>.</p>
<p class="p">The <em class="ph i">impersonate</em> scope allows a Zendesk admin to make requests on behalf of end
users. See <a class="xref" href="https://developer.zendesk.com/documentation/ticketing/using-the-zendesk-api/making-api-requests-on-behalf-of-end-users" target="_blank">Making API requests on behalf of end users</a>.</p>
<p class="p">For example, the following parameter gives an app read access to all resources:</p>
<div class="p">
<pre class="pre codeblock" id="topic_qkc_dcm_dcc__codeblock_rkc_dcm_dcc"><code>"scope": "read"</code></pre>
</div>
<p class="p">The following parameter gives read and write access to all resources:</p>
<div class="p">
<pre class="pre codeblock" id="topic_qkc_dcm_dcc__codeblock_skc_dcm_dcc"><code>"scope": "read write"</code></pre>
</div>
<p class="p">You can fine-tune the scope by specifying resource-specific scopes. For the complete
list of supported resources, see <a class="xref" href="https://developer.zendesk.com/api-reference/ticketing/oauth/oauth_tokens/#scopes" target="_blank">Scopes</a> in our developer documentation.</p>
<p class="p">The syntax is as follows:</p>
<div class="p">
<pre class="pre codeblock" id="topic_qkc_dcm_dcc__codeblock_ukc_dcm_dcc"><code>"scope": "<em class="ph i">resource:scope</em>"</code></pre>
</div>
<p class="p">For example, the following parameter restricts an app to only reading tickets:</p>
<div class="p">
<pre class="pre codeblock" id="topic_qkc_dcm_dcc__codeblock_vkc_dcm_dcc"><code>"scope": "tickets:read"</code></pre>
</div>
<p class="p">To give an app read and write access to a resource, specify both scopes:</p>
<div class="p">
<pre class="pre codeblock" id="topic_qkc_dcm_dcc__codeblock_wkc_dcm_dcc"><code>"scope": "users:read users:write"</code></pre>
</div>
<p class="p">To give an app write access only to one resource, such as organizations, and read
access to everything else:</p>
<div class="p">
<pre class="pre codeblock" id="topic_qkc_dcm_dcc__codeblock_xkc_dcm_dcc"><code>"scope": "organizations:write read"</code></pre>
</div>
</div>
</div>
</div>
<div aria-labelledby="ariaid-title8" class="topic nested2" id="topic_ykc_dcm_dcc">
<h3 class="title topictitle3" id="ariaid-title8">Step 2 - Handle the user's authorization decision</h3>
<div class="body">
<p class="p">Your application has to handle the response from Zendesk telling it what the user
decided. The information is contained in URL parameters in the redirect URL.</p>
<p class="p">If the user decided to grant access to the application, the redirect URL contains an
authorization code. Example:</p>
<div class="p">
<pre class="pre codeblock" id="topic_ykc_dcm_dcc__codeblock_zkc_dcm_dcc"><code>{redirect_url}?code=7xqwtlf3rrdj8uyeb1yf</code></pre>
</div>
<p class="p">The authorization code is only valid for 120 seconds.</p>
<p class="p">If the user decided not to grant access to the application, the redirect URL contains
<code class="ph codeph">error</code> and <code class="ph codeph">error_description</code> parameters that inform the
app that the user denied access:</p>
<div class="p">
<pre class="pre codeblock" id="topic_ykc_dcm_dcc__codeblock_alc_dcm_dcc"><code>{redirect_url}?error=access_denied&amp;error_description=The+end-user+or+authorization+server+denied+the+request</code></pre>
</div>
<p class="p">Use these values to control the flow of your application. If the URL contains a
<code class="ph codeph">code</code> parameter, get an access token from Zendesk as described in the
following section. This is the token to include in API calls to Zendesk.</p>
</div>
</div>
<div aria-labelledby="ariaid-title9" class="topic nested2" id="topic_blc_dcm_dcc">
<h3 class="title topictitle3" id="ariaid-title9">Step 3 - Get an access token from Zendesk</h3>
<div class="body">
<p class="p">If your application received an authorization code from Zendesk in response to the user
granting access, your application can exchange it for an access token and a refresh token.
To get the tokens, make a POST request to the <a class="xref" href="https://developer.zendesk.com/api-reference/ticketing/oauth/grant_type_tokens/#create-token-for-grant-type" target="_blank">Create Token Grant Type</a> endpoint:</p>
<div class="p">
<pre class="pre codeblock" id="topic_blc_dcm_dcc__codeblock_clc_dcm_dcc"><code>https://{subdomain}.zendesk.com/oauth/tokens</code></pre>
</div>
<div class="note" id="topic_blc_dcm_dcc__note_dlc_dcm_dcc">
<span class="notetitle">Note:</span> Don't confuse this endpoint with the <a class="xref" href="https://developer.zendesk.com/rest_api/docs/support/oauth_tokens#create-token" target="_blank">Create Token</a> endpoint in the OAuth Tokens API.
Though both endpoints return valid OAuth access tokens, the endpoints don't share the same
path, JSON format, or request parameters.</div>
<p class="p">Include the following required parameters in the request:</p>
<ul class="ul" id="topic_blc_dcm_dcc__ul_elc_dcm_dcc">
<li class="li">
<strong class="ph b">grant_type</strong> - Specify <strong class="ph b">"authorization_code"</strong> as the value.</li>
<li class="li">
<strong class="ph b">code</strong> - Use the authorization code you received from Zendesk after the user
granted access.</li>
<li class="li">
<strong class="ph b">client_id</strong> - Use the unique identifier specified in an OAuth client in the
Zendesk Admin Center (<strong class="ph b">Apps and integrations</strong> &gt; <strong class="ph b">APIs</strong> &gt; <strong class="ph b">OAuth
Clients</strong>). See <a class="xref" href="#topic_s21_lfs_qk">Registering your
application with Zendesk</a>.</li>
<li class="li">
<strong class="ph b">client_secret</strong> - Use the secret specified in an OAuth client in the Zendesk
Admin Center (<strong class="ph b">Apps and integrations</strong> &gt; <strong class="ph b">APIs</strong> &gt; <strong class="ph b">OAuth Clients</strong>).
See <a class="xref" href="#topic_s21_lfs_qk">Registering your application with
Zendesk</a>. <p class="p">If you use the PKCE <code class="ph codeph">code_challenge</code> and
<code class="ph codeph">code_verifier</code> parameters, <code class="ph codeph">client_secret</code> is not
required. You can use this characteristic to migrate from the <a class="xref" href="https://oauth.net/2/grant-types/implicit/" target="_blank">implicit grant flow</a>, which is no longer recommended because of security
concerns. See <a class="xref" href="https://developer.zendesk.com/documentation/ticketing/working-with-oauth/oauth-pkce#using-pkce-to-migrate-from-the-implicit-grant-flow" target="_blank">Using PKCE to migrate from the implicit grant
flow</a> in the developer documentation.</p>
</li>
<li class="li">
<strong class="ph b">redirect_uri</strong> - The same redirect URL as in step 1. For ID purposes only.</li>
<li class="li">
<strong class="ph b">scope</strong> - See <a class="xref" href="#topic_qkc_dcm_dcc">Setting the
scope</a>.</li>
<li class="li">
<strong class="ph b">code_verifier</strong> - Required if using PKCE. The string used to generate the
<code class="ph codeph">code_challenge</code> value. See <a class="xref" href="https://developer.zendesk.com/documentation/ticketing/working-with-oauth/oauth-pkce#generating-the-code_challenge-value" target="_blank">Generating the code_challenge value</a> in the
developer documentation.</li>
<li class="li">
<strong class="ph b">expires_in</strong> - Number of seconds the access token is valid. Specify a value
between 300 seconds (5 minutes) and 172,800 seconds (2 days).</li>
<li class="li">
<strong class="ph b">refresh_token_expires_in</strong> - Number of seconds the refresh token is valid.
Specify a value between 604,800 seconds (7 days) and 7,776,000 seconds (90 days).</li>
</ul>
<p class="p">See the <a class="xref" href="https://developer.zendesk.com/api-reference/ticketing/oauth/grant_type_tokens/#create-token-for-grant-type" target="_blank">Create Token Grant Type</a> endpoint in the API
reference for more information. </p>
<p class="p">The request must be over https and the properties must be formatted as JSON. If you use a
custom or third-party application to make the API request, see its documentation for the
proper format of property values.</p>
<p class="p"><strong class="ph b">Using the Python requests library</strong></p>
<div class="p">
<pre class="pre codeblock"><code>response = requests.post(
f'https://{subdomain}.zendesk.com/oauth/tokens',
data={
'grant_type': 'authorization_code',
'code': f'{your_code}',
'client_id': f'{your_client_id}',
'client_secret': f'{your_client_secret}',
'redirect_uri': f'{your_redirect_url}',
'scope': 'read',
'expires in': 172800,
'refresh_token_expires_in': 800000
}
)</code></pre>
</div>
<p class="p"><strong class="ph b">Example response</strong></p>
<pre class="pre codeblock" id="topic_blc_dcm_dcc__codeblock_glc_dcm_dcc"><code>Status: 201 OK

{
"access_token": "gErypPlm4dOVgGRvA1ZzMH5MQ3nLo8bo",
"refresh_token": "31048ba4d7c601302f3173f243da835f",
"token_type": "bearer",
"scope":"read",
"expires_in": 172800,
"refresh_token_expires_in": 800000
}</code></pre>
<p class="p">Save both the access token and the refresh token in a secure data store to reuse them
later.</p>
</div>
</div>
<div aria-labelledby="ariaid-title10" class="topic nested2" id="topic_hlc_dcm_dcc">
<h3 class="title topictitle3" id="ariaid-title10">Step 4 - Use the access token in API calls</h3>
<div class="body">
<p class="p">The app can use the access token to make API calls. Include the token in an HTTP
Authorization header with the request, as follows:</p>
<p class="p"><code class="ph codeph">Authorization: Bearer {a_valid_access_token}</code></p>
<p class="p">For example, a curl request to list tickets would look as follows:</p>
<pre class="pre codeblock" id="topic_hlc_dcm_dcc__codeblock_ilc_dcm_dcc"><code>curl https://{subdomain}.zendesk.com/api/v2/tickets.json \
-H "Authorization: Bearer gErypPlm4dOVgGRvA1ZzMH5MQ3nLo8bo"</code></pre>
</div>
</div>
</div>
<div aria-labelledby="ariaid-title11" class="topic nested1" id="topic_p1c_xjf_52c">
<h2 class="title topictitle2" id="ariaid-title11">Replacing expired access tokens</h2>
<div class="body">
<p class="p">Access tokens will expire after a set time. Use the refresh token you received with the
access token to request a new access token. You don't need to use the authorization code
flow to get the new token.</p>
<p class="p">Your application should implement a fallback mechanism to handle expired access tokens and
expired refresh tokens. For example, if the access token has expired or encountered an
error, use a handler to refresh it. If the refresh process fails or there is no refresh
token linked to the access token, redirect the user to
<code class="ph codeph">https://{subdomain}.zendesk.com/oauth/authorizations/new</code> to re-authorize
your application.</p>
</div>
<div aria-labelledby="ariaid-title12" class="topic nested2" id="topic_lcx_gpz_qhc">
<h3 class="title topictitle3" id="ariaid-title12">Detecting that an access token has expired</h3>
<div class="body">
<p class="p">To determine if an access token has expired, instrument your code to look for a
<strong class="ph b">401</strong> response after making an API request with the token. The response will
include the following JSON string:</p>
<div class="p">
<pre class="pre">{"error":"invalid_token","error_description":"The access token provided is expired, revoked,
malformed or invalid for other reasons."}</pre>
</div>
<p class="p">If you receive a 401 response, call a handler to refresh the access token using the
refresh token you received with the access token. </p>
<p class="p">Here's an example using the Python requests library:</p>
<pre class="pre codeblock"><code>url = f'https://{your_subdomain}.zendesk.com/{endpoint}'
headers = {'Authorization': f'Bearer {access_token}'}
response = requests.get(url, headers=headers)
if response.status_code == 401: # if token has expired or is otherwise invalid
access_token = refresh_access_token(refresh_token)
headers['Authorization'] = f'Bearer {access_token}'
response = requests.get(url, headers=headers)</code></pre>
</div>
</div>
<div aria-labelledby="ariaid-title13" class="topic nested2" id="topic_ltp_jpz_qhc">
<h3 class="title topictitle3" id="ariaid-title13">Refreshing an access token</h3>
<div class="body">
<p class="p">To refresh an access token, make a POST request to the <a class="xref" href="https://developer.zendesk.com/api-reference/ticketing/oauth/grant_type_tokens/#create-token-for-grant-type" target="_blank">Create Token Grant Type</a> endpoint:</p>
<div class="p">
<pre class="pre codeblock"><code>https://{subdomain}.zendesk.com/oauth/tokens</code></pre>
</div>
<p class="p">Include the following properties in the request body:</p>
<ul class="ul" id="topic_ltp_jpz_qhc__ul_ojl_2nz_qhc">
<li class="li">
<strong class="ph b">grant_type</strong> - Specify the string <strong class="ph b">"refresh token"</strong> as the value.</li>
<li class="li">
<strong class="ph b">refresh_token</strong> - Specify the value of the refresh token you received with the
access token.</li>
<li class="li">
<strong class="ph b">client_id</strong> - Use the identifier specified in the OAuth client in the Zendesk
Admin Center (<strong class="ph b">Apps and integrations</strong> &gt; <strong class="ph b">APIs</strong> &gt; <strong class="ph b">OAuth clients</strong>).
See <a class="xref" href="#topic_s21_lfs_qk">Registering your application with
Zendesk</a>.</li>
<li class="li">
<strong class="ph b">client_secret</strong> - Use the secret specified in the OAuth client in the Zendesk
Admin Center (<strong class="ph b">Apps and integrations</strong> &gt; <strong class="ph b">APIs</strong> &gt; <strong class="ph b">OAuth Clients</strong>).
See <a class="xref" href="#topic_s21_lfs_qk">Registering your application with
Zendesk</a>.<p class="p">If you use the PKCE <code class="ph codeph">code_challenge</code> and
<code class="ph codeph">code_verifier</code> parameters, <code class="ph codeph">client_secret</code> is not
required. You can use this characteristic to migrate from the <a class="xref" href="https://oauth.net/2/grant-types/implicit/" target="_blank">implicit grant flow</a>, which is no longer recommended because of security
concerns. See <a class="xref" href="https://developer.zendesk.com/documentation/ticketing/working-with-oauth/oauth-pkce#using-pkce-to-migrate-from-the-implicit-grant-flow" target="_blank">Using PKCE to migrate from the implicit grant
flow</a> in the developer documentation.</p>
</li>
<li class="li">
<strong class="ph b">scope</strong> - See <a class="xref" href="#topic_qkc_dcm_dcc">Setting the
scope</a>.</li>
<li class="li">
<strong class="ph b">expires_in</strong> - Number of seconds the access token is valid. Specify a value
between 300 seconds (5 minutes) and 172,800 seconds (2 days).</li>
<li class="li">
<strong class="ph b">refresh_token_expires_in</strong> - Number of seconds the refresh token is valid.
Specify a value between 604,800 seconds (7 days) and 7,776,000 seconds (90 days).</li>
</ul>
<p class="p">See the <a class="xref" href="https://developer.zendesk.com/api-reference/ticketing/oauth/grant_type_tokens/#create-token-for-grant-type" target="_blank">Create Token Grant Type</a> endpoint in the API
reference for more information. </p>
<p class="p">Here's an example request using the Python requests library:</p>
<div class="p">
<pre class="pre codeblock"><code>response = requests.post(
f'https://{your_subdomain}.zendesk.com/oauth/tokens',
data={
'grant_type': 'refresh_token',
'refresh_token': refresh_token,
'client_id': client_id,
'client_secret': client_secret,
'scope': 'read',
'expires in': 172800,
'refresh_token_expires_in': 800000
}
)</code></pre>
</div>
<p class="p">The request creates new access and refresh tokens while invalidating the previous ones.
Here's an example response:</p>
<pre class="pre codeblock"><code>Status: 201 OK

{
"access_token": "gErypPlm4dOVgGRvA1ZzMH5MQ3nLo8bo",
"refresh_token": "31048ba4d7c601302f3173f243da835f,
"token_type": "bearer",
"scope": "read",
"expires_in": 172800,
"refresh_token_expires_in": 80000
}</code></pre>
<p class="p">Save both tokens in a secure data store to reuse them later.</p>
</div>
</div>
</div>
<script id="docs-schema-markup" type="application/ld+json">{
"@context": "https://schema.org",
"@type": "TechArticle",
"@id": "https://support.zendesk.com/hc/en-us/articles/4408845965210",
"url": "https://support.zendesk.com/hc/en-us/articles/4408845965210",
"headline": "Using OAuth authentication with your application",
"description": "You can authenticate your application's API requests using OAuth 2 by registering your application, implementing the authorization code flow, and managing access and refresh tokens to securely access data without storing user passwords.",
"articleSection": "Account access",
"datePublished": "2021-10-16T05:17:03+00:00",
"dateModified": "2026-08-25T15:47:27.294593+00:00",
"inLanguage": "en-US",
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://support.zendesk.com/hc/en-us/articles/4408845965210"
},
"author": {
"@type": "Organization",
"name": "Zendesk",
"@id": "https://www.zendesk.com"
},
"publisher": {
"@type": "Organization",
"name": "Zendesk",
"@id": "https://www.zendesk.com"
},
"isPartOf": {
"@type": "WebSite",
"name": "Zendesk Help",
"@id": "https://support.zendesk.com/hc/"
},
"about": {
"@type": "SoftwareApplication",
"name": "Zendesk",
"@id": "https://www.zendesk.com"
}
}</script><script id="fast-path-script">
//<![CDATA[
const fast_path_style = document.createElement('style');
fast_path_style.innerHTML = `#article-body .fastpath{font-size:.9em;background-color:#f3f3f3;border:1px solid #d3d3d3;padding:10px 10px 8px;margin-bottom:16px}#article-body .fastpath::before{content:none!important}`;
document.head.appendChild(fast_path_style);
//]]>
</script><script id="ai-summary-script">
//<![CDATA[
const ai_summary_style = document.createElement('style');
ai_summary_style.innerHTML = `#styled-article-body{padding:0 0 0}#article-body #docs-ai-summary{background-color:#f3f3f3;border:1px solid #d3d3d3;padding:10px 10px 6px;margin-bottom:16px}#article-body #docs-ai-summary #docs-ai-summary-toggle{font-size:.9em;font-weight:700;margin-bottom:4px;cursor:pointer;display:flex;justify-content:space-between;align-items:center}#article-body #docs-ai-summary #docs-ai-summary-toggle #up-triangle{margin-left:auto;padding-right:10px;display:none}#article-body #docs-ai-summary #docs-ai-summary-toggle #down-triangle{margin-left:auto;padding-right:10px}#article-body #docs-ai-summary #docs-ai-summary-content{font-size:.9em;padding-left:25px;padding-right:25px;margin-bottom:12px}`;
document.head.appendChild(ai_summary_style);

const toggleAISummary = () => {
const summary = document.getElementById("docs-ai-summary-content");
const upTriangle = document.getElementById("up-triangle");
const downTriangle = document.getElementById("down-triangle");
if (summary.style.display === "none") {
summary.style.display = "block";
upTriangle.style.display = "none";
downTriangle.style.display = "inline";
} else {
summary.style.display = "none";
upTriangle.style.display = "inline";
downTriangle.style.display = "none";
}
};

document.getElementById("docs-ai-summary-toggle").addEventListener("click", toggleAISummary);
//]]>
</script>
</body>