Sign in with Google, Microsoft or OIDC
Single sign-on on every install: Google, Microsoft Entra or any OpenID Connect provider, with the settings, who may sign in, and how far each provider is trusted.
People can sign in with an account they already have: Google, Microsoft Entra (work and school accounts), or any OpenID Connect provider such as Keycloak, Authentik, Okta or Auth0. It is free, on every install, and passwords keep working next to it.
A button for each provider you set up appears on the sign-in screen, and nothing else changes. Account says "Signed in with Google" for a session that came from one.
What you need
TRCKABLE_BASE_URLset to the public address of your server, for examplehttps://stats.example.com. The provider sends people back to this exact address, so trckable never builds it from the request. Without it, providers stay off and the log says so.- A client (an "app") registered at the provider, with this as its redirect URI:
https://stats.example.com/api/v1/oidc/<name>/callback<name> is the provider's name in lower case: google, microsoft, or the
name you chose for another provider (keycloak, acme, and so on).
Nothing is offered until first-run setup has created the owner. Until then the setup link is what guards the instance, and a provider is not a second way in.
The settings
Each provider is a group of environment variables that start with
OIDC_<NAME>_, where <NAME> is in capitals.
| Variable | For | |
|---|---|---|
OIDC_<NAME>_CLIENT_ID | all | The client ID from the provider |
OIDC_<NAME>_CLIENT_SECRET | all | Its secret. Can also come from a file: OIDC_<NAME>_CLIENT_SECRET_FILE (see Secrets as files). Never written to the log |
OIDC_<NAME>_ISSUER | other providers | The provider's issuer address, https://. Its /.well-known/openid-configuration must be there. Not for Google or Microsoft |
OIDC_<NAME>_LABEL | optional | What the button says after "Continue with". Google and Microsoft have one; another provider defaults to its name |
OIDC_<NAME>_ALLOWED_DOMAINS | optional | Email domains, comma separated. Used for letting people join (below), and as the list of verified domains for one Microsoft directory |
OIDC_MICROSOFT_TENANT | Microsoft | Your directory (tenant) ID, or organizations / common |
OIDC_MICROSOFT_ALLOWED_TENANTS | Microsoft | The directory IDs that may sign in, comma separated. Required with organizations or common |
OIDC_ALLOW_SIGNUP | all | true lets people from an allowed domain create their own account. Default off |
OIDC_REQUIRE_TOTP | all | Default true. false skips the authenticator code for people who are not owners |
A name with GOOGLE is the Google preset, and MICROSOFT (or ENTRA) is the
Microsoft one. Any other name is a generic OpenID Connect provider. You can set
up several providers side by side. A mistake in these settings stops the server at
start and says which variable it is, rather than starting with a sign-in that
does not work.
- In the Google Cloud console, open APIs & Services → Credentials, create an OAuth client ID of type Web application, and add the callback address above as an authorized redirect URI. (If asked, configure the consent screen first. For a company, choosing Internal keeps it to your Workspace.)
- Set:
TRCKABLE_BASE_URL=https://stats.example.com
OIDC_GOOGLE_CLIENT_ID=1234-abcd.apps.googleusercontent.com
OIDC_GOOGLE_CLIENT_SECRET=GOCSPX-...Microsoft Entra
- In the Microsoft Entra admin center, open App registrations → New registration. For one organisation, choose Accounts in this organizational directory only. Add the callback address as a Web redirect URI.
- Under Certificates & secrets, create a client secret. From the app's overview, copy the Application (client) ID and the Directory (tenant) ID.
- Under Token configuration, choose Add optional claim, token type
ID, and add
emailandxms_edov. Accept the prompt to add the Microsoft Graphemailpermission.xms_edovis how Entra says that the domain of the address has been verified in the directory, and trckable relies on it (see How far each provider is trusted). - Set:
TRCKABLE_BASE_URL=https://stats.example.com
OIDC_MICROSOFT_CLIENT_ID=00000000-0000-0000-0000-000000000000
OIDC_MICROSOFT_CLIENT_SECRET=...
OIDC_MICROSOFT_TENANT=11111111-1111-1111-1111-111111111111To take people from more than one directory, register the app as multi-tenant and name the directories you trust:
OIDC_MICROSOFT_TENANT=organizations
OIDC_MICROSOFT_ALLOWED_TENANTS=11111111-1111-1111-1111-111111111111,22222222-2222-2222-2222-222222222222Personal Microsoft accounts are never accepted, and consumers is not an
option.
Any other OpenID Connect provider
Create a confidential client at the provider with the callback address above and
the scopes openid, email and profile. Then:
TRCKABLE_BASE_URL=https://stats.example.com
OIDC_ACME_ISSUER=https://sso.acme.example/realms/main
OIDC_ACME_CLIENT_ID=trckable
OIDC_ACME_CLIENT_SECRET=...
OIDC_ACME_LABEL="Acme SSO"The issuer must be exactly what the provider's discovery document names as its
issuer, character for character (a trailing slash counts). The provider must send an email
claim and email_verified: true: without the second, nobody can sign in.
The flow is the authorization code flow with PKCE (S256). The ID token is checked
for its signature, issuer, audience and expiry, and for the one-time nonce and
state trckable made for that sign-in. Only a page on your own server is opened
afterwards.
Who can sign in
- Someone who is already on this instance. Add people in Account → People, and they can then sign in with a provider. The email the provider has verified has to be exactly the one on the account. An address the provider has not verified is never matched, and a person whose password an owner set and who has not used it yet loses that password the first time they sign in with a provider.
- Optionally, anyone from your domain. Set
OIDC_<NAME>_ALLOWED_DOMAINStoacme.comandOIDC_ALLOW_SIGNUP=true, and a person with a verified address on that domain gets a viewer account the first time they sign in. Without both, nobody is created. Viewers read your sites and change nothing; an owner can change the role later. A person made this way has no password. - The same person each time. The first finished sign-in records the provider's own ID for the person, together with the provider. If the same email later arrives with another ID, which can happen when an account is deleted and made again at the provider, or when a domain changes hands, the sign-in is refused.
Clearing the link
When someone's account at the provider really was replaced, forget the recorded ID and the next sign-in links again. Either of these does it:
- an owner resets that person's password in Account → People (they choose a new one at their next password sign-in), or
- the person who runs the server runs, on the server itself:
trckabled admin clear-sso person@acme.comTwo-step sign-in
An owner who has two-step sign-in turned on is always asked for the code from
their authenticator app after the provider. For everyone else who has it on, it is
asked too unless you set OIDC_REQUIRE_TOTP=false. People who have not turned
two-step on are not asked. The ID of the person is recorded only once the code is
right, so a wrong code does not claim anyone's link.
A person made by a provider has no password, so they cannot turn two-step on themselves until an owner resets their password for them.
How far each provider is trusted
A provider tells trckable an email address, and trckable lets that person into the account that has it. So the question for each provider is whether it can say that address truthfully. They differ.
Google. Google marks an address verified for any Google account, including
accounts made with a company address that is not on Google at all. So trckable
accepts a Google address only when its domain is gmail.com or googlemail.com,
or when the token's hd claim (the Google Workspace the account belongs to) is
the address's own domain. A person on a Workspace alias domain therefore signs in
with the Workspace's primary domain address. An address on any other domain is
refused, even if Google says it is verified.
Microsoft Entra. The email claim is whatever the directory holds for the
person, and a directory's administrators, or, where sign-up is open, the people
themselves, can set it to an address they do not own. trckable accepts it only
when all of these hold:
- the token's directory (
tid) is one you allow, and its issuer is that directory's own; - the person is not a guest of that directory;
- the domain has been verified in the directory, which Entra states with the
optional claim
xms_edov: true. When that claim is sent asfalse, the sign-in is refused. For a single directory, if the claim is not sent at all, the address is accepted only when its domain is listed inOIDC_MICROSOFT_ALLOWED_DOMAINS. Withorganizationsorcommon, the claim is required: a list of domains cannot say which of several directories may hold an address on one of them.
Other providers. trckable takes the provider's email_verified: true as it
is. Set up only a provider that you trust to hand out the addresses of your
people, and that does not let anyone register an address they do not control.
Domains
OIDC_<NAME>_ALLOWED_DOMAINS matches exactly what follows the @: acme.com
does not include mail.acme.com. List only domains whose addresses are all
yours. A domain shared by unrelated people, such as a free mail provider or a
parent domain that many companies have subdomains of, would let every one of them
create an account.
When a sign-in is refused
The sign-in screen says why in a few words: it failed, it was cancelled, the
account has no verified email, there is no account here for that email, or there
were too many tries. The details are in the server's log, with a person's user ID
and never their address (a refusal logs the email's domain only). Every sign-in
is logged as signed in with google, for example, and the session remembers the
provider.
Too many failed tries from one address are held back for a few minutes. Signing in correctly never counts against that limit.
Configuration
Every setting is an environment variable, and none of them is required. trckable starts with sensible defaults and generates its own secrets.
Backups and restore
Encrypted once a day, seven deep on the machine, thirty days in a bucket of your choice, and the restore is tested rather than assumed.