Authentication
Flows
Single Sign-On

Single Sign-on authentication

Keel provides an abstraction over the complex OAuth gymnastics which you would normally need to build into your application. This is especially useful if you want to support multiple different authentication providers (such as Google, Facebook, GitLab, etc.). What this means is that all you need to do is provide some simple configuration in your keelconfig.yaml file and integrate with a singular auth endpoint. Keel handles the rest.

These are the general steps:

  1. Configure the 3rd party provider's client ID into the keelconfig.yaml - see here.
  2. Set the 3rd party provider's client secret - see here.
  3. Configure a redirectUrl in the keelconfig.yaml or use a dynamic redirect URI.
  4. Point the browser to the relevant provider login; /auth/authorize/{name}. This will redirect the user to the provider's login page. Once the user has successfully authenticated, the provider will redirect the user back to the configured redirect URL.
    {name} here is the name of the provider as configured in your keelconfig.yaml file. More on this in the getting started section.
  5. Handle the redirect after the completed authentication flow. To handle this, you will need to:
    1. Parse the query string and extract the value of the code parameter.
    2. Give the authorization code to our /auth/token endpoint to authenticate the provider with Keel. This will return a Keel access token and refresh token. See here.
  6. Use the access and refresh tokens to query your Keel API

Let's break these down in more detail.

Setting the callbackUrl with the Provider

Configure the callbackUrl below to the client's allowed redirect URLs. This can be found at GET /auth/providers:

[
  {
    "name": "Auth0",
    "type": "oidc",
    "authorizeUrl": "http://localhost:8000/auth/authorize/auth0",
    "callbackUrl": "http://localhost:8000/auth/callback/auth0"
  }
]

Setting the Client Secret

The Single Sign-On flow requires a client secret, which is obtained from the auth provider's console, typically when creating the client. This secret must be set as a secret in your environment.

  • For local CLI use, keel secrets set MY_SECRET 'my-value' is used to set a secret
  • For hosted environments, use the environment variables page in the Console

The name of the secret has the format AUTH_PROVIDER_SECRET_{name} where {name} is the uppercased name of the provider as configured in your keelconfig.yaml file.

We cover this in much more detail in the broader getting started section as it covers both flows.

Setting the redirectUrl in keelconfig.yaml

Configure a redirectUrl in the keelconfig.yaml with the URL you want authentication to redirect to after it has completed:

auth:
  redirectUrl: http://localhost:8000/callback
  providers:
    - type: google
      name: google_client
      clientId: 1234

After the user has successfully authenticated with the provider, they will be redirected to the redirectUrl with a code query parameter. This authorization code is used to get a Keel access token.

Dynamic Redirect URIs

The redirectUrl in keelconfig.yaml is optional. If omitted, clients can provide their own redirect_uri as a query parameter on the authorize request:

GET /auth/authorize/google?redirect_uri=http://localhost:3000/callback

When a redirect_uri is provided in the authorize request, the same value must also be sent in the token exchange (per RFC 6749):

curl --request POST \
  --url 'http://localhost:8000/auth/token' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data grant_type=authorization_code \
  --data code={{auth_code}} \
  --data redirect_uri=http://localhost:3000/callback

This is useful when multiple clients each have their own callback URL, such as MCP clients or development tools.

⚠️

When redirectUrl is configured in keelconfig.yaml, it always takes precedence over any client-provided redirect_uri. Dynamic redirect URIs only work when redirectUrl is not set.

Getting Access Tokens

After logging in on the external provider, being redirecting to your redirectUrl, having extracting the code URL query parameter, you must then trade that authorization code for a Keel access token.

Note that the authorization code has a very short expiry and must be used immediately after retrieved.

You can trade the authorization code for a set of Keel tokens by calling the /auth/token endpoint with the authorization_code grant like so:

curl --request POST \
  --url 'http://localhost:8000/auth/token' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data grant_type=authorization_code \
  --data code={{auth_code}}

The expected Content-Type of the /auth/token endpoint is application/x-www-form-urlencoded because this is enforced by the OAuth standard, however we also support application/json for convenience. After making this request, if you are successfully authenticated, the token endpoint will respond with HTTP 200 and the following application/json response body.

HTTP 200
{
  "access_token": "{{keel_access_token}}",
  "token_type": "Bearer",
  "expires_in": 86400, // one day
  "refresh_token": "{{keel_refresh_token}}",
  "identity_created": false
}

You can read more about the tokens here.

PKCE

Keel supports Proof Key for Code Exchange (PKCE) (opens in a new tab), which prevents authorization code interception attacks. PKCE is recommended for all OAuth clients and is required by the MCP authentication spec.

PKCE adds a verification step to the authorization code flow. The client generates a random code_verifier and derives a code_challenge from it using SHA-256. The challenge is sent with the authorize request, and the verifier is sent later during the token exchange to prove the same client is completing the flow.

Step 1 — Authorize request. Include the code_challenge and code_challenge_method as query parameters:

GET /auth/authorize/google?code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256&redirect_uri=http://localhost:3000/callback

Step 2 — Handle the redirect. After the user authenticates, Keel redirects to your redirect URL with an authorization code — the same as the standard flow.

Step 3 — Token exchange. Include the original code_verifier when exchanging the authorization code for tokens:

curl --request POST \
  --url 'http://localhost:8000/auth/token' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data grant_type=authorization_code \
  --data code={{auth_code}} \
  --data code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

Keel hashes the verifier and compares it to the stored challenge. If they don't match, the token exchange is rejected. Both S256 (recommended) and plain challenge methods are supported. If code_challenge_method is omitted, it defaults to plain.

State Parameter

The authorize endpoint accepts a state parameter for CSRF protection. This is an opaque value that Keel echoes back in the redirect to your callback URL:

GET /auth/authorize/google?state=my-csrf-token&redirect_uri=http://localhost:3000/callback

After authentication, the redirect includes the state:

HTTP/1.1 302 Found
Location: http://localhost:3000/callback?code=AUTH_CODE&state=my-csrf-token

Your client should verify that the returned state matches the value it originally sent to prevent cross-site request forgery attacks.

Other Considerations

Make sure to enable the Authorization Code Grant flow on the auth provider's console, if necessary. Auth0 requires this to be explicitly enabled.

Perform authenticated requests to your Keel APIs

After authenticating, proceed to use the access token you have received to perform authenticated requests to your Keel APIs. This is done by including the access token (prefixed with Bearer) in the Authorization header of the request.

curl --request POST \
  --url 'http://localhost:8000/api/json/searchAuthors' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ...' \
  --data '{ "where": { "name": { "startsWith": "Bob" } } }'