OAuth 2.0 implementation for JavaScript

Connect to an identity provider such as Google using OAuth 2.0 and validate authentication status at the Edge, to authorize access to your edge or origin hosted applications.

Platform:
Fastly Compute
Language:
JavaScript
Repo:
https://github.com/fastly/compute-js-auth

Use this starter

Using the Fastly CLI, create a new project using this starter somewhere on your computer:

$ fastly compute init --from=https://github.com/fastly/compute-js-auth

Or click the button below to create a GitHub repository, provision a Fastly service, and set up continuous deployment:

Deploy to Fastly

Authentication at the network's edge, using OAuth 2.0, OpenID Connect, and Fastly Compute

This is a self-contained JavaScript implementation for the OAuth 2.0 Authorization Code flow with Proof Key for Code Exchange (PKCE), deployed to Fastly Compute.

It includes JSON Web Token (JWT) verification, and access token introspection.

A simplified flow diagram of authentication using Compute

Scroll down to view the flow in more detail.

Getting started

After you have checked out the code from this repository, you'll need to do some configuration before you can deploy it, so that Fastly knows which identity provider to use and how to authenticate.

Make sure you have installend and configured the Fastly CLI first.

Quick start

  1. Obtain a client ID and optional client secret from your chosen OAuth 2.0 Identity Provider (IdP).
  2. Create an .env file and set the CLIENT_ID, CLIENT_SECRET, and a random NONCE_SECRET environment variables.
  3. Run fastly compute publish and follow the interactive configuration prompts to set up a new Fastly Compute service.
  4. Add https://{your-fastly-compute-domain}/callback to the list of allowed callback URLs in your IdP's app configuration.

Configuration

The first time you run fastly compute publish, respond with y to the prompt to create a new service.

Accepting the default values for all other prompts will set up Google as your OAuth 2.0 Identity Provider (IdP), to let you get started as quickly as possible. You may choose to provide your own configuration settings instead.

Create new service: [y/N] y
Service name: [compute-js-auth]
✓ Creating service
Domain: [vaguely-pretty-ray.edgecompute.app]
Configure a backend called 'origin'
...

Backends

You will be prompted to set up two backends:

  • idp: Your authorization server;
  • origin: Your application or content server.

Configuration data

Configuration data lives in Fastly Config Store named compute_js_auth_config, with the following keys:

  • openid_configuration: The OpenID Configuration (OIDC) metadata from your authorization server, JSON-serialized;
  • jwks: JWKS metadata from your authorization server (obtained from the jwks_uri property of the OIDC metadata), JSON-serialized.

💡 After you've obtained each of the JSON metadata above from your authorization server, you'll have to stringify it before using as an input for the Fastly CLI. Check out this jq playground snippet for a quick way to accomplish this.

Configuration secrets

Option A: Using environment variables

Create an .env file (example contents here) and set the following environment variables:

  • CLIENT_ID: The OAuth 2.0 client ID (determined by the Identity Provider (IdP)).
  • CLIENT_SECRET: The OAuth 2.0 client secret (if required by the IdP).
  • NONCE_SECRET: A secret to verify the OpenID nonce used to mitigate replay attacks. It must be sufficiently random to not be guessable.

💡 Run dd if=/dev/random bs=32 count=1 | base64 to generate a random, non-guessable secret.

Option B: Using a Fastly Secret Store (beta)

Store configuration secrets in a Fastly Secret Store named compute_js_auth_secrets, with the keys client_id, client_secret, and nonce_secret respectively.

You must set the USE_SECRET_STORE constant to true in src/config.js

⚠️ For this to work, Secret Stores must be enabled on your Fastly account. Secret Stores is a paid feature in Fastly Compute. Contact Fastly Support to opt in to the beta.

💡 To simplify local development and initial deployment, you may add the [local_server.secret_stores] and [setup.secret_stores] sections in your fastly.toml file. Check out fastly.secretstore.example.toml.

Using an OAuth 2.0 Identity Provider with Fastly Compute

1. Set up an Identity Provider (IdP)

