Authentication at Fastly's edge, using OAuth 2.0, OpenID Connect, and Compute@Edge
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@Edge.
It includes JSON Web Token (JWT) verification, and access token introspection.
Scroll down to view the flow in more detail.
Read the blog post to learn why this is a good idea. For Compute@Edge starter kits, visit the Fastly Developer Hub.
Setting up edge authentication
Get an identity provider (IdP)
💡 You might operate your own identity service, but any OAuth 2.0, OpenID Connect (OIDC) conformant provider will do.
Register your application with the IdP. Make a note of the client_id
and the address of the authorization server.
Save a local copy of the OpenID Connect discovery document associated with the server. You’ll find this at /.well-known/openid-configuration
on the authorization server’s domain. For example, here's the one provided by Google.
Save a local copy of the JSON Web Key Set (JWKS) metadata. You’ll find this under the jwks_uri
property in the discovery document you just downloaded.
Create the Compute@Edge service
💡 You will need to have a Fastly account that is enabled for Compute@Edge services. Follow the Compute@Edge welcome guide to install the
fastly
CLI and the Rust toolchain onto your local machine.
After cloning this repository, follow the steps below – or use the interactive set-up script provided, by running ./setup.sh
1. Initialize the Compute@Edge service
fastly compute init
When prompted for language, choose Rust.
When prompted to create a backend, accept the default originless option.
2. Add some OAuth / OIDC configuration details
- Open
src/config.toml
, and:- Paste in the
client_id
- Add a
nonce_secret
that is sufficiently random to not be guessable
- Paste in the
- Create a new directory,
./src/well-known
, and copy the OpenID Connect and JWKS metadata files you saved earlier to./src/well-known/openid-configuration.json
and./src/well-known/jwks.json
, respectively
3. Build and deploy
fastly compute build
fastly compute deploy
Note the hostname of the deployed Compute@Edge service (e.g., {some-funky-words}.edgecompute.app
)
4. Create backends
Clone the service version you just deployed, e.g., by running:
fastly service-version clone --service-id=YOUR_FASTLY_SERVICE_ID --version=1
Add the authorization server backend to your Fastly service, and name it idp
:
fastly backend create --name=idp \
--service-id=YOUR_FASTLY_SERVICE_ID --version=2 \
--address=AUTH_SERVER_HOST --override-host=... \
--port=443 --ssl-sni-hostname=... --ssl-cert-hostname=... --use-ssl --ssl-check-cert
Add your origin backend, and name it backend
:
fastly backend create --name=backend ...
# See the previous step.
5. Rebuild and deploy the service
fastly compute build
fastly compute deploy
Link the Identity Provider (IdP)
Add https://{some-funky-words}.edgecompute.app/callback
to the list of allowed callback URLs in your IdP’s app configuration. This allows the authorization server to send the user back to the Compute@Edge service.
The flow in detail
- The user makes a request for a protected resource, but they have no session cookie.
- 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 thecode_verifier
. - A time-limited token, authenticated using the
nonce_secret
, that encodes thestate
and anonce
(a unique value used to mitigate replay attacks).
- A unique and non-guessable
- The
state
andcode_verifier
are stored in session cookies. - The service builds an authorization URL and redirects the user to the authorization server operated by the IdP.
- The user completes login formalities with the IdP directly.
- The IdP will include an
authorization_code
and astate
(which should match the time-limited token we created earlier) in a post-login callback to the edge. - The edge service authenticates the
state
token returned by the IdP, and verifies that the state cookie matches its subject claim. - Then, it connects directly to the IdP and exchanges the
authorization_code
(which is good for only one use) andcode_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.
- An
- The end-user is redirected to the original request URL (
/articles/kittens
), along with their security tokens stored in cookies. - 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.
Issues
If you encounter any non-security-related bug or unexpected behavior, please file an issue using the bug report template.
Security issues
Please see our SECURITY.md for guidance on reporting security-related issues.