OAuth Sign-In
Let editors sign in to the dashboard with Google or GitHub on your self-hosted instance.
InlineCMS dashboard sign-in is email + password out of the box. You can optionally add Continue with Google and Continue with GitHub buttons to the login page by registering an OAuth app with each provider and setting a few environment variables.
SSO (SAML/OIDC single sign-on) is a separate, InlineCMS Cloud-only feature. This page covers Google and GitHub OAuth, which run in the self-hosted build.
How it behaves
Section titled “How it behaves”OAuth sign-in is intentionally conservative on a self-hosted instance:
- A provider button appears only when both its client id and secret are set. Leave them unset and the login page stays a clean email + password form.
- Sign-in links to an existing account by verified email — it never creates a new account. The person must already have been invited (i.e. have a project membership). See Users & Access.
- The first OAuth sign-in for an existing account links the identity; later sign-ins match by the provider’s stable user id.
- If no account matches the provider’s verified email, sign-in is refused with “No InlineCMS account is linked to this email. Ask an admin to invite you.”
Prerequisites
Section titled “Prerequisites”Set PUBLIC_URL to the base URL of your install as the browser sees it. It is
required for OAuth because the redirect URI you register with the provider
must match it exactly.
# Production (API serves the dashboard at the same origin)PUBLIC_URL=https://cms.example.com
# Local development (the dashboard runs on the Vite dev server)PUBLIC_URL=http://localhost:3002Each provider’s redirect/callback URL is:
<PUBLIC_URL>/v1/auth/oauth/google/callback<PUBLIC_URL>/v1/auth/oauth/github/callback-
Open the Google Cloud Console and select (or create) a project.
-
Go to APIs & Services → OAuth consent screen and configure it (External is fine). You don’t need to add scopes manually — InlineCMS requests
openid email profileat sign-in. -
Go to APIs & Services → Credentials → Create credentials → OAuth client ID.
-
Choose Web application. Under Authorized redirect URIs, add:
https://cms.example.com/v1/auth/oauth/google/callbackFor local testing also add
http://localhost:3002/v1/auth/oauth/google/callback. -
Copy the Client ID and Client secret into your environment:
Terminal window GOOGLE_OAUTH_CLIENT_ID=xxxxxxxx.apps.googleusercontent.comGOOGLE_OAUTH_CLIENT_SECRET=xxxxxxxx
GitHub
Section titled “GitHub”-
Open Settings → Developer settings → OAuth Apps → New OAuth App (or use an organization’s settings).
-
Set Homepage URL to your
PUBLIC_URL. -
Set Authorization callback URL to:
https://cms.example.com/v1/auth/oauth/github/callback -
Create the app, generate a client secret, and copy both values:
Terminal window GITHUB_OAUTH_CLIENT_ID=Iv1.xxxxxxxxGITHUB_OAUTH_CLIENT_SECRET=xxxxxxxx
InlineCMS requests the read:user user:email scopes so it can read the user’s
verified primary email.
Verify
Section titled “Verify”Restart the API so it picks up the new variables. Open the dashboard login page — a Continue with Google / Continue with GitHub button now sits above the email field. Sign in with an account whose verified email matches an existing InlineCMS user.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Cause / fix |
|---|---|
| Button doesn’t appear | Both the id and secret must be set for that provider. Restart the API after changing env vars. |
redirect_uri_mismatch (Google) | The callback URL registered with the provider must match <PUBLIC_URL>/v1/auth/oauth/<provider>/callback exactly, including scheme and port. |
| ”No InlineCMS account is linked to this email” | OAuth never creates accounts. Invite the person first (or create the account during setup), then have them sign in. |
| Redirected back but not signed in (dev) | PUBLIC_URL must be the dashboard origin (http://localhost:3002), not the API’s, so the flow lands back on the SPA. |
| ”Your provider account has no verified email address” | The provider returned no verified email. Verify the email with the provider, then retry. |