You might operate your own identity service, but any OAuth 2.0, OpenID Connect (OIDC) conformant identity provider will work. You will need the following from your IdP:

  • A Client ID, and optionally, a Client secret ➡️ Set the CLIENT_ID and CLIENT_SECRET environment variables, or set the client_id and client_secret keys in the Secret Store.
  • An OpenID Connect Discovery document ➡️ Set the openid_configuration key (JSON-serialized string value) in the Config Store.
  • A JSON Web key set ➡️ Set the jwks key (JSON-serialized string value) in the Config Store.
  • The hostname of the IdP's authorization server ➡️ Create as a backend called idp on your Fastly service

2. Deploy the Fastly service and get a domain

To build and deploy your Fastly Compute service, run:

fastly compute publish

You'll be prompted to enter a series of configuration settings, explained above. When the deployment is finished you'll be given a Fastly-assigned domain such as random-funky-words.edgecompute.app.

Remember to add https://{your-fastly-compute-domain}/callback (e.g., https://{random-funky-words}.edgecompute.app/callback) to the list of allowed callback URLs in your IdP's OAuth app configuration.

This allows the authorization server to send the user back to the Compute@Edge service.

Example

As an example, if you are using Google as your IdP, follow these steps:

  1. In the Google API Console, use the Credentials API to create a new OAuth client ID. Choose Web application as your application type, give your app a name, and finally make note of the following two outputs:
    • The Client ID (eg. RANDOM_LONG_ID.apps.googleusercontent.com) is shown next to your application name.
    • The Client SECRET (eg. RANDOM_LONG_SECRET) is shown next to your application name.
  2. Create an .env (example) in your Fastly project and paste in the CLIENT_ID and CLIENT_SECRET obtained before. Set a random NONCE_SECRET, a long, non-guessable random string of your choice. Save the file.
  3. After you've configured and deployed your new Fastly Compute service, find your new OAuth client ID in the Google API Console, and add https://{random-funky-words}.edgecompute.app/callback to the list of Authorized redirect URIs

    💡 Optionally, also add http://127.0.0.1:7676/callback as an authorized redirect URI for local development.

Try it out!

Follow the steps above and visit your Fastly-assigned domain. You should be prompted to follow a login flow with your IdP, and then after successfully authenticating, will see content delivered from your own origin.


The flow in detail

Here is how the authentication process works:

Edge authentication flow diagram

  1. The user makes a request for a protected resource, but they have no session cookie.
  2. At the edge, this service generates:
    • A unique and non-guessable state parameter, which encodes what the user was trying to do (e.g., load /articles/kittens).
    • A cryptographically random string called a code_verifier.
    • A code_challenge, derived from the code_verifier.
    • A time-limited token, authenticated using the nonce_secret, that encodes the state and a nonce (a unique value used to mitigate replay attacks).
  3. The state and code_verifier are stored in session cookies.
  4. The service builds an authorization URL and redirects the user to the authorization server operated by the IdP.
  5. The user completes login formalities with the IdP directly.
  6. The IdP will include an authorization_code and a state (which should match the time-limited token we created earlier) in a post-login callback to the edge.
  7. The edge service authenticates the state token returned by the IdP, and verifies that the state cookie matches its subject claim.
  8. Then, it connects directly to the IdP and exchanges the authorization_code (which is good for only one use) and code_verifier for security tokens:
    • An access_token – a key that represents the authorization to perform specific operations on behalf of the user)
    • An id_token, which contains the user's profile information.
  9. The end-user is redirected to the original request URL (/articles/kittens), along with their security tokens stored in cookies.
  10. When the user makes the redirected request (or subsequent requests accompanied by security tokens), the edge verifies the integrity, validity and claims for both tokens. If the tokens are still good, it proxies the request to your origin.

Local development

Run fastly compute serve --watch (or npm run dev) to spin up a local development server and watch source files for changes.

Issues

If you encounter any bugs or unexpected behavior, please file an issue.

Next steps

This page is part of a series in the Authentication use case.

Starters are a good way to bootstrap a project. For more specific use cases, and answers to common problems, try our library of code examples.