For AI agents: the complete documentation index is at llms.txt. Markdown versions are available by appending .md or sending Accept: text/markdown.
Reflex Logo
Docs Logo
Enterprise

/

Auth

/

Deployment

New in reflex-enterprise v0.9.1.

Deploying to Production

The quickstart works on localhost out of the box, but moving the same app to a real deployment against a real identity provider (IdP) has three requirements: serve the app over HTTPS, register the exact callback URL with the IdP, and report the public origin correctly behind reverse proxies.

HTTPS is required

All four auth cookies (access token, ID token, refresh token, and granted scopes) are issued Secure; SameSite=Strict; HttpOnly. These attributes are fixed and not configurable. Because browsers drop Secure cookies sent over plain HTTP, the app must be served to the browser over HTTPS in any non-localhost deployment. Local reflex run works without TLS only because browsers exempt localhost from the Secure rule.

Behind a TLS-terminating reverse proxy, terminate TLS at the proxy and ensure the browser-facing origin is https. Browsers enforce Secure based on the origin visible to the browser.

Registering the callback URL

The OAuth redirect URI is built at runtime from the browser-visible page URL, with the path replaced by the plugin's auth_callback_endpoint (/callback by default). It is not a config value: its scheme, host, and port follow the request origin. This is the concrete version of step 3 in the overview.

Register the full callback URL, including scheme, host, port, and path, as an allowed redirect URI in your IdP's client settings, and register every origin you actually use:

A redirect URI that does not match a registered value produces the IdP's most common error, redirect_uri_mismatch.

Behind a reverse proxy / at scale

Two properties of the auth model determine how it behaves behind a proxy or across multiple replicas.

The public origin must be correct. Both the redirect URI and the post-login index URI are derived from the browser-visible request origin. A reverse proxy must forward the real public scheme and host. If the proxy reports http or an internal hostname, the runtime redirect URI won't match what's registered at the IdP. The backend (api_url) must also be reachable from the browser: after login the client makes a credentialed request to /_reflex/cookies/sync to persist the auth cookies.

No sticky sessions are needed. Auth secrets live in client-side HTTP cookies. A LocalStorage flag signals other tabs to re-pull the cookies. There is no server-side session store, so multiple backend replicas can run behind a load balancer without sticky-session configuration. Give every replica the same OIDC client configuration (the same OIDC_* / {PROVIDER}_* environment variables).

Connecting a real identity provider

Every provider is discovered from its issuer's .well-known/openid-configuration, always runs the Authorization Code flow with PKCE (S256), and requests openid email profile by default. Because client_secret is optional, each IdP client can be either public (PKCE only, no secret) or confidential (PKCE plus a secret). The mechanics are the same for every IdP; only the issuer URL changes.

A worked example with Google:

  1. In the Google Cloud console, create an OAuth 2.0 Client ID of type Web application.
  2. Add your callback URLs (see registering the callback URL) as Authorized redirect URIs, e.g. https://your-app.com/callback.
  3. Configure the app. Because Google issues a client secret, run the client as confidential by setting all three variables (omit OIDC_CLIENT_SECRET to run PKCE-public instead):
  1. To receive group claims for authorization checks, add the relevant scope via extra_scopes (see providers).

Other IdPs follow the same pattern with their own issuer URL:

IdPOIDC_ISSUER_URI form
Googlehttps://accounts.google.com
Azure ADhttps://login.microsoftonline.com/<tenant>/v2.0
Auth0https://<tenant>.auth0.com
Oktahttps://<org>.okta.com

Troubleshooting

SymptomCauseFix
redirect_uri_mismatch (from the IdP)The redirect URI is derived from the request scheme + host + auth_callback_endpoint; the value registered at the IdP does not match it.Register the exact callback URL; behind a proxy, make sure the app sees the public scheme and host.
invalid_client (from the IdP at token exchange)The IdP client is confidential, but OIDC_CLIENT_SECRET is unset. It defaults to empty, and no local startup error is raised.Set the client secret, or switch the IdP client to public / PKCE.
Logged in but bounced back to /login (login loop)Secure; SameSite=Strict cookies are dropped over plain HTTP on a non-localhost host.Serve the app over HTTPS (localhost is exempt).
ConfigError at startupEither a plain rx.App() was used with the plugin, or two or more providers both fall back to the shared OIDC_* config for issuer or client id.Use rxe.App(); for multiple providers, set provider-specific {PROVIDER}_* variables (see providers).
Built with Reflex