--- name: configuration-oauth-providers description: "Configure external OAuth/OIDC login providers, credentials, scopes, issuer/audience trust, JWKS, PKCE, and portal enablement. Named relying-party registrations and portal OPs belong to OAuth applications." --- # Configuration OAuth Providers ## Purpose Use this skill to configure `oauth identity provider ` blocks. The Caddyfile syntax is authoritative in `caddyfile_identity.go` and `caddyfile_identity_provider_oauth.go`; it delegates to the shared upstream OAuth parser. The provisioning behavior is authoritative in the module selected by `go.mod` and any active replacement, especially `pkg/idp/oauth/config.go`. A sibling checkout is read-only context and may differ from that selection; inspect `go list -m -json github.com/greenpau/go-authcrunch`. Do not use this skill for `sso provider ` blocks. Those configure the SSO app/SAML role-assumption feature and belong in `configuration-sso-app`. Also do not route `saml identity provider ` blocks here; their headers share the dispatcher but SAML uses the local `go-authcrunch/pkg/idp/saml` implementation. Read [shared parsing, grammar compatibility, and trust](references/shared-parser.md) when changing OAuth directives, issuer/audience, keys, or parser validation. The [qualified operator examples](../configuration/references/operator-examples.md) include an actual TLS journey using explicit issuer/access-token audience and static Ed25519 keys. Upstream login does not create downstream OP or local portal-refresh authority. Use `assets/config/home.Caddyfile` as the nearest repository example for Azure, GitHub, and LinkedIn OAuth providers. ## Shape ```caddyfile { security { oauth identity provider azure { realm azure driver azure tenant_id {env.AZURE_APP_TENANT_ID} client_id {env.AZURE_APP_CLIENT_ID} client_secret {env.AZURE_APP_CLIENT_SECRET} scopes openid email profile enable id token cookie id_token AZURE_ID_TOKEN } oauth identity provider github { realm github driver github client_id {env.GITHUB_APP_CLIENT_ID} client_secret {env.GITHUB_APP_CLIENT_SECRET} icon github priority 100 disable pkce } authentication portal myportal { enable identity provider azure github } } } ``` The identity provider name must match the portal's `enable identity provider ` value. The `realm` is what user transforms usually match: ```caddyfile transform user { match realm github action add role authp/user } ``` ## Supported Drivers `go-authcrunch` currently supports these OAuth drivers: ```text azure, cognito, discord, facebook, generic, github, gitlab, google, linkedin, nextcloud, okta ``` Every OAuth provider needs `realm`, `driver`, `client_id`, and `client_secret`; the Caddyfile provider name becomes authcrunch's config `Name`. Use Caddy placeholders or secrets for client secrets. For runtime references, retain the app's `oauth_provider_directives` snapshot in adapted JSON: it recalculates driver defaults after resolving the original arguments. See [runtime references](references/shared-parser.md#runtime-references). The shortcut form is supported only for `github`, `google`, and `facebook`: ```caddyfile oauth identity provider github {env.GITHUB_APP_CLIENT_ID} {env.GITHUB_APP_CLIENT_SECRET} ``` Prefer full blocks when adding icons, scopes, cookie behavior, or provider toggles. When `scopes` is omitted, authcrunch defaults by driver: - `github`: `read:user`. - `facebook`: `email`. - `discord`: `identify`. - `nextcloud`: `email`. - `google`, `cognito`, `linkedin`, and the fallback for `azure`, `gitlab`, `okta`, and `generic`: `openid email profile`. ## Provider Notes - Azure: include `tenant_id` when targeting a tenant. If omitted, authcrunch defaults to `common` and computes Azure base and metadata URLs from it. - Google: authcrunch fills Google base and metadata URLs. If `client_id` has no dot, authcrunch appends `.apps.googleusercontent.com`. - GitHub, Facebook, and Discord: authcrunch fills authorization and token URLs and requires only `access_token` in the token response. - GitLab: authcrunch defaults `domain_name` to `gitlab.com` and computes base and metadata URLs from it. - LinkedIn: defaults to OpenID-style scopes; `assets/config/home.Caddyfile` enables an id token cookie for this provider. - Okta: requires `domain_name` and `server_id` even when overriding URLs. If `base_auth_url` is omitted, authcrunch computes base and metadata URLs from those fields; if `base_auth_url` is supplied manually, also supply `metadata_url` unless using the explicit static-key path below. - Cognito: requires `region` and `user_pool_id`; authcrunch computes base and metadata URLs from them. - Nextcloud: set `base_auth_url`; authcrunch derives the authorization and token URLs from it. - Generic: always set a parseable `base_auth_url`. Then either set `metadata_url` for discovery, or set `authorization_url`, `token_url`, and `jwks key ` together. Static and combined key sources retain TLS, nonce, PKCE, and signature verification. Explicit static IDs override colliding discovery keys. ## GitHub identity claims With go-authcrunch v1.3.8, authenticated GitHub `/user` IDs also appear as the lossless string claim `github_id`. Numeric `metadata.id` and login-based `sub` remain unchanged. A rename therefore does not change ID matching; missing IDs cannot match, and malformed supplied IDs reject login. For organization claims, add `user_org_filters .*` (or narrower login-name regexes) inside the GitHub provider. Only returned organizations passing those filters populate `github_orgs`; existing `github.com//members` groups remain. No filter means no organization lookup. The existing endpoint exposes a single page of public memberships; this feature adds no pagination or private membership discovery, and adding `read:org` alone does not change the endpoint. Use [configuration-authentication-user-transforms](../configuration-authentication-user-transforms/SKILL.md#github-identity-matchers) to assign roles with `match github id ` and `match github org `. The actual backend driver establishes trust; naming another driver's realm `github` does not grant these claims. Transforms cannot mutate either claim, including through nested actions. `TestCaddyGithubTransformsE2E` qualifies these contracts through Caddy and a local TLS OAuth fixture, including lookup denial and provider impersonation. ## Provider-Side Claim Notes Some OAuth failures require changes in the upstream provider console, not the Caddyfile parser: - Discord: the default `identify` scope yields the Discord user identity. Add `email` for email claims, `guilds` for guild membership, and `guilds.members.read` for guild role checks. When `user_group_filters` matches a guild, authcrunch can emit roles such as `discord.com//members`, `discord.com//admins`, and `discord.com//role/` for transform matching. - GitHub: configure App account permissions for email addresses with read-only access when `/whoami` or transforms need email claims. Without this provider permission and user consent, email may be absent even when the Caddyfile is valid. - Keycloak: create realm roles or groups that correspond to application roles, assign users to them, and add client mappers for email and groups/roles so the claims appear in tokens or userinfo. Missing mappers often look like a transform bug but are provider-side configuration. - Cognito: configure required user-pool fields, app client callback/sign-out URLs, domain, and custom attributes before login. The legacy docs note that custom attributes such as `custom:roles` and `custom:timezone` may not appear in the issued portal token without additional provider/userinfo extraction behavior. - Ping Identity, Auth0, OneLogin, and other hosted providers often require console-side callback URL, logout URL, scope, and claim mapping setup even when the generic Caddyfile shape is correct. ## Common Options The parser accepts single-value OAuth fields such as `realm`, `driver`, `tenant_id`, `domain_name`, `client_id`, `client_secret`, `server_id`, `base_auth_url`, `metadata_url`, `authorization_url`, `token_url`, `issuer`, `access_token_audience`, `region`, `user_pool_id`, `identity_token_field_name`, `identity_token_cookie_name`, and `user_info_roles_field_name`. Shared keys also accept separate words. Recognized syntax with a shared-validation restriction: ```caddyfile logout_url logout url ``` These are aliases for one scalar in upstream `pkg/idp/oauth/parser/fields.go`. The selected v1.3.4 shared validator in `pkg/idp/config.go` excludes that field, so Caddy adaptation rejects it. Keep both forms documented with that status; exclude them from runnable examples until shared validation supports them. `enable logout` / `logout enabled` remains a separate supported switch. It accepts numeric retry and delayed-start fields: ```caddyfile delay_start 10 retry_attempts 5 retry_interval 5 ``` With `delay_start` but no retry settings, authcrunch defaults to two attempts and uses `delay_start` as the retry interval. With `retry_attempts` but no interval, authcrunch defaults the interval to 5 seconds. It accepts repeatable/list fields: ```caddyfile scopes openid email profile user_group_filters "^github.com/example/" user_org_filters "^example-org$" response_type code required_token_fields access_token id_token jwks key main testdata/oauth/87329db33bf_pub.pem ``` For generic OpenID providers with a discovered `userinfo_endpoint`, choose one extraction line below; optionally set the roles field: ```caddyfile extract email profile roles from userinfo extract all from userinfo user_info_roles_field_name roles ``` Accepted toggles include: ```caddyfile disable metadata discovery disable key verification disable pass grant type disable response type disable scope disable nonce disable tls verification disable email claim check disable pkce enable accept header enable js callback enable logout enable id token cookie id_token AZURE_ID_TOKEN ``` `disable metadata discovery` is parsed into `metadata_discovery_disabled`, but current authcrunch OAuth provider setup does not use that flag by itself to skip discovery. To avoid metadata fetching, configure explicit URLs as required by the driver and account for JWKS behavior. External logout is separate from local portal logout. `enable logout` enables provider-specific logout handling when the driver implements it. It does not make typed-only `logout_url` available through Caddy's shared dispatcher. For id token cookies, these are alternative spaced Caddyfile forms: ```caddyfile enable id token cookie enable id token cookie id_token enable id token cookie id_token AZURE_ID_TOKEN ``` The first optional value is the token response field to copy and must be `id_token` or `access_token`; the second optional value is the cookie name. When the cookie name is omitted, authcrunch uses `AUTHP_ID_TOKEN` for the provider identity-token cookie. ## Review Checklist Check generated OAuth provider entries against these code-backed constraints: - Use `oauth identity provider `, not `sso provider `. - Include `realm`, `driver`, `client_id`, and `client_secret`. - Choose a driver supported by `go-authcrunch`. - Add provider-specific required fields for Okta, Cognito, Nextcloud, and generic providers. - For generic providers, include `base_auth_url` plus either `metadata_url` or explicit `authorization_url`, `token_url`, and static `jwks key` entries. - Use `enable identity provider ` in the authentication portal. - Use `match realm ` in transforms when assigning roles after OAuth login. - Use the spaced form `enable id token cookie ...`; avoid inventing `enable id_token cookie`. - Treat `disable metadata discovery` as a parsed flag, not as sufficient runtime behavior by itself. - Keep client secrets in placeholders or secret lookups. ## Fixtures Use these examples: - `assets/config/home.Caddyfile` for Azure, GitHub, and LinkedIn. - `testdata/caddyfile_adapt/testcase_authenticate_with_oauth.Caddyfile` for OAuth plus portal and authorization wiring. - `caddyfile_identity_provider_oauth.go` for Caddy translations into the shared parser, with grammar inventory and validation in the linked reference. - `go-authcrunch/pkg/idp/oauth/config.go` for driver defaults and validation.