<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Xkit</title>
    <description>The latest articles on Forem by Xkit (@xkit).</description>
    <link>https://forem.com/xkit</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F3567%2F43bcea44-0f61-49f8-b513-0a9183117d67.png</url>
      <title>Forem: Xkit</title>
      <link>https://forem.com/xkit</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/xkit"/>
    <language>en</language>
    <item>
      <title>What domain do I use when setting up OAuth for Zendesk?</title>
      <dc:creator>Trey Griffith</dc:creator>
      <pubDate>Thu, 28 Jan 2021 19:53:08 +0000</pubDate>
      <link>https://forem.com/xkit/what-domain-do-i-use-when-setting-up-oauth-for-zendesk-5h13</link>
      <guid>https://forem.com/xkit/what-domain-do-i-use-when-setting-up-oauth-for-zendesk-5h13</guid>
      <description>&lt;p&gt;If you're building a Zendesk integration that allows your users to connect their Zendesk accounts to your app, you have probably noticed that all the &lt;a href="https://support.zendesk.com//hc/en-us/articles/203663836"&gt;Zendesk documentation for OAuth&lt;/a&gt; use the domain &lt;code&gt;{subdomain}.zendesk.com&lt;/code&gt;, and you might be asking: whose subdomain is this? Is it the app developer's or the user's?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The subdomain you use when developing OAuth apps for Zendesk is the &lt;em&gt;user&lt;/em&gt;'s subdomain&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The answer is that it's the &lt;em&gt;user&lt;/em&gt;'s subdomain, not you, the developer's subdomain. If you're building the integration only for internal use, that's the same subdomain so it won't matter, but if you intend for other Zendesk users to make use of it (what Zendesk calls a "global OAuth client"), you'll need to use their subdomain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why do I need the user's subdomain?
&lt;/h3&gt;

&lt;p&gt;Why use the customer's subdomain? &lt;a href="https://developer.zendesk.com/apps/docs/publish/global_oauth_intro"&gt;Zendesk's docs&lt;/a&gt; sum it up:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Zendesk maintains separate logins for each Zendesk account or subdomain. When a customer signs in, they're signing into a specific Zendesk subdomain which carries over to OAuth. When a Zendesk account owner uses OAuth to authorize your service, they're authorizing the service for their subdomain.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The documentation can be a little bit confusing at times, using "your" subdomain at times when they mean "the user's" subdomain. Just know whereever you see &lt;code&gt;{subdomain}&lt;/code&gt;, they're referring to your user, not you.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to get the user's subdomain
&lt;/h3&gt;

&lt;p&gt;Now you might be wondering if Zendesk provides a sort of global subdomain that you can use where Zendesk either determines through cookies, or collects directly from the user, their Zendesk subdomain. The unfortunate answer here is no: you're left to your own devices to determine the user's subdomain &lt;em&gt;before&lt;/em&gt; sending them through the OAuth flow. You'll also need to hang on to this subdomain: it's used not only for the initial authorization request, but also the token request and API calls afterward.&lt;/p&gt;

&lt;p&gt;You'll probably want to model your own subdomain collection after Zendesk's login process pictured here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TBIRgoPN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/gi6c1l8ogvobah1v29o0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TBIRgoPN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/gi6c1l8ogvobah1v29o0.png" alt="Zendesk's default subdomain collection screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;So if you're building a Zendesk integration, don't forget to build in subdomain collection to make sure you're making requests to the right domain. &lt;/p&gt;

&lt;p&gt;Of course, if you don't want to bother building an entire subdomain collection flow, you can use &lt;a href="https://app.xkit.co/connectors/new/zendesk"&gt;Xkit's Zendesk Connector&lt;/a&gt;. It has built-in subdomain collection through a popup window and it will surface the subdomain to you with every access token it provides.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EYYiCxfg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zxaenyecq2kyi1okyfxm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EYYiCxfg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zxaenyecq2kyi1okyfxm.png" alt="Xkit's Zendesk subdomain collection popup"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With one API call you'll get everything you'll need to get access to your user's Zendesk account. And you can &lt;a href="https://xkit.co/pricing"&gt;get started in 30 minutes, for free&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>oauth</category>
      <category>api</category>
      <category>zendesk</category>
    </item>
    <item>
      <title>Why does my GitHub OAuth2 Token not have the scopes I requested?</title>
      <dc:creator>Trey Griffith</dc:creator>
      <pubDate>Wed, 27 Jan 2021 18:18:06 +0000</pubDate>
      <link>https://forem.com/xkit/why-does-my-github-oauth2-token-not-have-the-scopes-i-requested-3nfm</link>
      <guid>https://forem.com/xkit/why-does-my-github-oauth2-token-not-have-the-scopes-i-requested-3nfm</guid>
      <description>&lt;h3&gt;
  
  
  Why doesn't my access token work?
&lt;/h3&gt;

