OIDC sign-in¶
Use this guide to configure human sign-in, distribute a public provider profile and verify group-based access on 0.11. The identity reference lists every setting and limit. Jobs and services use workload identity.
Register the provider client¶
The provider owner supplies an HTTPS issuer, client ID, discovery document and asymmetric signing keys. Register a public/native client: the CLI uses no client secret. Enable the grants needed by the intended login mode:
| Login mode | Provider requirement | User action |
|---|---|---|
gdsgate login |
Device Authorization grant and an advertised device_authorization_endpoint |
Open the printed verification URL, enter the user code and approve. |
gdsgate login --browser |
Authorization Code grant with PKCE S256 and an allowed loopback callback | Complete sign-in in a browser on the CLI machine. |
| Renewable identity | Provider permission to issue a refresh token, commonly through offline_access |
Sign in once; later client operations can refresh the identity. |
Allow openid. An explicit scopes list must include it; request additional
scopes only when that client is allowed to use them. The provider must return an
id_token, with the expected audience and intended identity claims. A successful
exchange returning only an access token cannot complete gdsgate login.
Register the browser callback as http://127.0.0.1:<port>/callback. A fixed
oidc.browser.callback_port makes the URI predictable; an ephemeral port needs
the provider's supported loopback-port registration mechanism. A redirect URI
does not enable the device grant. A confidential client requiring a secret is
not supported by this profile. The clientless web entry has its separate HTTPS
callback; see redirect changes.
Check the provider's public discovery metadata:
Record issuer, jwks_uri, token_endpoint, authorization_endpoint and the
device endpoint when used. All participating nodes and clients need trusted
HTTPS access to the endpoints they use. Do not disable TLS verification to
diagnose an issuer or signing-key mismatch.
The configured issuer and discovery issuer are cross-checked, tolerating a
trailing slash in that comparison. The token's iss must match the advertised
issuer used by its validator. A different hostname or path is refused. The
profile has no issuer aliases or separate discovery-base override: a device
pending-error rule does not change issuer validation.
Configure and distribute the profile¶
Authority owns the intended public profile. Its validators enforce identity
claims and group policy. During authorized Proxy join, the profile is saved
into the Proxy configuration. The Proxy advertises its effective profile to
connect, which writes it into the selected client config.
| Component | Configuration responsibility |
|---|---|
| Every Authority | Same [oidc] profile and matching [identity] sanitisation; validates human tokens. |
| Every Proxy | Same public [oidc] profile; advertises it and uses it for browser entry. Authorized node metadata checks the configured issuer/client binding. |
| Each client | Saved [oidc] profile from the verified Proxy, or an explicitly maintained local profile; obtains, validates and refreshes the identity token. |
Existing files are snapshots. Changing Authority config does not rewrite every Proxy or client file, and replacing a binary does not refresh those files. Update the complete public profile on existing Proxies as part of the change. Local settings must agree with the enrolled node's issuer/client binding. Keep node identities and protected metadata; never edit or delete them to bypass a binding failure.
Initial profile¶
Merge this example into the existing Authority config, using provider-approved values. Preserve its endpoints, store, policy and key settings:
[oidc]
issuer = "https://idp.example.com/realms/gdsgate"
client_id = "gdsgate"
scopes = ["openid", "profile"]
id_token_signing_algs = ["RS256"]
audience defaults to client_id. Set it explicitly when the provider's
identity token has another intended audience. Add resource only if that
provider requires a public OAuth resource identifier. It selects a provider
resource; it does not cause gdsgate to read access-token or userinfo claims.
The intended groups must appear in the identity token.
Supply the issuer/client when preparing a new deployment, then set any extended profile before joining additional Proxies. See setup and Proxy join. Existing manual deployments must copy the same public profile into their Proxy configs.
Change an existing profile¶
This procedure changes scopes, resource, claim mapping, callback/polling or public request parameters while retaining the issuer and client ID:
- Take a protected backup of affected configs. Confirm the current cluster selection and upgrade Proxy/client consumers to 0.11 before distributing an extended profile. Older readers refuse the extended bootstrap layout.
- Apply the intended
[oidc]on every Authority and existing Proxy. Include nestedclaims,device,browserandparameterssettings; copying only issuer/client loses the rest. Do not copy server secrets to client configs. - Validate each role's existing full config, then restart Authorities and Proxies in the planned window. OIDC is a setting requiring restart; configuration reload does not apply it:
gdsgate config check /etc/gdsgate/authority.toml --role authority
gdsgate config check /etc/gdsgate/proxy.toml --role proxy
sudo systemctl restart gdsgate-authority
sudo systemctl restart gdsgate-proxy
Use the corresponding service manager on Windows or containers. Check every HA member and public Proxy backend before proceeding; see the upgrade checks. 4. On each workstation, back up the existing selected config and refresh it from the verified gateway at its intended path:
gdsgate contexts show
gdsgate connect gate.example.com:50061 \
--output ~/.gdsgate/clusters/production/config.toml --force
gdsgate config check ~/.gdsgate/clusters/production/config.toml --role client
gdsgate contexts show
connect requires system trust, terminal CA confirmation or the approved
--fingerprint. --force replaces the generated config and selects it;
review its path, transport anchor and retained local client settings before
applying a replacement. The output directory owns its anchor: use separate
directories for separate clusters. See connect.
An explicitly maintained client can receive the same public [oidc] section
directly; use gdsgate reload to apply its client settings to a resident.
5. Run a fresh gdsgate login, then gdsgate resources list and an allowed
operation. Confirm a denied operation too. If a resident is running, sign-in
announces the new identity to it. Existing sessions retain their own grant.
Replacing the issuer or client ID also changes node/client identity bindings. Coordinate that migration with authorized node metadata and all HA members; the recipe above does not bypass an old binding. A refresh record for another issuer/client is refused. Sign in again after the approved change, and inspect the explicit config named by any conflict error.
Device login and polling¶
The CLI requests a device code, prints the verification URL and user code, then polls the provider's token endpoint using the same device code. Do not print or share the device code, refresh token or returned bearer tokens in diagnostics. Approval must complete before the device code expires.
Normal pending replies continue polling. slow_down adds five seconds to the
delay between polls. Denial, expiry and other terminal errors stop the login.
These optional fragments merge into an already configured [oidc] profile:
interval is a local minimum between polls: the greater of it and the provider
interval is used. Without a provider interval the default is five seconds.
expires_in is a local maximum wait: the shorter of it and the provider lifetime
is used. If the provider supplies no lifetime, the local limit applies; without
either lifetime the loop permits at most 60 polls. Setting these values does not
make a terminal error pending.
Opt-in MSIS9612 pending compatibility¶
Enable this only after confirming that the observed response means approval is still pending and that the same device code succeeds after approval:
{
"error": "invalid_grant",
"error_description": "MSIS9612: The authorization code received in 'code' parameter is invalid. "
}
Add the bounded compatibility rule to the Authority profile and distribute it using the profile update procedure:
[oidc.device]
interval = 5
expires_in = 600
[[oidc.device.pending_errors]]
error = "invalid_grant"
description_prefix = "MSIS9612: The authorization code received in 'code' parameter is invalid."
The error code and case-sensitive description prefix must both match. A missing
or different description, access_denied, expiry and unrelated errors still
stop login. Matching pending responses obey the same interval and expiry limits.
The rule applies only to device polling, never to refresh or browser-code exchange.
Remove pending_errors or use an empty list to restore standard handling.
Do not enable the rule solely because of a provider product name. The response above was reported for a deployed provider; the controlled testbed used normal pending responses. Compatibility matching was exercised with simulated provider responses. Test this rule against the intended deployment before relying on it.
Browser login¶
For a fixed loopback callback, merge:
Register http://127.0.0.1:8400/callback, then run:
An occupied callback port fails the login. State, PKCE and nonce are generated and checked by gdsgate. Public provider parameters cannot override those fields, codes, grant type, redirect URI or client ID. Separate parameter tables apply to device authorization, token exchange and refresh; see request parameters. They are distributed in bootstrap and must contain no secrets or private values.
Map verified claims to groups and policy¶
Only the verified id_token supplies human claims. This illustrative payload
excerpt omits required signing/validity fields and is not a usable token:
{
"iss": "https://idp.example.com/realms/gdsgate",
"sub": "user-42",
"aud": "gdsgate",
"upn": "alice@example.test",
"membership": { "roles": ["lab-readers"] }
}
Merge these settings into the shared provider profile:
[oidc.claims]
preferred_username = "upn"
[oidc.claims.groups]
path = "/membership/roles"
format = "array"
required = true
This produces subject user-42, display username alice@example.test and
Cedar membership Group::"lab-readers". Display username and email do not
replace the verified subject. display_name_claims separately chooses what
Authority remembers for human-readable audit display.
| Provider payload | Group settings |
|---|---|
"groups": ["lab-readers", "operators"] |
path = "groups", format = "array" |
"role": "lab-readers" |
path = "role", format = "string" |
"roles": "lab-readers,operators" |
path = "roles", format = "delimited", delimiter = "," |
Nested membership.roles as above |
path = "/membership/roles", format = "array" |
A plain path is an exact top-level claim name; / selects a JSON pointer.
Dotted names are literal keys. Types are explicit, names are case-sensitive,
and whitespace/path prefixes are not trimmed. Missing optional groups yield no
groups; required = true refuses a missing claim. Malformed present values
and empty delimited elements fail mapping. Authority enforces its own count,
length and reserved-name limits: reserved values are refused, not silently
removed. Successful CLI login alone does not prove Authority admission.
For a declared and served database lab-read, merge these rules into the
reviewed existing policy, preserving its other rules and break-glass invariant:
permit (principal in Group::"lab-readers",
action == Action::"view",
resource == Database::"lab-read");
permit (principal in Group::"lab-readers",
action == Action::"connect",
resource == Database::"lab-read");
permit (principal in Group::"lab-readers",
action == Action::"dbQuery",
resource == Database::"lab-read")
when { context.sql_category == "read" };
Use the exact catalog ID. Automatic publication may assign a qualified ID. Validate the complete candidate policy offline, then use the normal reviewed policy-change workflow:
Verify fresh login, visibility and a read-only operation on lab-read. Verify
that a user outside the group and a lab-denied resource remain denied by the
intended complete policy. A rule cannot make an absent or unserved catalog row
reachable. See group access.
A provider group named admins receives only the permissions in the active
policy. The setup --access-group option seeds owner rules on a new installation;
changing a claim name does not itself issue an administrative certificate or
rewrite the running policy. For SSH also permit the intended sshProgram;
for Kubernetes check kubeRequest and backend impersonation/RBAC.
Identity tokens and renewal¶
Successful login validates signature, issuer, audience, expiry and configured claims before caching the identity. Browser login also checks the nonce. Authority validates the identity again for access and applies its sanitisation. The provider's access token is not the gdsgate identity, and userinfo claims are not fetched or merged.
The protected cluster directory stores identity.json, including the validated
identity token, optional refresh token and provider coordinates. Existing legacy
id_token files can be migrated. Do not expose either bearer token through
screenshots, support logs or online decoders.
With a provider-issued refresh token, later client operations can obtain a new
identity token before expiry. Explicit scopes are used as configured; request
offline_access only when granted to the client. Without a refresh token,
expiry requires another login. A rejected refresh or invalid new token preserves
the existing identity record; sign in again to recover. Configured issuer/client
changes cannot reuse a refresh grant for a different target.
Diagnose login and access¶
Start with the explicit config actually used by that command:
gdsgate contexts show
gdsgate config check ~/.gdsgate/clusters/production/config.toml --role client
gdsgate login
gdsgate resources list
config check validates local settings without contacting the provider. Inspect
discovery and provider registration separately. Share config field names, error
codes, sanitized descriptions and endpoint shapes; omit credentials and tokens.
| Symptom | Check | Corrective action |
|---|---|---|
| Partial provider or invalid profile | Issuer/client pair, HTTPS URL, group format/delimiter and protected parameter names | Correct the named field; distribute the same validated profile. |
unsupported ... layout during join/connect |
Versions of Authority, Proxy and client | Upgrade consumers before using extended settings. |
configured identity provider differs from the cluster provider |
Proxy config versus authorized saved issuer/client binding | Restore agreement through the planned binding migration; retain identity and metadata. |
OIDC issuer mismatch or invalid token issuer |
Config URL, discovery issuer, token iss, hostname and path |
Align the trusted issuer; a pending rule cannot repair this mismatch. |
Wrong audience or multi-audience azp failure |
Identity-token audience and [oidc].audience |
Correct the provider's intended audience and distribute it; never validate an access token as an identity token. |
Missing device endpoint, unauthorized_client or unsupported grant |
Discovery and client registration for Device Authorization | Enable the permitted public-client grant, or use an already registered PKCE flow. Redirect registration alone is insufficient. |
Immediate invalid_grant |
Exact device response, approval state and whether the same code succeeds after approval | Treat as terminal by default; use the narrowly verified MSIS9612 rule only for the confirmed pending response. |
authorization timed out or expired code |
Provider lifetime, local expires_in, polling delay and time taken to approve |
Obtain a new device code and approve before the effective deadline. Local settings cannot extend provider validity. |
| Redirect refusal or occupied callback port | Registered URI and [oidc.browser].callback_port |
Register the actual loopback URI or select a free registered port. |
Unknown kid, no usable JWKS key or unsupported algorithm |
Trusted discovery/JWKS, key publication and configured asymmetric algorithms | Publish usable keys before signing, retain overlap and verify refresh. Do not enable symmetric signing for external identities. |
idp returned no id_token |
Token response and requested openid scope |
Configure an identity-token grant with the provider; access-token-only responses cannot complete login. |
claim mapping failed |
Claim path, present type, delimiter, required setting and extraction limits | Correct the provider's identity-token claim or explicit mapping, then sign in again. |
| Login completes but listing/access is denied | Authority sanitisation, exact group names, active policy, selected cluster and serving state | Test the complete claim-to-policy mapping; malformed/reserved claims are refused and empty groups grant nothing by themselves. |
| Refresh is rejected | Provider refresh permission, token status and unchanged issuer/client binding | Sign in again; the device pending rule is not used for refresh. |
Verify the deployment¶
Test device approval, a deliberate denial and expiry without approval. With an enabled compatibility rule, confirm that its exact pending reply continues polling and unrelated failures stop. Test browser login with its registered callback when used. Verify both a group member and a nonmember, an allowed and a denied resource, and a fresh token after provider signing-key rotation.
Where refresh is used, verify renewal and the expected group claims in the new identity. In HA, verify every Authority profile and each public Proxy backend. Check the corresponding audit and session recording. These are deployment checks; this guide does not claim every provider configuration has been exercised on the controlled testbed.