How to build Single Sign On using OAuth2.0 and OpenID Connect

Christopher Knight
Xero Developer
Published in
6 min readDec 14, 2020

--

This is a continuation from our article on What travel visas teach us about software authentication and will focus on the code required to implement SSO for an API that uses the OAuth2.0 (OA2) & OpenID Connect (OIDC) specifications.

This pair is now the gold standard for businesses who want to offer secure APIs and Single Sign On functionality seen clearly from this list of the world’s largest software platforms and their migration status toward each specification.

This tutorial will explain in detail how to work with OAuth2.0 & OpenID Connect to implement SSO in a traditional web application authorization flow. The full code for this tutorial can be found on Github.

github.com/XeroAPI/xero-node-sso-app

Key Terminology

OAuth2.0 (OA2) — The industry-standard protocol for software authorization of web, desktop, mobile, and other devices

OpenID Connect (OIDC) — OpenID Connect is an identity layer that works with OAuth2.0 used for facilitating software authentication

scopes — A mechanism in OAuth 2.0 to limit an application’s access to a user’s account

token_set — This article will use this term to describe the set of tokens received during the authorization flow

  • access_token — A stateless JSON Web Token (JWT) that enables scalable authorization with verifiable encoded data in the string itself
  • refresh_token — Refresh tokens are string credentials used to obtain new access tokens
  • id_token — When you include the openid scope the spec will return a JWT security token that contains verifiable claims about the end-user

This tutorial uses Xero as the identity provider — but the code & logic are transferable to any provider that uses OA2 and OIDC for access to their API’s.

The Node.js app in the tutorial implements Single Sign up and Sign On with Xero and extends Xero’s small business accounting platform by pulling invoice data for easy search ability in a table view.

We are able to verify and create a user account using their id_token & pull their Xero Invoice data using their access_token.

Full code for the tutorial can be found in the xero-sso repo and if you create a free Xero demo account you demo the app.

We can on-board new SSO users to our app in 3 steps

Step 1

Send user to the authorization url with a well maintained OAuth2.0 library.

We are using the xero-node SDK. which once configured has a helper function to create the authorization url.

Configure with our XeroAPI application credentials and scopes:

const xero = new XeroClient({
clientId: 'CLIENT_ID',
clientSecret: 'CLIENT_SECRET',
redirectUris: [`https://<identity_domain>.com/<CALLBACK_PATH>`],
scopes: ["offline_access", "openid", "profile", "email", "accounting.transactions"]
});
let consentUrl = await xero.buildConsentUrl();

The final authorization url should look like the following:

https://<identity_domain>.com/<authorize_route>?client_id=<CLIENT_ID>&scope=offline_access openid profile email accounting.transactions&response_type=code&redirect_uri=https://<identity_domain>.com/<CALLBACK_PATH>

Xero only supports the `openid profile email` OIDC scopes, but the spec does support others. Make sure you validate with the API provider to see what OIDC scopes they have implemented in the spec.

In addition, the offline_access scope tells the API return the refresh_token which are used to refresh access_tokens prior to each usage.

Xero’s access_tokens are valid for 30 minutes though durations and refresh_tokens may slightly vary in other OA2 implementations.

Step 2

In the redirect route of the authorization flow we need to securely exchange the temporary code for a valid token_set.

It is highly recommended you leverage an existing open source OpenID Connect certified implementation. This ensures you handle all the pertinent cryptographic security checks that make OIDC + OA2 such a secure authorization protocol pairing.

The callbackURI must also match with what the app was configured with in the provider’s system. This prevents anyone from spoofing your authorize URL by redirecting the user to a malicious callback that had not been whitelisted.

In our node/express app we setup a route called /callback, and within that thread we exchange the temporary code for a valid token_set. This process is also referred to as 3-legged OAuth.

const requestUrl = req.url=>/callback?code=5c8926be00a152961xxxf0810329c3ec85d911252xxx5a7255b0582492xxx1f5&scope=openid%20profile%20email%20accounting.transactions.read%20accounting.settings.read&session_state=W2PT2k8w6mlq3e3t8.14b5d3d4401a5const tokenSet = await xero.apiCallback(requestUrl);

Under the hood the xero-node function apiCallback uses a certified OIDC library called openid-client which handles the temporary code exchange for a token_set and validates both JWT’s came from the expected source.

The most important piece of step 2 is to cryptographically validate both the access_token and id_token.

Unless you are a security professional please use a certified open source library to validate your id_token JWT. Here is a great post that describes what certified libraries do to cryptographically prove a token is from a provider.

Step 3

Once validated you can decode the base64 encoded id_token using a trusted JWT decoding library. That data can then be user to create a new user account, or log users into an existing account.

In the following example we use the id_token email identifier to lookup that user in our database. If it matches, we update the user details with the info coming from the identity provider as their phone number, first name, or even address may have changed since last login.

After that we can assign the user a signed cookie using a SESSION_SECRET which maintains a secure logged in state for the next hour.

For each subsequent load we validate the user has a signed cookie that matches the most recent login from the SSO provider.

Open standards such as OAuth2.0 and OpenID Connect enable small teams to offer great software authentication and authorization experiences by offloading much of the complexity of user management systems to much more resourced businesses such as Facebook, Google, Amazon or Xero.

By integrating with an SSO provider our application can now benefit from existing security measures the provider has already built such as fraud detection and multi factor authentication, in addition to the trust built off brand recognition that millions of users around the world already trust.

Now that the user has authenticated themselves to our application with the previously described scopes, we have both their id_token (which contains data needed to provision a new account), as well as an access_token (which can be used for the authorization of the provider’s API).

We make a call to the /invoices endpoint and bam!

They land as a new user in our application stocked with their critical businesses invoice data!

For the full code samples in this article you can reference the xero-sso sample app code which shows a working demo and logic of how to use OAuth 2.0 and OpenID Connect to implement Single Sign On for your own application.

Drop me a line on twitter if this helped you or leave a comment below!

--

--

Developer Evangelist @XeroAPI — helping devs to integrate with our API’s to build ecosystem businesses.