&lt;p&gt;If you're building a GitHub integration into your app that uses GitHub's OAuth authorization method (as opposed to their App authorization, which is similar but has important differences), you may have noticed that sometimes the scopes that your access token has been granted are different from what you requested. This can be a particularly difficult issue to debug since it usually rears its head when you're trying to use an API protected by one of the scopes you requested, but the API request fails for just one of your users. However, when you try to reproduce this issue, it seems to work just fine. What's going on here?&lt;/p&gt;

&lt;p&gt;GitHub makes use of a little known part of the &lt;a href="https://tools.ietf.org/html/rfc6749#section-3.3"&gt;OAuth2 spec&lt;/a&gt; that allows the authorization server (in this case GitHub) to: "fully or partially ignore the scope requested by the client, based on the authorization server policy or the resource owner's instructions". The way GitHub does this is by allowing your user to pick and choose which of your requested scopes to actually grant to your application through a process we call "line item grants".&lt;/p&gt;

&lt;p&gt;As you can see, this is a completely valid use of the OAuth2 spec, but since most providers don't use this, you may not have been ready for it. But not to worry, while the spec includes the ability for the authorization server (GitHub) to ignore your scope, it does provide you some recourse: "if the issued access token scope is different from the one requested by the client, the authorization server MUST include the &lt;code&gt;scope&lt;/code&gt; response parameter to inform the client of the actual scope granted."&lt;/p&gt;

&lt;h3&gt;
  
  
  Verifying the Granted Scope
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;scope&lt;/code&gt; parameter in the Access Token response (which you were probably ignoring until now) will contain the scope that your user actually granted you, and which you therefore actually have access to with your token. See &lt;a href="https://docs.github.com/en/free-pro-team@latest/rest/guides/basics-of-authentication#checking-granted-scopes"&gt;GitHub's docs about this process here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Unfortunately, here's where GitHub goes off the rails. While GitHub allows you to specify the &lt;code&gt;scope&lt;/code&gt; you want in your request by &lt;em&gt;space&lt;/em&gt;-delimiting each scope string (e.g. &lt;code&gt;read:org read:user&lt;/code&gt;), which matches the &lt;a href="https://tools.ietf.org/html/rfc6749#section-3.3"&gt;OAuth2 Spec&lt;/a&gt;, it returns &lt;code&gt;scope&lt;/code&gt; by &lt;em&gt;comma&lt;/em&gt;-delimiting the scope strings (e.g. &lt;code&gt;read:org,read:user&lt;/code&gt;) in violation of the specification. Which means you may have to serialize and parse your &lt;code&gt;scope&lt;/code&gt; using different patterns.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scope Normalization
&lt;/h3&gt;

&lt;p&gt;In addition, GitHub transforms the scopes through a process called "&lt;a href="https://docs.github.com/en/free-pro-team@latest/developers/apps/scopes-for-oauth-apps#normalized-scopes"&gt;scope normalization&lt;/a&gt;". Basically, they take your requested scopes and narrow them down to the smallest set of logical scopes that will be granted. So, for example, if you request the &lt;code&gt;repo&lt;/code&gt; scope, but you also request &lt;code&gt;public_repo&lt;/code&gt; and &lt;code&gt;delete:repo&lt;/code&gt;, GitHub will return just &lt;code&gt;repo&lt;/code&gt;, since the other requested scopes are already included in the &lt;code&gt;repo&lt;/code&gt; scope.&lt;/p&gt;

&lt;p&gt;The actual normalization process (which scopes are removed when requesting two or more) is only partially documented, but based on our reading of the documentation and subsequent testing, here's the normalization tree:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;repo
┣ delete:repo
┣ repo:status
┣ repo:invite
┣ repo_deployment
┣ public_repo
┃ ┗ admin:repo_hook
┃   ┗ write:repo_hook
┃     ┗ read:repo_hook
┗ security_events
admin:org
┗ write:org
  ┗ read:org
admin:public_key
┗ write:public_key
  ┗ read:public_key
user
┣ read:user
┣ user:email
┗ user:follow
write:discussion
┗ read:discussion
write:packages
┗ read:packages
admin:gpg_key
┗ write:gpg_key
  ┗ read:gpgp_key
workflow
gist
notifications
admin:org_hook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;If you're building a GitHub integration, be sure to check the normalized, comma-delimited scopes that your user actually granted you via GitHub's API to make sure that your token has the scopes you expect it to.&lt;/p&gt;

&lt;p&gt;Of course, if you want to avoid building (or heck, even learning) all that, you can use &lt;a href="https://app.xkit.co/connectors/new/github-oauth"&gt;Xkit's GitHub OAuth Connector&lt;/a&gt; and be up and running with always-valid access tokens in a half hour. We have built-in checks to make sure that your tokens have the scopes you expect them to so you don't have to worry about it.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>api</category>
      <category>oauth</category>
      <category>github</category>
    </item>
    <item>
      <title>When do Salesforce access tokens expire?</title>
      <dc:creator>Trey Griffith</dc:creator>
      <pubDate>Thu, 21 Jan 2021 23:09:20 +0000</pubDate>
      <link>https://forem.com/xkit/when-do-salesforce-access-tokens-expire-1ih9</link>
      <guid>https://forem.com/xkit/when-do-salesforce-access-tokens-expire-1ih9</guid>
      <description>&lt;p&gt;If you're building a Salesforce integration into your app, particularly a "Connected App" style of integration, and your integration uses &lt;a href="https://help.salesforce.com/articleView?id=remoteaccess_authenticate.htm&amp;amp;type=5"&gt;OAuth to get access to Salesforce's REST APIs&lt;/a&gt;, you may be wondering when the access tokens issued by Salesforce expire.&lt;/p&gt;

