---
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 <name>` 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 <name>` blocks. Those configure the SSO
app/SAML role-assumption feature and belong in `configuration-sso-app`. Also do
not route `saml identity provider <name>` 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 <name>` 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 <kid> <pem_path>` 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/<org>/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 <exact|regex> <value>` and
`match github org <exact|regex> <value>`. 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/<guild_id>/members`, `discord.com/<guild_id>/admins`, and
  `discord.com/<guild_id>/role/<role_id>` 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>
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 <name>`, not `sso provider <name>`.
- 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 <name>` in the authentication portal.
- Use `match realm <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.
