Easy Auth – App Service token store

The App Service Token Store was added to App Service Authentication / Authorization and it is a repository of OAuth tokens associated with your app users.

When a user logs into your app via an identity provider, such as AAD or Social Providers, the identity provider returns one or more tokens that:

  • prove the user’s identity
  • provide access to resources owned by that user.

By default, App Service apps have a built-in token store available for authentication, which your app code can immediately take advantage of and is available in all SKUs.

 

Back in February, I was putting together a talk for DevTeach conference in Montreal and I stumbled upon Chris Gillum‘s post on the “App Service Token Store”. I believe he does a brilliant job detailing the topic so I reached out to him asking if I could quote hist post and he kindly accepted. You may find his entire post here, going very much in detail on the topic. A couple of things I want to point out:

 

Common Scenarios for the Token Store

Let’s say you’re building an app and you want the ability for users to log in with their Facebook account credentials. Lets also say that you want your app post to their Facebook timelines on their behalf. In order to call the Facebook API to perform such an action, you would need an OAuth token issued by Facebook with the proper permissions to do this. The token store is for automatically collecting and storing these tokens and making it easy for your app to access them.

Similarly if you are writing an app which needs to call into the Azure Active Directory Graph API or even the Microsoft Graph on behalf of a user in your corporate directory, your app can be configured to store the required access token in the token store automatically. More details on how to configure your AAD applications for Graph API access will come in a subsequent post.

While convenient, not all apps require these capabilities. If, for example, you’re only using built-in authentication to protect access to a staging slot and don’t need to actually do anything with these extra tokens, then you likely don’t need to use the token store and can safely disable the feature.

Accessing the Tokens

From within your backend code, accessing these tokens is as easy as reading an HTTP request header. The headers are named like X-MS-TOKEN-{provider}-{type}. The possible token header names are listed below:

Azure Active Directory Token Request Headers

X-MS-TOKEN-AAD-ID-TOKEN

X-MS-TOKEN-AAD-ACCESS-TOKEN

X-MS-TOKEN-AAD-EXPIRES-ON

X-MS-TOKEN-AAD-REFRESH-TOKEN

Facebook Token Request Headers

X-MS-TOKEN-FACEBOOK-ACCESS-TOKEN

X-MS-TOKEN-FACEBOOK-EXPIRES-ON

Google Token Request Headers

X-MS-TOKEN-GOOGLE-ID-TOKEN

X-MS-TOKEN-GOOGLE-ACCESS-TOKEN

X-MS-TOKEN-GOOGLE-EXPIRES-ON

X-MS-TOKEN-GOOGLE-REFRESH-TOKEN

Microsoft Account Token Request Headers

X-MS-TOKEN-MICROSOFTACCOUNT-ACCESS-TOKEN

X-MS-TOKEN-MICROSOFTACCOUNT-EXPIRES-ON

X-MS-TOKEN-MICROSOFTACCOUNT-AUTHENTICATION-TOKEN

X-MS-TOKEN-MICROSOFTACCOUNT-REFRESH-TOKEN

Twitter Token Request Headers

X-MS-TOKEN-TWITTER-ACCESS-TOKEN

X-MS-TOKEN-TWITTER-ACCESS-TOKEN-SECRET

Querying the request headers is the simplest method for obtaining these user-specific OAuth tokens. No SDKs, external API calls, database queries, or file access is required (this is a general theme you’ll see repeated when it comes to Easy Auth). The values of these headers are the raw token values and can be used as-is when calling into the provider APIs.

If you want to access the tokens from a client (like JavaScript in a browser), or if you want to get a richer set of information about the logged in user, you can also send an authenticated GET request to the local /.auth/me endpoint. Whatever authentication method you use to access your app (cookies or tokens) can be used to access this API. The request format is very simple:

GET /.auth/me

…which returns a JSON response that looks like the following:

[{

“provider_name”:””,

“user_id”: “”,

“user_claims”:[{“typ”: “”,”val”: “”}, …],

“access_token”:””,

“access_token_secret”:””,

“authentication_token”:””,

“expires_on”:””,

“id_token”:””,

“refresh_token”:””

}]

This API is what the App Service Server SDK uses internally to fetch information about the currently logged-in user.

Regardless of the selected method, actual tokens available depend on what provider was used as well as which scopes were configured for that provider. For example, a Google login will always include an access token, but will only include a refresh token if the offline access scope is configured.

