Skip to main content

OAuth providers

An OAuth provider is the thing that tells Reboot who a user is. You pass one (or one per environment) to OAuth(provider=...); Reboot's own OAuth server does everything else.

All of these live in reboot.aio.auth.oauth_providers.

ProviderUse it when
Development()Local development. Shows a fake account picker; no registration anywhere.
Anonymous()You want no sign-in at all. Every visitor is a new person.
Google(...)Users sign in with Google.
GitHub(...)Users sign in with GitHub.
Auth0(...)You want several sign-in methods, or user management, behind one provider.
Ory(...)You want several sign-in methods, or user management, behind one provider, on Ory Network or self-hosted Ory.
Pick before you have production users

Whichever you pick issues the IDs that become your User state IDs. Each provider issues IDs in its own space, with no mapping between them, so switching providers once you have real users strands every user-keyed piece of state you have. If you expect to need several sign-in methods, or user management beyond a bare ID, start with a broker like Auth0 or Ory: they let you add and change upstream login methods without changing the IDs your application sees.

Development

from reboot.aio.auth.oauth_providers import Development

Development(
# Identity claims to deliver on each sign-in (optional). See
# the claims below for what it can fabricate.
claims=["email", "name"],
)

Shows a fake "pick an account" page with a handful of identities. No passwords, no registration, nothing to configure.

Picking the same identity twice signs you in as the same user, so you can exercise returning users, multi-user behavior, and two clients signed in as the same person, all locally.

The user IDs it issues are opaque, so do not hardcode one into authorization logic; read the signed-in user's ID at runtime instead, as described in Using the signed-in user.

Development only

Development authenticates nobody. Never use it as the prod arm of your selector.

Setup

None.

Claims

ClaimWhat it holds
emailA made-up address for the identity.
email_verifiedAlways true.
nameThe identity's display name.

Anonymous

from reboot.aio.auth.oauth_providers import Anonymous

Anonymous()

No sign-in page at all: every visitor becomes a fresh user. Useful for a demo or a kiosk-style app where per-session state is all you need. A returning visitor is a brand-new user, with a brand-new, empty User, so nothing can outlive a session.

Setup

None.

Claims

None.

Google

from reboot.aio.auth.oauth_providers import Google

Google(
# From the Google Cloud console. Deliver both as secrets.
client_id=os.environ.get("GOOGLE_OAUTH_CLIENT_ID"),
client_secret=os.environ.get("GOOGLE_OAUTH_CLIENT_SECRET"),
# Identity claims to deliver on each sign-in (optional). See the
# claims below.
claims=["email", "name"],
# Extra OAuth scopes, so your app can call Google's APIs on the
# user's behalf, and whether to keep Google's tokens for that
# (both optional). See Call external APIs as the user.
scopes=["https://www.googleapis.com/auth/calendar.events"],
store_tokens=True,
)

Setup

In the Google Cloud console, create an OAuth 2.0 Client ID of type "Web application" and add <your-backend-url>/__/oauth/callback to its authorized redirect URIs. Deliver the client ID and secret as secrets.

Claims

ClaimWhat it holds
emailThe account's email address.
email_verifiedWhether Google has verified that address.
nameFull name.
given_nameFirst name.
family_nameLast name.
pictureURL of the profile picture.
localeThe account's locale, e.g. en.
profileURL of the profile page.

GitHub

from reboot.aio.auth.oauth_providers import GitHub

GitHub(
# From the app's page in GitHub's developer settings. Deliver both
# as secrets.
client_id=os.environ.get("GITHUB_OAUTH_CLIENT_ID"),
client_secret=os.environ.get("GITHUB_OAUTH_CLIENT_SECRET"),
# Identity claims to deliver on each sign-in (optional). See the
# claims below.
claims=["email"],
# Extra OAuth scopes, so your app can call GitHub's API on the
# user's behalf, and whether to keep GitHub's tokens for that
# (both optional). See Call external APIs as the user.
scopes=["repo"],
store_tokens=True,
)

Setup

Register an OAuth App (or a GitHub App) in GitHub's developer settings and set its authorization callback URL to <your-backend-url>/__/oauth/callback. Deliver the client ID and secret as secrets.

Claims

ClaimWhat it holds
emailThe account's primary email address, once GitHub has verified it.
email_verifiedtrue whenever email is delivered.

Auth0

