OAuth 2.0 in 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-starter-kits/tree/main/starter-kits/javascript/auth

Use this starter

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

$ fastly compute init --from=starter-kit/javascript/auth

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 installed the starter kit, 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 installed 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. Run fastly compute publish and follow the interactive configuration prompts to set up a new Fastly Compute service. You'll be prompted for your configuration secrets and configuration data along the way.
  3. 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: [my-oauth-app]
✓ 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 oauth_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

Configuration secrets live in a Fastly Secret Store named oauth_secrets, with the following keys:

  • 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.

fastly compute publish creates the store and prompts you for each of these values, as declared under [setup.secret_stores] in fastly.toml.

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

For local development, the same three values are read from files in the root of your project, as declared under [local_server.secret_stores] in fastly.toml: .secret.client_id, .secret.client_secret, and .secret.nonce_secret. These files are gitignored, and excluded from the published package by .fastlyignore.

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 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 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. In the root of your Fastly project, paste the Client ID into .secret.client_id and the Client secret into .secret.client_secret. Type a long, non-guessable random string of your choice into .secret.nonce_secret.
    dd if=/dev/random bs=32 count=1 | base64 > .secret.nonce_secret
  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.

The local server reads your secrets from the .secret.* files described under configuration secrets, so create those before starting it.

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.