Where do Tokens Live

Internally, all these tokens are stored in your app’s local file storage under D:/home/data/.auth/tokens. The tokens themselves are all encrypted in user-specific .json files using app-specific encryption keys and cryptographically signed as per best practice. This is an internal detail that your app code does not need to worry about. We’re asked to trust they are secure.

App’s distributed file storage was chosen as the default location for storing tokens because it’s freely available to all App Service apps without any additional configuration. However, the file system token store may not be ideal for all customers. In particular, it does not scale well when large numbers of concurrent logins are expected and is incompatible with the local disk caching feature of App Service.

As an alternative, you can provision an Azure Blob Storage container and configure your web app with a SaS URL (with read/write/list access) pointing to that blob container. This SaS URL can then be saved to the WEBSITE_AUTH_TOKEN_CONTAINER_SASURL app setting. When this app setting is present, all tokens will be stored in and fetched from the specified blob container.

!

Existing tokens are not migrated to the new store, therefore users will need to re-authenticate with the app in order for their tokens to become available.

Refreshing Tokens

Most tokens will eventually expire. Some providers, like Facebook, have access tokens which expire after 60 days. Other providers, like Azure AD, Microsoft Account, and Google, issue access tokens which expire in 1 hour. In all cases, a fresh set of tokens can be obtained by forcing the user to re-authenticate. This is reasonable for Facebook since a re-auth would only need to happen once every 60 days. However, this is not practical for Azure AD, Microsoft Account, and Google, where the token expiration is 1 hour.

To avoid the need to re-authenticate the user to get a new access token, you can instead issue an authenticated GET request to the /.auth/refresh endpoint of your application. This is a built-in endpoint, just like /.auth/me. When called, the Easy Auth module will automatically refresh the access tokens in the token store for the authenticated user. Subsequent requests for tokens by your app code will then get the most up-to-date tokens. In order for this to work, the token store must contain refresh tokens for your provider. If you’re not familiar with how to do this, here are some hints:

Google: Append an “access_type=offline” query string parameter to your /.auth/login API call (if using the Mobile Apps SDK, you can add this to one of the LogicAsync overloads).

Microsoft Account: Select the wl.offline_access scope in the Azure management portal.

Azure AD: This is a little complex right now, but take a look at my next post on enabling Graph API access. Follow the setup steps and this will also enable you to get refresh tokens for Azure AD (you can omit the Read directory data and the resource=… parts if they don’t apply to you). The plan is to simplify this in the future.

Here is an example snippet which refreshes tokens from a JavaScript client (with jQuery):

function refreshTokens() {

var refreshUrl = “/.auth/refresh”;

$.ajax(refreshUrl) .done(function() {

console.log(“Token refresh completed successfully.”);

}) .fail(function() {

console.log(“Token refresh failed. See application logs for details.”);

});

}

It’s important to note that the /.auth/refresh API is not guaranteed to succeed. For example, a user is free to revoke the permissions granted to your app at any time. In such cases, any attempt to refresh existing access tokens will fail with a 403 Forbidden response. Also, if your auth provider is not configured to return refresh tokens (e.g. you did not request the appropriate offline scope), you can expect this to fail with a 400 Bad Request response. In either case, you can check your application logs for details (assuming you have already enabled application logging).

If you are a mobile app and use App Service Mobile SDK, which internally uses the x-zumo-auth header to authenticate with your App Service backend, you may be aware of the fact that your x-zumo-auth JWT may also have a short expiration. This mobile authentication token can also be refreshed using the /.auth/refresh endpoint. Just send a GET request to /.auth/refresh with the x-zumo-auth header (present by default when using the mobile client SDK), and the endpoint will respond with a new authentication token for use by your application. Note that the same restrictions regarding refresh tokens still apply.

If you’re building your client using one of the Azure Mobile Client SDK flavors, then you can use the RefreshUser method to refresh both the local authentication token as well as the provider tokens. More documentation on RefreshUser can be found at https://azure.microsoft.com/en-us/blog/mobile-apps-easy-authentication-refresh-token-support/.

Calls with an expired authentication token.

This is allowed in the first 72-hours after expiration and simplifies token management by not requiring you to track expirations yourself. If the authentication token is not refreshed within the 72-hour window, a fresh re-auth by the end-user will be required to get a new, non-expired authentication token.

 

Again, if you are looking for in-depth info on the token store and usages, check out Chris’s post on the topic: App Service Token Store