Skip to content

Commit

Permalink
Update Auth0 guide with JWKS support (#369)
Browse files Browse the repository at this point in the history
  • Loading branch information
gguillemas authored Mar 1, 2024
1 parent 1af2b93 commit 69130e3
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 113 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ sidebar_position: 2

# Integrate Auth0 as an Authentication Provider

# Integrate Auth0 as an Authentication provider
# Integrate Auth0 as an Authentication Provider

This guide will cover using [Auth0](https://auth0.com/) as the authentication provider for single-page web applications using SurrealDB as the only backend. In this guide you will learn how to:

Expand Down Expand Up @@ -43,10 +43,10 @@ You will also need to [create an Auth0 account](https://auth0.com/signup), which

First of all, you will need to complete the regular setup for creating a Single-Page Application and an API resource within Auth0. You can do this by following the official Auth0 [documentation](https://auth0.com/docs/quickstart/spa) for your SPA.

If you are using plain JavaScript, follow [the vanillajs guide](https://auth0.com/docs/quickstart/spa/vanillajs/01-login) to create an application in Auth0 and [the API guide](https://auth0.com/docs/quickstart/spa/vanillajs/02-calling-an-api) to create an API in Auth0.
If you are using plain JavaScript, follow [the vanilla guide](https://auth0.com/docs/quickstart/spa/vanillajs/01-login) to create an application in Auth0 and [the API guide](https://auth0.com/docs/quickstart/spa/vanillajs/02-calling-an-api) to create an API in Auth0.

:::note
<em> Note: </em> You will not need to create an actual backend API (e.g. using backend languages like NodeJS or Go) as the documentation suggests when using SurrealDB. A simple file server (e.g. python3 -m http.server 8080, for local testing or any static web server for production) that can serve the static content of your website will suffice. However, creating an API resource in Auth0 is necessary, as it will generate an “audience” string which will be required for Auth0 to add claims to its access tokens.
<em> Note: </em> You will not need to create an actual backend API (e.g. using backend languages like NodeJS or Go) as the documentation suggests when using SurrealDB. A simple file server (e.g. <code>python3 -m http.server 8080</code>, for local testing or any static web server for production) that can serve the static content of your website will suffice. However, creating an API resource in Auth0 is necessary, as it will generate an “audience” string which will be required for Auth0 to add claims to its access tokens.
:::

At the end of those tutorials, you should have both an application and an API created in your Auth0 account and a simple client-side web application that authenticates with Auth0 using those two resources. This website will capture the access token issued by Auth0, which is the token that we are using with SurrealDB. If you were not able to create a working website, you can also use this [minimal example created by SurrealDB](https://github.com/surrealdb/examples/tree/main/auth0).
Expand Down Expand Up @@ -98,53 +98,13 @@ This action should be saved and added to the “Login” flow in the “Actions

Next, we should configure SurrealDB so that it can verify tokens sent to it through the [HTTP REST API](/docs/surrealdb/integration/http) via the “Authorization” header or through any of the [SDKs](/docs/surrealdb/integration/sdks/Overview) via the “Authenticate” methods.

To do that, we will require the public key of the key pair that Auth0 will use to sign the tokens that it will issue for our application. This key can be [obtained by querying the following endpoint](https://auth0.com/docs/secure/tokens/json-web-tokens/locate-json-web-key-sets):

```surql
https://<YOUR_AUTH0_DOMAIN>/.well-known/jwks.json
```

Where the placeholder text is to be replaced by the domain value defined for your Auth0 application.

This will return a JSON (more specifically [JWKS](https://auth0.com/docs/secure/tokens/json-web-tokens/json-web-key-sets)) file with an array of public keys, the first of which is the public key that will be used to sign all tokens issued by Auth0 for your application. Store the value of the `x5c` attribute for that first key. This is the value of your current public key.

Here is an example JWKS file, indented and with the relevant value highlighted:

```json
{
"keys": [
{
"kty": "RSA",
"use": "sig",
"n": "2nsSvrRnuw6OLJCqltkiRAGV07-35isdPwyTrrWQ3PwxEZc-lDbquQ7Z9Fkx5Y-ldVzBbTHEsbmhDYjBubUlS4dhstvpYD93963Sw6Q6gQjow_T4xWqsaeuj4PpcajPjI_ybbDwLa7bIXEBz7AC3UAgxY0khiERfq2quWIaeK0MLJ7bBcpyGF7hZy1SUehQ187-yBrM9Dsi2qKxQX981JFsctEnJLaabvoWUMQsMucTJXBRp5X_bGJ70XjgB85DNWTVqw7XwEfe_piM5DcvjVcR86bYMw-Qs46a3IzvIDs54X9--frM35IHLNrpwVbfsg4qgmya_GTPF4NSVab0xaQ",
"e": "AQAB",
"kid": "_8kKMct_togebAwqQ8Uos",
"x5t": "ZffK9pHzOtCslIK_800RhfZZ_ks",
"x5c": [
// highlight-next-line
"MIIDBTCCAe2gAwIBAgIJdeyDfUXHLwX+MA0GCSqGSIb3DQEBCwUAMCAxHjAcBgNVBAMTFWdlcmF1c2VyLmV1LmF1dGgwLmNvbTAeFw0yMzEwMzExNzI5MDBaFw0zNzA3MDkxNzI5MDBaMCAxHjAcBgNVBAMTFWdlcmF1c2VyLmV1LmF1dGgwLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANp7Er60Z7sOjiyQqpbZIkQBldO/t+YrHT8Mk661kNz8MRGXPpQ26rkO2fRZMeWPpXVcwW0xxLG5oQ2Iwbm1JUuHYbLb6WA/d/et0sOkOoEI6MP0+MVqrGnro+D6XGoz4yP8m2w8C2u2yFxAc+wAt1AIMWNJIYhEX6tqrliGnitDCye2wXKchhe4WctUlHoUNfO/sgazPQ7ItqisUF/fNSRbHLRJyS2mm76FlDELDLnEyVwUaeV/2xie9F44AfOQzVk1asO18BH3v6YjOQ3L41XEfOm2DMPkLOOmtyM7yA7OeF/fvn6zN+SByza6cFW37IOKoJsmvxkzxeDUlWm9MWkCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUOeOmT9I3/MJ/zI/lS74gPQmAQfEwDgYDVR0PAQH/BAQDAgKEMA0GCSqGSIb3DQEBCwUAA4IBAQBDue8iM90XJcLORvr6e+h15f5tlvVjZ/cAzv09487QSHJtUd6qwTlunEABS5818TgMEMFDRafQ7CDX3KaAAXFpo2bnyWY9c+Ozp0PWtp8ChunOs94ayaG+viO0AiTrIY28cc26ehNBZ/4gC4/1k0IlXEk8rd1e03hQuhNiy7SQaxS2f1xkJfR4vCeF8HTN5omjKvIMcWRqkkwFZm4gdgkMfi2lNsV8V6+HXyTc3XUIdcwOUcC+Ms/m+vKxnyxw0UGh0RliB1qBc0ADg83hOsXEqZjneHh1ZhqqVF4IkKSJTfK5ofcc14GqvpLjjTR3s2eX6zxdujzwf4gnHdxjVvdJ"
],
"alg": "RS256"
},
{
"kty": "RSA",
"use": "sig",
"n": "vtOCOuiM_JI87mQ8E6ICCJLSC5KliR9vQC0s1XJV4A17m-CMmgFAN7u8AabrxId-3zjUZAE-nkpanENM76WIQJUCdt1H1gfC5lY4a49FVXA2q1WZLwDvlgb-ZNYZXi2vaH50uONXeO9XSG9dEnBUVKGVRL34GqB68UGgXrPGLkAcjH-TW0KDXLZ-FKXNhQfESIVGDHRGG0l-LPK_1AegtJjdEUjhA4CQ-1jA3kLVfr2cQc8rRD5b486R5XvC4xBlZNFFP7Fm5if4khhAJC-JnnYWgmytPM4Q7mOWatRr08wQmmfQDDrw53IseNA-yKnwHYlJ6ChU_UtNzS0OipUapQ",
"e": "AQAB",
"kid": "fwrcOmV26mBUkeqbXfL_4",
"x5t": "RhdLvYxnXgM6TYxpzbG-K-RleqQ",
"x5c": [
"MIIDBTCCAe2gAwIBAgIJUzJ062XCgOVQMA0GCSqGSIb3DQEBCwUAMCAxHjAcBgNVBAMTFWdlcmF1c2VyLmV1LmF1dGgwLmNvbTAeFw0yMzEwMzExNzI5MDBaFw0zNzA3MDkxNzI5MDBaMCAxHjAcBgNVBAMTFWdlcmF1c2VyLmV1LmF1dGgwLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL7TgjrojPySPO5kPBOiAgiS0guSpYkfb0AtLNVyVeANe5vgjJoBQDe7vAGm68SHft841GQBPp5KWpxDTO+liECVAnbdR9YHwuZWOGuPRVVwNqtVmS8A75YG/mTWGV4tr2h+dLjjV3jvV0hvXRJwVFShlUS9+BqgevFBoF6zxi5AHIx/k1tCg1y2fhSlzYUHxEiFRgx0RhtJfizyv9QHoLSY3RFI4QOAkPtYwN5C1X69nEHPK0Q+W+POkeV7wuMQZWTRRT+xZuYn+JIYQCQviZ52FoJsrTzOEO5jlmrUa9PMEJpn0Aw68OdyLHjQPsip8B2JSegoVP1LTc0tDoqVGqUCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUYp67WM42b2pqF7ES0LsFvAI/Qy8wDgYDVR0PAQH/BAQDAgKEMA0GCSqGSIb3DQEBCwUAA4IBAQANOhmYz0jxNJG6pZ0klNtH00E6SoEsM/MNYH+atraTVZNeqPLAZH9514gMcqdu7+rBfQ/pRjpQG1YbkdZGQBaq5cZNlE6hNCT4BSgKddBYsN0WbfTGxstDVdoXLySgGCYpyKO6Hek4ULxwAf1LmMyOYpn4JrECy4mYShsCcfe504qfzUTd7pz1VaZ4minclOhz0dZbgYa+slUepe0C2+w+T3US138x0lPB9C266SLDakb6n/JTum+Czn2xlFBf4K4w6eWuSknvTlRrqTGE8RX3vzOiKTM3hpDdjU7Tu7eNsZpLkDR1e+w33m5NMi9iYgJcyTGsIeeHr0xjrRPD9Dwh"
],
"alg": "RS256"
}
]
}
```
To do that, we will leverage the JWKS support in SurrealDB in order to define a token verification mechanism pointing to a JWKS object served by Auth0. This JWKS object can be found in a [dedicated endpoint for your Auth0 domain](https://auth0.com/docs/secure/tokens/json-web-tokens/locate-json-web-key-sets).

Subsequent keys found in the JWKS object are those that Auth0 will use next to sign tokens if you were to [rotate the signing keys](https://auth0.com/docs/get-started/tenant-settings/signing-keys/rotate-signing-keys) from Auth0. **It is important to note that, if you follow this guide, rotating keys in Auth0 will require that you also update the public key defined in SurrealDB.** This will simply require running the `DEFINE TOKEN` query to update the public key value, but it cannot be done unilaterally from Auth0. This will be possible once SurrealDB natively supports JWKS.
Pointing to a JWKS file ensures that token verification will work seamlessly even after [rotating the signing keys](https://auth0.com/docs/get-started/tenant-settings/signing-keys/rotate-signing-keys) and that tokens signed with revoked keys will no longer be accepted by SurrealDB.

Although what is described in this guide is the recommended approach, if you require an alternative to using public key cryptography in this manner, you may also use an HMAC algorithm to sign tokens as explained in the “Alternative: Using HMAC” [Annex](#annex) section below.
:::note
<em> Note: </em> Remote JWKS objects are locally cached by SurrealDB to prevent unnecessary network requests. Due to this, revoked keys may not become untrusted immediately. If you wish to immediately update the cache, you may delete the files under the <code>storage/jwks/</code> and <code>cache/jwks/</code> directories created in the directory from which you run SurrealDB.
:::

The following queries will create the required resources to authenticate a token for a scope:

Expand All @@ -159,12 +119,14 @@ DEFINE SCOPE user;
-- Define the public key to verify tokens issued by Auth0 for our application.
-- The name of the token should match the custom claim that we configured before.
DEFINE TOKEN auth0 ON SCOPE user TYPE RS256 VALUE "-----BEGIN PUBLIC KEY-----
<YOUR_AUTH0_PUBLIC_KEY_VALUE>
-----END PUBLIC KEY-----";
DEFINE TOKEN auth0 ON SCOPE user TYPE JWKS VALUE "https://<YOUR_AUTH0_DOMAIN>/.well-known/jwks.json";
```

In the example above, replace the placeholder with the `x5c` value retrieved from the JWKS object.
In the example above, replace the placeholder with the domain value defined for your Auth0 application.

:::note
<em> Note: </em> In order to allow SurrealDB to establish a connection with Auth0 to download the JWKS object, you will require running it with the network <a href="/docs/security/capabilities">capability</a>. For the strongest security, provide your specific Auth0 domain when starting SurrealDB with <code>--allow-net</code>. For example: <code>--allow-net example.eu.auth0.com</code>.
:::

### Defining authorization criteria in SurrealDB

Expand Down Expand Up @@ -280,13 +242,11 @@ To learn about other potential uses for the SurrealDB token functionality, you c

## Example Single Page Application

You can view and download a minimal example of an SPA using Auth0 and SurrealDB below.

[](https://github.com/surrealdb/examples/tree/main/auth0)
You can view and download a minimal example of an SPA using Auth0 and SurrealDB [here](https://github.com/surrealdb/examples/tree/main/auth0).

## Alternative: Using HMAC

Using public key cryptography algorithms for signing tokens prevents you from having to store any secrets at all in SurrealDB. However, some SurrealDB administrators may prefer to use HMAC algorithms, which use the same secret to both sign and verify the signature of the JWT. This secret will be stored in SurrealDB when provided as value for the `DEFINE TOKEN` statement and its access should be restricted, as it can be used to issue arbitrary tokens which will be trusted by SurrealDB.
Using public key cryptography algorithms for signing tokens prevents you from having to store any secrets at all in SurrealDB. However, some SurrealDB administrators may prefer to use HMAC algorithms, which use the same secret to both sign and verify the signature of the JWT. This secret will be stored in SurrealDB when provided as value for the `DEFINE TOKEN` statement and its access should be restricted, as it can be used to issue arbitrary tokens which will be trusted by SurrealDB. However, **we do not recommend this method** over using public cryptography, as the later significantly reduces the burden of creating strong secrets, keeping them secret and managing their lifecycle.

According to the OAuth 2.0 specification (part of OpenID Connect), only confidential (as opposed to public) applications should be allowed to use HMAC algorithms, as it requires being able to keep the secret secure. For this reason, Auth0 will not allow using HMAC algorithms with applications of the SPA (Single-Page Application) type, as they generally would have to store the secret in the client, which is publicly accessible. However, because of the particular case of SurrealDB, the secret will not need to be exposed to the client and will instead be stored in SurrealDB.

Expand Down
Loading

0 comments on commit 69130e3

Please sign in to comment.