Sign in with a Workspace account¶
Google is a standards-compliant OpenID Connect provider, and signing in to Mewbo with a Google Workspace account takes a short configuration block. Group-driven authorization is the part that needs a decision.
Google's OIDC ID token carries no groups claim at all
This is not a scope you forgot to request. Google's OpenID Connect implementation does not emit group membership in the ID token, and no combination of scopes will make it appear. Mapping Google Groups to Mewbo roles needs one of the alternatives below.
Read the authorization options before you commit to a design.
What this unlocks¶
- Single sign on for the Mewbo console and REST API with Google Workspace or Cloud Identity accounts.
- Google's own security controls, two-step verification, context-aware access and session length, apply to Mewbo without Mewbo implementing any of them.
- Authorization by email address, email domain, SAML group attributes, or explicit role assignment, depending on which option below you choose.
The login flow¶
sequenceDiagram
autonumber
participant B as Browser
participant M as Mewbo API
participant G as Google
B->>M: GET /api/auth/login
M-->>B: 302 to accounts.google.com + signed state cookie
B->>G: Authorization request
G->>G: Google sign-in, two-step verification, consent
G-->>B: 302 back with ?code=...&state=...
B->>M: GET /api/auth/callback?code&state
M->>G: Exchange code for tokens (back channel)
G-->>M: ID token, with no groups claim
M->>M: Verify, map claims, provision, resolve roles
M-->>B: 302 to return_to + session cookie
Configure Google¶
In the Google Cloud console, under APIs and Services, create an OAuth 2.0 Client ID of type Web application.
| Google setting | Value |
|---|---|
| Application type | Web application |
| Authorised redirect URI | https://console.example.com/api/auth/callback |
| Authorised JavaScript origin | https://console.example.com |
Set the OAuth consent screen to Internal. Only accounts in your Workspace tenant can then complete the flow, which is an authorization boundary in its own right and almost always what an enterprise deployment wants.
Copy the client ID and client secret.
Configure Mewbo¶
{
"api": {
"auth": {
"enabled": true,
"authenticators": [
{
"name": "google",
"kind": "oidc",
"issuer": "https://accounts.google.com",
"discovery_url": "https://accounts.google.com/.well-known/openid-configuration",
"client_id": "1234567890-abcdefg.apps.googleusercontent.com",
"client_secret": "the-client-secret",
"scopes": ["openid", "email", "profile"]
}
],
"session": { "secret": "generate-a-long-random-string" },
"role_mappings": { "default_role": "viewer" }
}
}
}
Field notes, verified against authenticators.py.
issuerishttps://accounts.google.comwith no trailing slash. It must match theissclaim exactly.identity_claimdefaults tosub, a stable opaque numeric string on Google that survives an email change. Prefer it over email as the join key.email_claimandemail_verified_claimdefault toemailandemail_verified. Google populates both.email_verifiedis read only when the provider sends a real boolean. Anything else leaves it unknown rather than assuming false.picture_claimdefaults topicture, which Google populates with the profile photo URL.- There is deliberately no
groups_claimabove. Setting one yields nothing and every user still lands ondefault_role.
The oidc extra is required. Run pip install mewbo-iam[oidc].
Getting groups into Mewbo¶
Four options, best first.
Option 1: assign roles by email or domain rule¶
The simplest approach, and often sufficient. Mapping rules match group names and Google supplies none, so pin the small set of privileged users with the bootstrap allowlist and leave everyone else on the default role.
"role_mappings": { "default_role": "member" },
"bootstrap": {
"admin_subjects": ["100000000000000000001", "100000000000000000002"]
}
admin_subjects matches the sub claim exactly, which for Google is the numeric account id rather than the email address. Find it by signing in once and reading the subject field from GET /api/auth/me.
Combine this with an Internal consent screen and the result is direct. Anyone in your Workspace tenant signs in as a member, and a named list of people are admins.
On the Google OIDC path, admin_subjects is not a bootstrap. It is the permanent list
Roles are recomputed from the group mapping at every login, so a hand-granted role does not survive the next one. See Your identity provider is authoritative.
Google supplies no groups, so that mapping always resolves to default_role. Keep every privileged user in admin_subjects, and treat the list as your real source of truth. If that is untenable, use one of the three options below, all of which supply real groups.
Option 2: use SAML instead of OIDC¶
Google's SAML implementation can send group membership, which OIDC cannot. In the Google Admin console, configure Mewbo as a custom SAML app and add a Group membership attribute mapping, selecting which groups to include and the attribute name to send them as.
Mewbo's SAML limitations apply here unchanged, and one of them changes what your users do. Sign in is service-provider initiated only, so the app tile in the Google apps launcher will not sign anyone in. Point it at https://console.example.com/api/auth/saml/login instead. Leave assertion encryption off, since Mewbo holds no service-provider private key. The Entra guide's SAML prerequisites cover the rest, including request signing and Single Logout, and its reverse-proxy alternative if any of them block you.
{
"name": "google-saml",
"kind": "saml",
"issuer": "https://accounts.google.com/o/saml2?idpid=C01abcdef",
"sp_entity_id": "https://console.example.com",
"idp_metadata_url": "https://accounts.google.com/o/saml2/idp?idpid=C01abcdef",
"subject_attribute": "NameID",
"email_attribute": "email",
"name_attribute": "displayName",
"groups_attribute": "groups"
}
groups_attribute must match the attribute name you configured in the Google Admin console. The metadata source rule and the two URLs to register are in Any other SAML provider.
| Google SAML setting | Value |
|---|---|
| ACS URL | https://console.example.com/api/auth/saml/acs |
| Entity ID | https://console.example.com |
The saml extra is required. Run pip install mewbo-iam[saml].
Option 3: query the Directory API yourself¶
Google's Cloud Identity and Admin SDK Directory API can list a user's groups, but Mewbo does not call it. There is no Google specific directory driver and no configuration field that would enable one, so do not go looking for a google_directory authenticator kind.
The integration point sits outside Mewbo. Have an external process read group membership from the Directory API and assign Mewbo roles through the IAM admin API, or provision users over SCIM.
Option 4: put an identity broker in front¶
If you already run Keycloak, Authentik or Authelia, broker Google through it. The broker handles Google sign in, you manage groups in the broker, and Mewbo sees a normal OIDC provider emitting a proper groups claim. For an organisation that wants Google as the credential source and real group-driven authorization, this is usually the least total work.
See the Keycloak, Authentik or Authelia guides, and configure Google as an upstream identity provider inside them.
Verify it works¶
- Sign in through the console, then call
GET /api/auth/me. Expectauthenticated: true, your numeric Googlesubas the subject,email_verified: true, apicture_urlunderavatar, and anauth_methodreportingkind: "oidc"with issuerhttps://accounts.google.com. - On the OIDC path, expect
rolesto contain exactly yourdefault_roleunless you used the bootstrap allowlist. That is correct behaviour, not a misconfiguration. - On the SAML path, confirm
rolesreflects your group attribute mapping. If it does not, the attribute name in the config and in the Google Admin console disagree.
Failure modes¶
These are Google specific. Boot failures and generic callback errors are in the shared Troubleshooting table.
| Symptom | Cause | Fix |
|---|---|---|
Everyone lands on default_role, and groups_claim is set |
Google's ID token has no groups claim, and never will | Use one of the four options above. This is not fixable by configuration |
redirect_uri_mismatch from Google |
The registered redirect URI does not match what Mewbo sent | Register <origin>/api/auth/callback exactly, including scheme and any port |
The URI Google rejects reads http:// when you serve https |
The reverse proxy is not forwarding X-Forwarded-Proto |
Forward X-Forwarded-Proto and X-Forwarded-Host |
| Users outside your organisation can sign in | The OAuth consent screen is set to External | Set it to Internal, which restricts it to your Workspace tenant |
?auth_error=provider_error |
Google returned an error to the callback, typically a denied consent | Retry, and check the consent screen configuration |
For the concepts behind this page, including roles, the permission catalogue, how a request resolves to a principal, and what is and is not enforced, see Authentication and Access. This guide connects one provider. It deliberately does not restate the model.