OAuth2 integrations made super simple

Ever wondered of all technical considerations regarding OAuth2? Where do you store access tokens and refresh tokens safely? How do you declare a redirect uri? Do you need state, nonce or PKCE? Or all of them? Sitevision makes this really simple. We'll handle the details and you just focus on creating awesome apps.

OAuth2 is a really simple way of requesting resources from protected API:s. At least when you already have an access token. The process of getting hold of a token might be somewhat cumbersome. As of Sitevision 7 this process will be much simpler. As a matter of fact you will not even see the access token used.

The key concept is simple. Add your configuration and start requesting resources immediately. Simple as that.

OAuth2 roles

OAuth 2 defines four roles.

  • Resource Owner - Someone capable of granting access to a protected resource. This might be a user or a registered application.
  • Resource Server - The server hosting the protected resources. Validates requests by checking Access Tokens before responding to requests.
  • Client - An application requesting resources on behalf of someone else.
  • Authorization Server -The server issuing access tokens to the client after successfully authenticating the resource owner and obtaining authorization

Example: A user (resource owner) visits a web page in Sitevision. On the page there's a webapp (client) listing documents from Microsoft SharePoint (resource server). Before the webapp may list any documents, the user is redirected to Microsoft Azure (authorization server) where the user is authenticated and authorize permissions for the client.

OAuth2 flow in Sitevision

The solution consists of several separate parts. The client configuration plays a central part in the flow.

As an App developer you may use Requester to perform requests as a user or an application. User operations follow the Code Authorization grant and application operations follow the Client Credentials grant.

Client Configuration

The core of the Sitevision OAuth2 flow is the OAuth2 client configuration. To be able to perform any requests the Client must be registered as an OAuth2 App in the Authorization Server.

Have the customer fill out the settings in a new OAuth2 Client Configuration in the web sites settings in Sitevision.

General

  • Name - A friendly name to be used in the Sitevision GUI.
  • Identifier - This will be part of the URL used by the Authorization server when posting back to Sitevision.
  • Description - A text more thoroughly describing what the configuration is used for.

The value used as Identifier here should be registered in the OAuth2 App registration in the Authorization Server. The format of the redirect URI is http(s)://<domain>/oauth2-client/<Identifier>/login

Client ID

  • Client ID - The client id from the OAuth2 App registration
  • Client secret - The client secret from the OAuth2 App registration

Authentication provider

  • Some Authorization Servers are predefined. If yours isn't listed, use the generic setting and provide values to the necessary fields

Scopes

  • Default scopes - These scopes will always be included when requesting an access token as a user.
  • Application scopes - The scopes to use when requesting resources as an application

You probably don't want to change the identifier once the configuration is in use. If changed, working integrations might break.

Help your customers out with the registration process. It's not easy to do everything right when registering an OAuth2 App for the first time. A well written step-by-step guide is almost essential if you expect the customer to perform the registration

OAuth2 configuration selector

Programmatic access to a Client Configuration is provided via the OAuth2 Configuration selector. Add the selector to the apps configuration and use appData to get ahold of the configuration

Requester

With a Client Configuration available it's easy to start performing requests. Require the Requester utility and perform requests as usual.

Performing requests as an application

Below is a simple example of how to perform requests to a protected resource as an application and as a user.. No need to fiddle with tokens - Sitevision's got you covered! Handle failures gracefully and you're good to go.

// Server-side app code (index.js, hooks, or server module)
const appData = require('appData');
const oauth2Config = appData.get('oauth2-config');
const requester = require('Requester');

// Request protected resource as an application. Handle response as usual
requester.get('https://resourceserver.com/resource', { oauth2: oauth2Config, oauth2Type: 'app' })
  .done(function(result) { ... })
  .fail(function(message, status) { ... };

// Request protected resource as a user. Handle response as usual
requester.get('https://resourceserver.com/resource', { oauth2: oauth2Config})
  .done(function(result) { ... })
  .fail(function(message, status) { ... };

Failure handling

Every single request may fail which means your app need to be resilient to failures. This is extra important when doing OAuth2 requests. The token used behind the scenes might expire at any time which must be handled. Sitevision does its best to refresh tokens before sending the requests but there is always a possibility that the token is too old.

Different resource servers responds in different formats but there are a few common cases to handle.

  • No access token - The user must be redirected to obtain an access token
  • Insufficient scope - The user must be redirected to obtain the required scope
  • User denied the authorize request - Inform the user why the app needs access to the users resources
  • Expired access token and possibly refresh token (Not frequent) - The user must be redirected to obtain a new access token

Example of handling insufficient scope:

const oauth2 = require('oauth2');
const appData = require('appData');
const oauth2Config = appData.get('oauth2-config');
const requester = require('Requester');
const options = {
  oauth2: oauth2Config
};

// Request protected resource as a user
requester.get('https://resourceserver.com/resource', options)
  .done(function(result) {
    // Do awesome stuff!
  })
  .fail(function(message, status) {
    // Different error format for different providers. 
    // Find out if scopes are unsufficient
    const sufficient = isSufficient(status);
    if (!sufficient) {
      const redirectUrl = ...;
      const loginLink = oauth2.createLoginLink(oauth2Config, redirectUrl, neededScopes);
      // Redirect user or render the link
    }
  });

OAuth2 requireable util

The OAuth2 requireable util helps out with the operations needed when performing requests as a user.

If you want to limit failures for "No access token", you may use a pre page render hook to check the status of the access token before page rendering.

To limit failures for "Insufficient scope" you may inspect the scopes of the current access token as well.

// hooks.js
(function() {
  'use strict';

  const { beforeRender } = require('hooks');
  const neededScopes = ['profile', 'email'];

  beforeRender((req, res) => {
    const appData = require('appData');
    const oauth2 = require('oauth2');
    const url = require('url');
    
    const oAuth2Config = appData.getNode('oauth2-config');
    const currentStatus = oauth2.getAccessTokenStatus(oAuth2Config);
    const isValid = currentStatus.isValid;
    const scopes = currentStatus.scopes;

    // Redirect if token is not valid
    // Optional: Inspect scopes and redirect if scopes is insufficient
    if (!isValid) { 
      const currentUrl = url.get(req.path);
      const redirectUrl = oauth2.createLoginLink(oAuth2Config, currentUrl,
        neededScopes);
      res.redirect(redirectUrl);
      return;
    }
  });
}());

It might not always be the best user experience to redirect during pre page render. If your app isn't the main content on the page it might even annoy the user

Be careful when comparing scopes. The Authorization Server might rewrite the scope names or not provide them at all. Be careful with simple String equality checks. Know the system you're integrating to.

Do you want to subscribe to News from Sitevision Developer team? Subscribe here!