# OpenID Connect

OAuth answers *may this application do this*. OpenID Connect adds the missing question — *who is this person* — by returning a signed ID token alongside the access token. Connect signs people in with Google, which is an OpenID Connect provider, and there is no other way in. Identity is where a session starts; it is not where any permission is decided.

- **Status:** Reference
- **Audience:** developer, both
- **Last verified:** 2026-09-10
- **Canonical:** https://connectbyjbrh.com/docs/technology/openid-connect/

## What the extra token contains

An ID token is a signed assertion about the person who just authenticated, in a format the relying application can verify without asking the provider anything further. Its claims are small and specific.

| Claim | Meaning | Why it matters |
|---|---|---|
| `sub` | The provider's stable identifier for this person | The only claim safe to key an account on — it does not change |
| `email`, `email_verified` | The address, and whether the provider vouched for it | Convenient for display, unreliable as a key: addresses get reassigned and changed |
| `iss`, `aud` | Who issued the token and who it was issued for | A token minted for another application is not yours to accept |
| `exp`, `iat` | Expiry and issue time | An assertion about a moment, not a standing fact |
| `nonce` | A value the application put into the request | Ties the token to the sign-in attempt that asked for it |

Every one of those has to be checked. A relying party that reads claims without verifying the signature, the issuer, the audience and the expiry is accepting a document anybody could have written — which is the single most common way an identity integration goes wrong.

## Why the email is not the account

Keying an account on an email address feels natural and fails in three ordinary ways: a person changes their address and loses their history; an organisation reassigns a departed employee's address and the new holder inherits an account; two providers assert the same address and each believes it owns it. `sub` has none of those problems because it means nothing outside the issuer that minted it.

The same reasoning appears elsewhere in Connect for the same reason. A Person is a record; an address on a channel is an Identity that resolves to that Person. One human with a work address, a personal address, a WhatsApp number and a phone number is one relationship, not four, and the address is never the thing being identified.

## Does Connect use OpenID Connect?

**Used, as the only sign-in.** Signing in to Connect means signing in with Google. There is no password login, no magic link and no local account: `password_sign_in` is recorded as not implemented, deliberately. If your organisation cannot use Google identities, Connect has no alternative route to offer, and that is a fact to establish before an evaluation rather than after one.

What the identity does **not** do is grant access to anything. Signing in establishes who you are; the workspace you may act in is resolved separately by `workspace_kernel`, and every request after that is filtered three more times — the `customer_safe` allowlist in the middleware, the SQLAlchemy workspace kernel, and row-level security in PostgreSQL. A valid identity with no workspace is a signed-in person who can see nothing, which is the correct outcome and not a fault.

## Identity, authentication, authorisation

**Identity** — Which person this is. Answered once, by the provider, and carried afterwards by the session.
**Authentication** — Proof that they are that person right now. The provider does it; Connect never sees the password.
**Authorisation** — What they may do here. Decided per request, per workspace, per record — never inferred from being signed in.

Collapsing the third into the first is how systems end up with an administrator who is administrative everywhere. Keeping them separate is why a single Connect deployment can serve the operator's own workspace and every customer workspace over one implementation without either being able to see the other.

## Questions

### Can I use my own identity provider?

Not today. Google is the identity provider Connect signs in with, and nothing on this page should be read as describing a configurable one. It is the right question to ask before adopting, because there is no fallback path.

### Is the ID token used to call the API?

No, and it should never be. An ID token is an assertion about a sign-in, not a credential for an API. A person's browser carries a session; a machine uses an integration key. Sending an identity token as an API bearer is a category error that some services accept and none should.

### What happens if the same person signs in on a second browser?

Both sessions exist. Signing in as somebody else on one browser ends the session it replaced on that browser only — never that person's other devices, because sharing one machine should not sign somebody out of their phone.

## Related

- [OAuth 2.0](https://connectbyjbrh.com/docs/technology/oauth/)
- [Sessions and cookies](https://connectbyjbrh.com/docs/technology/sessions-cookies/)
- [Authorisation models](https://connectbyjbrh.com/docs/technology/authorization-models/)
- [Account and access](https://connectbyjbrh.com/docs/account/)
- [Security and isolation](https://connectbyjbrh.com/docs/security/)
- [Three independent layers of tenant isolation](https://connectbyjbrh.com/research/three-layers-of-isolation/)

## What this page is based on

- Connect source pack (docs-source/sources/GENERAL.md §1, §2, §10) — request flow, three isolation layers, Google-only sign-in
- Connect capability registry (docs-source/facts.py) — `google_sign_in`, `password_sign_in`, `workspace_resolution`, CANONICAL_TERMS
- https://openid.net/specs/openid-connect-core-1_0.html — OpenID Connect Core
