Auth at edge with OAuth 2.0

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:
Rust
Repo:
https://github.com/fastly/compute-rust-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-rust-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 Fastly's edge, using OAuth 2.0, OpenID Connect, and Fastly Compute

This is a self-contained Rust implementation 🦀 for the OAuth 2.0 Authorization Code flow with Proof Key for Code Exchange (PKCE), deployed to 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.

1. Set up an identity provider

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

  • A Client ID
  • For some IdPs, a Client Secret
  • The hostname of the IdP's authorization server
  • An OpenID Connect (OIDC) Discovery document, typically at https://{authorization-server-hostname}/.well-known/openid-configuration
  • A JSON Web key set

Example: Google

This starter kit is pre-configured to work with Google OAuth clients, so if you are using Google, follow these steps:

  1. In the Google API Console, search for "oauth" and navigate to the Credentials page. Select + Create Credentials > OAuth client ID.
    1. Select the Web application type and give your app a name.
    2. Add http://127.0.0.1:7676 and http://127.0.0.1:7676/callback to Authorized JavaScript origins and Authorized redirect URIs, respectively. This is for local testing only; remember to remove these URLs later!
    3. Tap Create.
  2. Store your newly created credentials in new (gitignored) files in the root of your Compute project:
    • Paste the client ID in .secret.client_id
    • Paste the client secret in .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. Fetch Google's OIDC Discovery document from accounts.google.com/.well-known/openid-configuration. Paste the JSON-stringified contents of the file into the openid_configuration property in fastly.toml, under [local_server.config_stores.oauth_config.contents].
    curl -s https://accounts.google.com/.well-known/openid-configuration | jq -c @json
  4. Note the jwks_uri property inside the OIDC Discovery document. Fetch the document at that URL and paste its JSON-stringified contents into the jwks property in fastly.toml, under [local_server.config_stores.oauth_config.contents].
    curl -s https://www.googleapis.com/oauth2/v3/certs | jq -c @json

2. Test your configuration locally

Spin up the local development server for your Compute service:

fastly compute serve

Browse to http://127.0.0.1:7676. If everything is configured correctly, you should be able to complete an end-to-end OAuth 2.0 flow.

3. Deploy the Fastly service and get a domain

Now you can build and deploy your new service:

fastly compute publish

This will run through the setup configuration defined in fastly.toml before building and publishing your Compute service.

You'll be prompted to enter the hostname of your own origin to configure the backend called origin, and also the authorization server of the identity provider (IdP) which will be used to configure a backend called idp.

A secret store called oauth_secrets will automatically be created, and you'll be prompted for your client_id, client_secret and nonce_secret.

A config store called oauth_config will automatically be created, and you'll be prompted to input values for openid_configuration and jwks. You can find these in fastly.toml if you followed the instructions in Step 1.

When the deploy is finished you'll be given a Fastly-assigned domain such as random-funky-words.edgecompute.app.

Add https://{your-fastly-domain}/callback to the list of allowed callback URLs in your IdP's app configuration (for Google, this is Authorized redirect URIs within your application's OAuth 2.0 Client Credentials).

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

5. Try it out!

Now you can visit your Fastly-assigned domain. You should be prompted to follow a login flow with your identity provider, 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.

Configuration

Secrets

The following secrets must be stored in the oauth_secrets secret store associated with the Compute service:

SecretDescription
client_idOAuth 2.0 client identifier valid at the IdP's authorization server.
nonce_secretA secret to verify the OpenID nonce used to mitigate replay attacks. It must be sufficiently random to not be guessable.
client_secret (optional)Optional client secret for certain IdPs' token endpoint. Google, for example, requires a client secret obtained from its API console. WARNING: Including this parameter produces NON-NORMATIVE OAuth 2.0 token requests.

Optional configuration

The following keys may be stored in the oauth_config config store associated with the Compute service:

KeyDescriptionDefault
callback_pathPath for the redirection URI to which OAuth 2.0 responses will be sent./callback
scopeOAuth 2.0 scope list (one or more space-separated scopes).openid
introspect_access_tokenWhether to verify the access token using the OpenID userinfo endpoint. Used to introspect opaque and other types of tokens revocable by the authorization server. If revocation is not a concern – or when IdP rate limits are – set to true to validate JWT access tokens at the edge.false
jwt_access_tokenWhether the access token is a JWT. JWT access tokens may be validated at the edge, using an approach similar to ID tokens. Omitted if introspect_access_token is true.false
code_challenge_methodPKCE code challenge method.S256

Issues

If you encounter any non-security-related bug or unexpected behavior, please file an issue using the bug report template.

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.