Web development

Ubisecure SSO and Single Page Applications

In this article, I’ll show you how to enable JavaScript single page applications to use OpenID Connect 1.0 for authentication, and then how to access OAuth 2.0 protected APIs. We have made the single page application available on GitHub Pages and the API runs on a free-of-charge tier of Azure.

What are Single Page Applications?

A Single Page Application (SPA) is a web application that loads a single HTML page from the web server and then dynamically updates the page in response to user interaction and other events. Compare this to a traditional web application that typically loads a new HTML page each time the user interacts with the application.

There are several architectures that enable you to build single page apps. In this article I’m focusing on “thin server architecture”, where most logic and state is implemented in the client and the server provides RESTful OAuth 2.0 protected APIs for the client.

Single Page Apps are still relatively rare compared to traditional web apps. The main reason is probably that SPA requires a new set of skills from developers. This article aims to simplify SPAs and shows how to solve login and secure access to APIs.

Mobile Apps

The success of mobile apps is closely related to recent increased interest in single page applications.

The architecture of a typical mobile app is quite similar to thin server architecture of Single Page Apps. A mobile app is the client that implements state and logic, with the server providing OAuth 2.0 protected APIs.

The similarity enables reuse because the same OAuth 2.0 protected APIs could be consumed by both mobile apps and SPAs. Also, the skills required for building mobile apps and single page apps are quite similar.

Architecture

In this figure, the application could be either a Single Page App or a Mobile App.

 

Single Page Application and OpenID Connect

 

The rest of this article will focus on Single Page Apps. A later article will cover the specific differences with mobile apps.

Cross-Origin Resource Sharing

When creating Single Page Applications, it is likely that you will want to separate the hosts for the application and the API endpoints themselves. For example, the application could be served from a CDN, whilst the APIs are delivered by container-hosted microservices spread over dynamically instantiated hosts.

In normal web usage this multi-host or, more precisely, ‘cross-origin’ approach is restricted for security reasons. Cross-Origin Resource Sharing (or CORS) provides a standards-backed approach to solving this need, whilst maintaining security.

Use Authorization Code Flow

Implicit flow of OpenID Connect was originally designed as a simplified flow, optimised for SPAs. It is, however, important to recognise that many browser technologies have improved since Implicit Grant was designed. For example, CORS – which enables ‘token request’ from JavaScript – was not generally available at that time. The optimised Implicit Grant flow is no longer needed and should be avoided because of security risks and other constraints.

Authorisation Code flow should be the flow of choice for interactive user authentication/authorisation.

ID Token Verification

The Web Crypto API is another fairly recent technology in web browsers. Web Crypto API defines the cryptographic operations required to verify the integrity of the JSON Web Tokens – the format used by OpenID Connect ID Token.

Using this API to validate the integrity of the OpenID Connect ID Token improves the security of the application.

Access Token Storage?

Over the years, traditional web application developers have learned to maintain application state between page loads with http cookies and, more recently, with the browser’s session and local storage capabilities. However, both technologies are susceptible to XSS and CSRF attacks, not only because of errors within the application itself but also due to errors in any other application running on the same server.

Is the situation any better with Single Page Apps? Basically, with SPAs you can completely avoid storing credentials – such as access tokens in cookies and session storage. Instead, simply keep the access token in JavaScript variables and consider using encapsulation to hide the access token even further.

Checkout the live demo and source code

We have two applications freely available. SimpleSPA is a Single Page Application and SimpleAPI is the OAuth 2.0 protected API for that application. The source code for these apps has been shared on GitHub.

These apps are live – the single page application is deployed on GitHub Pages and the API runs on a free-of-charge tier of Azure. Both apps can be integrated with Ubisecure SSO – get in touch to talk about your project or arrange a demo.

2 Comments

  1. Steve H

    The problems with using the Authorization grant from client-side code are two fold:
    1. The client secret is no longer a secret, being completely exposed to anyone who examines the code.
    2. Refresh tokens cannot be issued.
    In addition, I cannot see how this achieves better security than Implicit grant, as (for SPA) all traffic proceeds via the browser in both cases. So, exchanging a code for the access token / id token has no more security than getting these directly in a single call (bearing in mind point (1).

    Finally, the Authorization grant as shown here is unsuitable for mobile apps, for the reasons staled above. Instead, use the PKCE grant which is designed for this purpose.

    • Petteri Stenius

      Thank you for your comments. These are the right questions ask.

      For client secret, the right thing to do would be to use public clients where client secret is not used at all. In my case the OpenID Provider I’m integrating with does not support public clients. As a workaround I have setup the client’s registration in same way a public client would be setup, so that disclosure of client secret does not present additional risk.

      This example SPA implementation does not use refresh tokens. The assumption is that the IDP will maintain SSO session and an application like this should initially attempt fetching an access token with a silent logon with the “prompt=none” parameter.

      On the OAuth mailing list there was recently a fairly active discussion about authorization code grant vs implicit grant. The most recent security best practices now advises against using implicit grant. There are a couple of reasons for this: authorization code is one time use and with PKCE the code is sender constrained.

      Also one practical reason why implicit grant is no longer needed is availability of CORS in browsers. CORS enables single page applications like this to invoke the token request of authorization code flow.

      The PKCE protocol is an extension to authorization code grant. This example is doing PKCE with authorization code flow.

      These two very new and not yet completed recommendations from the OAuth working group have more details into the topics of security and single page applications
      https://tools.ietf.org/html/draft-ietf-oauth-security-topics-11
      https://tools.ietf.org/html/draft-ietf-oauth-browser-based-apps-00

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>