&lt;p&gt;According to the &lt;a href="https://tools.ietf.org/html/rfc6749#section-4.2.2"&gt;OAuth 2.0 spec&lt;/a&gt; the &lt;code&gt;expires_in&lt;/code&gt; parameter is included with the Access Token response and provides the lifetime of the returned token in seconds. And while this parameter is extremely common in OAuth implementations, it is merely &lt;em&gt;recommended&lt;/em&gt; and not &lt;em&gt;required&lt;/em&gt;. The Salesforce OAuth implementation does &lt;em&gt;not&lt;/em&gt; use this parameter.&lt;/p&gt;

&lt;h3&gt;
  
  
  Typical Token Expiration
&lt;/h3&gt;

&lt;p&gt;In our experience at &lt;a href="https://xkit.co"&gt;Xkit&lt;/a&gt;, Salesforce Access Tokens typically expire in 2 hours (7,200 seconds), but this value is not guaranteed to be static—Salesforce could change it at any time with no warning.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Salesforce Access Tokens typically expire in 2 hours&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  How to determine token expiration
&lt;/h3&gt;

&lt;p&gt;So what do you do? You have two options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use your access token until you receive a &lt;code&gt;401&lt;/code&gt; HTTP status code, and only refresh it then&lt;/li&gt;
&lt;li&gt;Use Salesforce's token introspection endpoint to determine when the token expires&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Token Introspection
&lt;/h3&gt;

&lt;p&gt;That's right! While Salesforce does not include an &lt;code&gt;expires_in&lt;/code&gt; parameter, they do have a special token introspection endpoint as part of the &lt;a href="https://tools.ietf.org/html/rfc7662"&gt;extension to the OAuth 2.0 spec&lt;/a&gt;. This endpoint (&lt;a href="https://help.salesforce.com/articleView?id=remoteaccess_oidc_token_introspection_endpoint.htm&amp;amp;type=5"&gt;Salesforce docs here&lt;/a&gt;) returns a JSON object that includes an &lt;code&gt;exp&lt;/code&gt; property. This &lt;code&gt;exp&lt;/code&gt; corresponds to the &lt;a href="https://tools.ietf.org/html/rfc7519#section-4.1.4"&gt;&lt;code&gt;exp&lt;/code&gt; claim of the JWT spec&lt;/a&gt;. Unlike the &lt;code&gt;expires_in&lt;/code&gt; parameter, &lt;code&gt;exp&lt;/code&gt; is a Unix epoch timestamp.&lt;/p&gt;

&lt;p&gt;Here's an example request from the Salesforce docs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /services/oauth2/introspect HTTP/1.1
Host: https://mycompany.my.salesforce.com
Accept: application/json
Content-Type: application/x-www-form-urlencoded
Authorization: Basic M01WRzlsS2NQb05JTlZCSVBKamR3MUo5TExNODJIbkZWVlgxOUtZMQp1QTVtdTBRc
UVXaHFLcG9XM3N2RzNYSHJYRGlDUWpLMW1kZ0F2aENzY0E5R0U6MTk1NTI3OTkyNTY3NTI0MTU3MQ==

token=00DR00000009GVP!ARQAQE5XuPV7J4GoOu3wvLZjZI_TxoBpeZpRb6d8AVdII6cz
_BY_uu1PKxGeAjkSvO0LpWoL_qfbQWKlXoz1f2ICNiy.6Ndr&amp;amp;
token_type_hint=access_token
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And an example response from our own experience:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP/1.1 200 OK
Content-Type: application/json

{"active":true,"scope":"api refresh_token openid","client_id":"3MVG9lKcPoNINVBIPJjdw1J9LLM82HnFVVX19KY1uA5mu0QqEWhqKpoW3svG3XHrXDiCQjK1mdgAvhCscA9GE","username":"user@example.com\",\"sub\":\"https://login.salesforce.com/id/000000000000000000/000000000000000000\",\"token_type\":\"access_token\",\"exp\":1610509606,\"iat\":1610502406,\"nbf\":1610502406}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;So if you need to know when your Salesforce Access Token expires, call the introspection endpoint and you can figure it out for yourself. And don't forget to add the special &lt;code&gt;refresh_token&lt;/code&gt; scope so you can refresh your access when it does expire.&lt;/p&gt;

&lt;p&gt;Of course, if you want to avoid building (or heck, even learning) all that, you can use &lt;a href="https://app.xkit.co/connectors/new/salesforce"&gt;Xkit's Salesforce Connector&lt;/a&gt; and be up and running with always-fresh access tokens in a half hour.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>api</category>
      <category>oauth</category>
      <category>salesforce</category>
    </item>
  </channel>
</rss>
