Quick Start: Sign in with Google or Microsoft
A platform superadmin can put Continue with Google and Continue with Microsoft buttons on the login and register pages. They work for anyone, before any organization is known: a new user gets an account without typing a password, and an existing user signs in with the provider account they linked.
Everything is off by default. A deployment that never configures a provider shows exactly the login page it always has.
Turning it on
Section titled “Turning it on”Dashboard: Platform Admin → Settings → Sign-in Providers. The page has a tab for each part:
- General holds the master switch and the account policy: whether a sign-in may create an account, and whether it may link to an existing account by email.
- Google and Microsoft each hold that provider’s own switch, client ID and client secret. Each also shows the exact redirect URI to register with the provider, built from the Public API URL, with a copy button, and a Try it button.
Each tab label shows what that provider will be once you save. It follows your edits as you make them:
| Label | Meaning |
|---|---|
| Live | Its button is on the login page |
| Ready | Fully configured, but hidden while the master switch is off |
| Incomplete | Switched on, but its client ID or secret is missing, so no button is shown |
| Off | Switched off |
Edits on every tab go out together in the one Save settings. Switching tabs doesn’t drop an edit, and a tab with unsaved edits is marked with a dot. Until you save, the label describes the form, not what’s live.
Each setting’s switch means “override the default”. Turning it on for a yes/no setting also picks the non-default value, so switching on Offer Google sign-in selects Enabled.
Or use the API, with any superadmin credential:
curl -X PATCH http://localhost:8000/admin/settings \ -H "X-API-Key: change-me-to-a-strong-secret" \ -H "Content-Type: application/json" \ -d '{ "social_login_enabled": true, "social_login_google_enabled": true, "social_login_google_client_id": "1234567890-abc.apps.googleusercontent.com", "social_login_google_client_secret": "GOCSPX-..." }'A provider’s button appears once all three hold: the master switch social_login_enabled is
on, that provider’s own *_enabled is on, and both its client ID and client secret are set.
Turning the master switch off hides every button and refuses every provider sign-in, but keeps the
client IDs and secrets stored, so turning it back on needs nothing re-entered.
The client secrets are write-only: GET /admin/settings never returns them, only
secrets_set.social_login_google_client_secret: true. Like every field on the Settings page, none
of this can be set from the config file or an environment variable — see
Configuration Reference.
Every setting takes effect on the very next request. There’s no restart.
Checking a configuration with Try it
Section titled “Checking a configuration with Try it”Try it on a provider’s tab runs a real sign-in against the saved settings: the same redirect, token exchange and ID-token checks a user’s sign-in goes through. You sign in at the provider with any account. Nothing is created or linked, and your own session is left alone. You come back to the same tab with the result.
It works before the provider, or the master switch, is turned on, so you can prove a configuration before anyone sees the button. It needs a saved client ID and secret, and it’s disabled while the tab has unsaved edits.
| Result | Usual cause |
|---|---|
| Sign-in works | Everything agrees. The result also says if the button isn’t live yet, or if the email’s domain belongs to an organization’s SSO connection |
token_exchange_failed with invalid_client | Wrong client ID or client secret. For Microsoft, pasting the secret’s ID instead of its value, or an expired secret |
email_unverified (Microsoft) | The app registration lacks the optional ID-token claim xms_edov |
email_missing (Microsoft) | The app registration lacks the optional ID-token claim email |
id_token_invalid (Microsoft) | The account you used isn’t admitted by Accounts admitted |
discovery_failed | For Microsoft, Accounts admitted isn’t common, organizations, consumers or a real tenant ID |
provider_error | The provider refused the request. Its own error is shown alongside |
A redirect URI that isn’t registered exactly is reported by the provider itself, as
redirect_uri_mismatch on its own page, because it won’t send the browser back to an unregistered
address.
Registering the Google client
Section titled “Registering the Google client”-
In Google Cloud, open APIs & Services → Credentials → Create credentials → OAuth client ID, with application type Web application.
-
Under Authorized redirect URIs, add exactly:
{Public API URL}/auth/oauth/google/callbackwhere
{Public API URL}is theserver.public_base_urlsetting, the API’s own public address, not the dashboard’s. The provider redirects the browser back to the API. -
The OAuth consent screen needs the
openid,emailandprofilescopes only. -
Copy the client ID and client secret into the settings above.
Registering the Microsoft app
Section titled “Registering the Microsoft app”-
In Microsoft Entra, open App registrations → New registration. Choose the supported account types to match
social_login_microsoft_tenantbelow: any organizational directory and personal Microsoft accounts forcommon. -
Add a Web redirect URI, exactly:
{Public API URL}/auth/oauth/microsoft/callback -
Under Token configuration → Add optional claim → ID, add
emailandxms_edov. -
Under Certificates & secrets, create a client secret. Copy its value (not its ID) and the app’s Application (client) ID into
social_login_microsoft_client_secret/social_login_microsoft_client_id.
social_login_microsoft_tenant decides whose accounts are admitted:
| Value | Admits |
|---|---|
common (default) | Work or school accounts from any tenant, and personal Microsoft accounts |
organizations | Work or school accounts from any tenant |
consumers | Personal Microsoft accounts only |
| a tenant ID (GUID) | Users of that one tenant only |
What happens when someone clicks the button
Section titled “What happens when someone clicks the button”The browser goes to the provider, and the provider sends it back to
GET /auth/oauth/{provider}/callback, which resolves the account in this order:
- Is the email’s domain claimed by an organization’s SSO connection? Then the browser is sent into that org’s SSO sign-in instead. See SSO takes precedence.
- Is this provider account already linked to an OpenTremor account? Then that account is
signed in. Accounts are matched on the provider’s own stable ID for the person (Google’s
sub; Microsoft’s tenant ID + object ID), never on the email, so a provider-side email change doesn’t detach anyone. - Does an account already exist with this email? By default the sign-in is refused, and the
user is told to sign in with their password and link the provider from their Account page. With
social_login_allow_auto_linkon, the provider is attached to that account automatically. - No account at all? One is created, without an organization, and the user continues on the
onboarding page, where
registration.allow_public_org_creationstill decides whether they can create an org. Turnsocial_login_allow_signupoff to stop new accounts being created this way; existing accounts and invitation links keep working.
A deactivated account is refused, the same as a password sign-in. An email the provider didn’t
verify is refused too: Google’s email_verified, Microsoft’s xms_edov.
Invitation links work with the buttons. Opening an invite link and choosing Continue with Google carries the invitation through the round trip, so the account lands in the inviting org at the invitation’s role. An invitation addressed to a specific email is only accepted if the provider account has that email.
An account with its own two-factor authentication still needs it. If a user turned on TOTP for their account, signing in with a provider takes them to the same code prompt a password sign-in would. A compromised Google account is not a way around a factor they chose.
SSO takes precedence
Section titled “SSO takes precedence”If an organization’s enabled SSO connection claims an email domain (allowed_domains), a provider
sign-in with an address at that domain is always sent to that org’s SSO connection. This holds even
for an account that used the provider button before the org connected SSO.
This rule is what stops the button being a way around an org’s identity provider. Without it,
[email protected] could skip Acme’s Entra tenant — its conditional-access policies, its offboarding,
its default_role — by choosing Continue with Google on a Google account using the same address.
For the same reason, linking a provider account at an SSO-claimed domain is refused.
Linking and unlinking from the Account page
Section titled “Linking and unlinking from the Account page”A signed-in user can link a provider from Account → Sign-in providers → Link Google. They sign in at the provider, and that provider account is attached to their OpenTremor account, even if its email is different, since they’ve just proved they control both. Then they can sign in either way.
Unlink removes it. Removing the account’s only way to sign in is refused: no password, no org SSO connection, and no other linked provider.
An account created through a provider has no password. Its Account page doesn’t offer password or two-factor settings, because the provider owns both.
Organizations that require two-factor authentication
Section titled “Organizations that require two-factor authentication”A session that signed in through a provider, or through an org’s SSO connection, satisfies an organization’s require 2FA policy. The provider owns the second factor, and TOTP enrollment is only available for password accounts, so demanding it would lock these users out with nothing they could do. The same user signing in with their password still needs TOTP.
Whether a Google or Microsoft account actually uses MFA is that provider’s policy, not OpenTremor’s. An organization that needs to enforce it should connect its own SSO, where its identity provider’s conditional-access rules apply.
Error messages
Section titled “Error messages”A failed sign-in lands back on the login page (or the Account page, for a link) with a message.
The oauth_error query parameter carries its key:
oauth_error | Meaning |
|---|---|
account_exists | An account with this email exists and auto-linking is off — sign in with the password, then link |
signup_disabled | No matching account, and social_login_allow_signup is off |
email_unverified | The provider didn’t verify the email (for Microsoft, usually a missing xms_edov optional claim) |
email_missing | The provider shared no email address |
identity_in_use | That provider account is already linked to a different OpenTremor account |
provider_already_linked | This account already has a different account from that provider linked |
domain_managed_by_sso | Link refused: the email’s domain belongs to an org’s SSO connection |
deactivated | The account is deactivated |
provider_disabled | The provider was switched off mid-sign-in |
cancelled | The user backed out at the provider |
expired | The sign-in took longer than 10 minutes, or cookies are blocked |
rate_limited | Too many accounts created from one network |
failed | Anything else — the API log has the cause (most often a redirect URI mismatch or a wrong client secret) |
See API Endpoints — Social login for the endpoint reference.