from reboot.aio.auth.oauth_providers import Auth0

Auth0(
# Your Auth0 tenant, e.g. "your-tenant.us.auth0.com".
domain=os.environ.get("AUTH0_DOMAIN"),
# From the application's settings in the Auth0 dashboard. Deliver
# both as secrets.
client_id=os.environ.get("AUTH0_CLIENT_ID"),
client_secret=os.environ.get("AUTH0_CLIENT_SECRET"),
# Identity claims to deliver on each sign-in (optional). See the
# claims below.
claims=["email", "name"],
# Extra OAuth scopes, so your app can call Auth0's APIs on the
# user's behalf, and whether to keep Auth0's tokens for that
# (both optional). See Call external APIs as the user.
scopes=[],
store_tokens=False,
)

One Auth0 application lets people sign in through any connection you enable in the Auth0 dashboard — Google, GitHub, username and password, enterprise SSO — and your application sees one provider.

Setup

Register a "Regular Web Application" in Auth0 and add <your-backend-url>/__/oauth/callback to its allowed callback URLs. Deliver the client ID and secret as secrets.

Claims

Which of these are populated depends on the connection the person signed in through.

ClaimWhat it holds
emailThe user's email address.
email_verifiedWhether the connection has verified that address.
nameFull name.
given_nameFirst name.
family_nameLast name.
middle_nameMiddle name.
nicknameNickname.
pictureURL of the profile picture.
updated_atWhen the profile was last updated.

Ory

from reboot.aio.auth.oauth_providers import Ory

Ory(
# Your Ory project, e.g. "your-slug.projects.oryapis.com".
domain=os.environ.get("ORY_DOMAIN"),
# From the OAuth2 client you created in the project. Deliver both
# as secrets.
client_id=os.environ.get("ORY_CLIENT_ID"),
client_secret=os.environ.get("ORY_CLIENT_SECRET"),
# Identity claims to deliver on each sign-in (optional). See the
# claims below.
claims=["email", "name"],
# Shared secret for an Ory Action that tells Reboot when a user
# edits their profile (optional; requires `claims`). See Keeping
# claims fresh with Ory.
webhook_secret=os.environ.get("ORY_WEBHOOK_SECRET"),
# Where the browser is sent for the authorization request when it
# reaches Ory at a different origin than your server does
# (optional). In local development, typically an `ory tunnel`.
browser_facing_url="http://localhost:4000",
# Extra OAuth scopes, so your app can call Ory's APIs on the
# user's behalf, and whether to keep Ory's tokens for that (both
# optional). See Call external APIs as the user.
scopes=[],
store_tokens=False,
)

Works with an Ory Network project or a self-hosted Ory deployment. Like Auth0, it lets people sign in through whichever methods the project enables, and your application sees one provider.

Setup

Create an OAuth2 client in the Ory project with the authorization-code grant, add <your-backend-url>/__/oauth/callback to its redirect URIs, and make sure it is allowed to request the scopes your claims need. Deliver the client ID and secret as secrets. To keep claims current between sign-ins, also configure the Ory Action described in Keeping claims fresh with Ory.

Claims

Which of these are populated depends on the project's identity schema.

ClaimWhat it holds
emailThe identity's email address.
email_verifiedWhether Ory has verified that address.
nameFull name.
given_nameFirst name.
family_nameLast name.
usernameThe username.
websiteURL of the identity's website.
updated_atWhen the identity was last updated.

Writing your own provider

If none of the above fits — your users live in a self-hosted Keycloak, an internal SSO, or an identity provider no broker covers — subclass RegisteredOAuthProvider and pass an instance in the same dev= / prod= arms. You implement two methods; Reboot's OAuth server does the rest, including state verification, PKCE, and minting your application's own tokens:

  • authorization_url(state, redirect_uri) — build the identity provider's authorize URL, passing state and redirect_uri through verbatim.
  • exchange_code(code, redirect_uri) — exchange the code at the identity provider's token endpoint and return an ExchangeResult carrying the user's ID (and, optionally, their tokens and claims).

You can also override validate() to fail fast on missing configuration, and mount_routes() to add provider-specific HTTP routes.

important

The user ID you return must be stable: the same person must get the same ID on every sign-in. An account ID qualifies; an email address does not, because people change theirs. That ID becomes the state ID of their User, so the namespace-permanence warning applies to your provider too.