Skip to main content

Okta

Sign in through Okta and allow an app-members group to reach a protected application. The example separates Okta app assignment, authorization-server policy, and AuthCrunch's application policy so each can be checked independently.

This guide targets caddy-security v1.3.0 with go-authcrunch v1.3.8. Local OIDC fixtures verify the released configuration, token checks, and allow/deny behavior. Live Okta assignment, policies, and consent must still be verified in your organization.

Before you start​

Complete Install and verify. Have an Okta administrator, a group named app-members, and two test accounts: one member and one nonmember. Use a public AuthCrunch hostname with ports 80 and 443 available for HTTPS. Replace auth.example.com in the example and app registration.

The named okta driver builds URLs for a custom authorization server and requires a server_id, such as default. Okta's built-in org authorization server has a different issuer and endpoint layout. Custom authorization servers require API Access Management in production; test organizations may include them. The default server can exist without an access policy, so check the policy rather than assuming the name makes the server ready. See Okta's authorization-server types.

Register a web application​

In the Admin Console, open Applications and Resources → Applications → Create App Integration. Choose OIDC – OpenID Connect and Web Application. Older consoles may label the first section simply Applications. Follow Okta's web app registration guidance with these values:

SettingValue
Sign-in redirect URIhttps://auth.example.com/auth/oauth2/okta/authorization-code-callback
Grant typeAuthorization Code
Client authenticationClient secret; token endpoint method client_secret_post
AssignmentsThe users or groups intended to sign in through this portal

AuthCrunch sends the client ID and secret in the token request's form body. Configure token_endpoint_auth_method as client_secret_post; an API-created client can default to client_secret_basic. If the console does not expose this setting, have your administrator verify it through Okta's client API. See Okta client authentication methods.

Save the Client ID and Client secret for the server environment. The released driver sends S256 PKCE with the authorization-code flow. This example does not request an Okta refresh token or use implicit/client-credentials grants.

Earlier Okta application wizard with Web selected

Earlier developer console: Web corresponds to the current OIDC Web Application choice. Select the image to view it at full size.

App assignment controls who may attempt Okta sign-in. To test AuthCrunch's nonmember denial separately, assign both test users to the app while keeping only one in app-members. If you assign only that group, Okta rejects the nonmember before AuthCrunch gets a token.

Configure the authorization server​

In Security → API → Authorization Servers, select your server. This guide uses default; another server ID is valid when its scopes, claims, and policies are configured consistently.

Add the groups scope and ID-token claim​

Create a scope named groups if it is absent. The example explicitly requests it, so it need not be a default scope. Then create this claim:

Claim settingValue
Namegroups
Include in token typeID Token, Always
Value typeGroups
FilterMatches regex: ^app-members$
Include inThe groups scope
Disable claimOff

Always matters: the named driver does not fetch UserInfo to fill in missing ID-token groups. A claim available only through UserInfo does not grant the application role in this example. See Okta's claim inclusion settings and groups claim guidance.

Ensure the returned ID token also contains email, as required by the driver's default email-presence check. If your authorization-server configuration only releases email through UserInfo, configure its email claim for ID-token inclusion. The app's access rule remains group based.

Earlier Okta groups claim editor with ID Token and Always selected

ID Token and Always are the key controls. Replace the historical match-all regex with ^app-members$ for this walkthrough. Select the image to view it at full size.

Add an access policy and rule​

Under the server's Access Policies, select or create a policy for this client. Add a rule allowing Authorization Code, the intended assigned users, and the requested openid email profile groups scopes. Review rule ordering and the existing policies in your organization. See Okta's access-policy setup.

These controls serve separate purposes:

ControlDecision
Okta app assignment and sign-on policyMay this user sign in to this client?
Authorization-server access policyMay this client/user obtain tokens for these scopes?
ID-token claim filterWhich of the user's group names are included?
AuthCrunch transform and policyDoes the resulting identity receive app/member and reach /app?
Okta assignment, token issuance, and app membership are separate gatesOkta assignment, token issuance, and app membership are separate gates

Okta assignment, token issuance, and app membership are separate gates. App assignment admits a user to the Okta client, and the custom authorization-server policy permits token issuance. The example requires the exact app-members value in the ID-token groups claim. A claim released only through UserInfo does not satisfy this named-driver walkthrough. Test an assigned nonmember to isolate AuthCrunch denial.

Scroll horizontally when needed, or open the diagram for a larger view. Download Mermaid source.

Configure AuthCrunch​

Save this as Caddyfile. The source is the canonical Okta example.

Caddyfile
# Set the public portal hostname, OKTA_DOMAIN, and OKTA_SERVER_ID before use.
{
admin off
persist_config off

security {
oauth identity provider okta {
driver okta
realm okta
client_id {env.OKTA_CLIENT_ID}
client_secret {env.OKTA_CLIENT_SECRET}
domain_name {$OKTA_DOMAIN}
server_id {$OKTA_SERVER_ID}
scopes openid email profile groups
login icon text "Okta"
}

authentication portal myportal {
enable identity provider okta
crypto default token lifetime 900
crypto key sign-verify {env.JWT_SHARED_KEY}
cookie path /

ui {
links {
"Example app" /app icon "las la-external-link-alt"
"My identity" /auth/whoami icon "las la-user"
}
}

# Reserve portal roles and app/member for the transforms below.
transform user {
regex match role "^(authp/.*|app/member)$"
action drop matched role
}

transform user {
match realm okta
action add role authp/user
}

transform user {
match realm okta
match role app-members
action add role app/member
}
}

authorization policy apppolicy {
set auth url https://auth.example.com/auth/
crypto key verify {env.JWT_SHARED_KEY}
allow roles app/member
}
}
}

auth.example.com {
route {
redir /auth /auth/ 308

authenticate /auth/* with myportal

@app path /app /app/*
route @app {
authorize with apppolicy
respond "You reached the Okta-protected app." 200
}

respond "AuthCrunch is running. Open /app to begin." 200
}
}

The portal maps the token's groups into roles before applying transforms. The first transform removes provider-derived authp/* and app/member roles; the following transforms grant portal access and translate the exact app-members group into app access. Keep that order so a group named app/member cannot bypass membership or authp/admin grant portal administration. A signed-in user without app-members can enter the portal but receives 403 from /app and its children.

Set these variables for the process that runs AuthCrunch:

export OKTA_DOMAIN='YOUR_ORG.okta.com'
export OKTA_SERVER_ID='default'
export OKTA_CLIENT_ID='YOUR_CLIENT_ID'
export OKTA_CLIENT_SECRET='YOUR_CLIENT_SECRET'
export JWT_SHARED_KEY="$(openssl rand -hex 32)"

Use your actual Okta hostname without https:// or a trailing slash; your organization may use a different Okta domain or a configured custom domain. OKTA_SERVER_ID is the authorization-server ID, not the app's client ID.

{$OKTA_DOMAIN} and {$OKTA_SERVER_ID} expand during Caddyfile parsing. Credentials and the signing key use runtime {env.VARIABLE} placeholders. Protect the environment file and reuse the signing key across restarts.

The driver's discovery URL has this shape:

https://YOUR_ORG.okta.com/oauth2/default/.well-known/openid-configuration?client_id=YOUR_CLIENT_ID

Verify it returns metadata for the intended issuer and reachable endpoints. With the installed binary, check and run:

./bin/authcrunch adapt --adapter caddyfile --config Caddyfile >/dev/null
./bin/authcrunch run --config Caddyfile

Adaptation checks configuration syntax; startup and a real login check the provider. The example disables the admin endpoint, so use Ctrl+C and restart after changes. Replace the protected respond with your application's reverse_proxy when the allow/deny checks pass.

Verify sign-in and access​

  1. Open https://auth.example.com/app, choose Okta, and sign in as the member.
  2. Select Example app from the portal if you are not sent there automatically. Expect You reached the Okta-protected app.
  3. Open My identity at /auth/whoami. Confirm realm: okta, app-members, and app/member in the roles.
  4. In a fresh browser session, use the assigned nonmember. Login should complete, but /app must return 403. A group with a similar name is not sufficient.
  5. Remove the member from the group and repeat with a fresh portal session to confirm the policy no longer admits that user.

Existing portal tokens retain their recorded roles; this example uses a 900-second lifetime. /auth/logout ends the portal session, not the Okta SSO session. Listing that URL as an Okta logout redirect does not make AuthCrunch call Okta's end-session endpoint.

Using the org authorization server​

For an org authorization server, use the generic OIDC driver with issuer https://YOUR_ORG.okta.com and its root /.well-known/openid-configuration metadata. Do not invent a server_id to make the named driver generate those endpoints. Configure the app's ID-token group claim using Okta's org-server instructions, then verify the returned email and groups with your actual authorization-code flow.

Troubleshoot​

SymptomCheck
invalid_client during token exchangeClient ID, secret, and client_secret_post authentication method
Scope or policy error in OktaSelected custom server, groups scope, app assignment, and a matching access-policy rule
Email missing during callbackInclude email in the ID token; this driver does not fill it from UserInfo
Portal login works but /app is 403ID Token → Always, exact groups claim name and group value, and a fresh login
Issuer validation failsKeep org/custom server and custom-domain issuer settings consistent with discovery
Logout seems to sign the user straight back inThe browser's Okta SSO session is separate from its AuthCrunch portal session

Agentic Prompts​

Copy a prompt into your LLM to explore this topic. Each prompt prioritizes upstream repository guidance and code over this page, and asks for version-aware reasoning.

Separate Okta policy layers
Help me understand Okta.

Primary authorities (take precedence over website documentation):
https://github.com/greenpau/caddy-security/blob/main/AGENTS.md
https://github.com/greenpau/caddy-security/tree/main/.codex/skills
https://github.com/greenpau/go-authcrunch/blob/main/AGENTS.md
https://github.com/greenpau/go-authcrunch/tree/main/.codex/skills
Read each repository's root AGENTS.md first, then any scoped AGENTS.md that
applies to inspected paths. Read the relevant SKILL.md files and follow their
implementation and test references.

Relevant skills to locate: configuration-oauth-providers,
oauth-identity-provider.

Secondary reference:
https://docs.authcrunch.com/docs/authenticate/oauth/backend-oauth2-0001-okta

If a source is inaccessible, ask me to paste its relevant text. Identify the
versions your answer applies to; main may be newer than my release. Resolve
disagreements using code and tests, and flag unverified claims. Use synthetic
credentials and redacted examples; explain proposed checks before any changes.

Explain app assignment, authorization-server access policy, claim inclusion,
and AuthCrunch app ACL as separate decisions. Use an assigned member and
assigned nonmember so a provider rejection is not mistaken for a portal 403.
Compare authorization servers
Help me understand Okta.

Primary authorities (take precedence over website documentation):
https://github.com/greenpau/caddy-security/blob/main/AGENTS.md
https://github.com/greenpau/caddy-security/tree/main/.codex/skills
https://github.com/greenpau/go-authcrunch/blob/main/AGENTS.md
https://github.com/greenpau/go-authcrunch/tree/main/.codex/skills
Read each repository's root AGENTS.md first, then any scoped AGENTS.md that
applies to inspected paths. Read the relevant SKILL.md files and follow their
implementation and test references.

Relevant skills to locate: configuration-oauth-providers,
oauth-identity-provider.

Secondary reference:
https://docs.authcrunch.com/docs/authenticate/oauth/backend-oauth2-0001-okta

If a source is inaccessible, ask me to paste its relevant text. Identify the
versions your answer applies to; main may be newer than my release. Resolve
disagreements using code and tests, and flag unverified claims. Use synthetic
credentials and redacted examples; explain proposed checks before any changes.

Compare the named driver’s custom authorization-server server_id with
org-server generic OIDC discovery. Explain how issuer and endpoint layout
differ. Ask for my tenant’s actual metadata and consult current official Okta
requirements before discussing product entitlement or console steps.
Read group claim inclusion
Help me understand Okta.

Primary authorities (take precedence over website documentation):
https://github.com/greenpau/caddy-security/blob/main/AGENTS.md
https://github.com/greenpau/caddy-security/tree/main/.codex/skills
https://github.com/greenpau/go-authcrunch/blob/main/AGENTS.md
https://github.com/greenpau/go-authcrunch/tree/main/.codex/skills
Read each repository's root AGENTS.md first, then any scoped AGENTS.md that
applies to inspected paths. Read the relevant SKILL.md files and follow their
implementation and test references.

Relevant skills to locate: configuration-oauth-providers,
oauth-identity-provider.

Secondary reference:
https://docs.authcrunch.com/docs/authenticate/oauth/backend-oauth2-0001-okta

If a source is inaccessible, ask me to paste its relevant text. Identify the
versions your answer applies to; main may be newer than my release. Resolve
disagreements using code and tests, and flag unverified claims. Use synthetic
credentials and redacted examples; explain proposed checks before any changes.

Trace requested groups scope, an always-included ID-token group claim,
normalized roles, and a narrow app/member transform. Explain why a group
returned only through UserInfo may not satisfy this named-driver example.
Check the email-presence requirement separately.
Diagnose token exchange
Help me understand Okta.

Primary authorities (take precedence over website documentation):
https://github.com/greenpau/caddy-security/blob/main/AGENTS.md
https://github.com/greenpau/caddy-security/tree/main/.codex/skills
https://github.com/greenpau/go-authcrunch/blob/main/AGENTS.md
https://github.com/greenpau/go-authcrunch/tree/main/.codex/skills
Read each repository's root AGENTS.md first, then any scoped AGENTS.md that
applies to inspected paths. Read the relevant SKILL.md files and follow their
implementation and test references.

Relevant skills to locate: configuration-oauth-providers,
oauth-identity-provider.

Secondary reference:
https://docs.authcrunch.com/docs/authenticate/oauth/backend-oauth2-0001-okta

If a source is inaccessible, ask me to paste its relevant text. Identify the
versions your answer applies to; main may be newer than my release. Resolve
disagreements using code and tests, and flag unverified claims. Use synthetic
credentials and redacted examples; explain proposed checks before any changes.

Help me investigate invalid_client or a missing group using redacted
client-auth method, issuer/server_id, scope, access policy, and ID-token claim
shape. Explain form-body secret authentication versus Basic. Preserve PKCE,
signature, issuer, audience, and nonce checks.
Design Okta access checks
Help me understand Okta.

Primary authorities (take precedence over website documentation):
https://github.com/greenpau/caddy-security/blob/main/AGENTS.md
https://github.com/greenpau/caddy-security/tree/main/.codex/skills
https://github.com/greenpau/go-authcrunch/blob/main/AGENTS.md
https://github.com/greenpau/go-authcrunch/tree/main/.codex/skills
Read each repository's root AGENTS.md first, then any scoped AGENTS.md that
applies to inspected paths. Read the relevant SKILL.md files and follow their
implementation and test references.

Relevant skills to locate: configuration-oauth-providers,
oauth-identity-provider.

Secondary reference:
https://docs.authcrunch.com/docs/authenticate/oauth/backend-oauth2-0001-okta

If a source is inaccessible, ask me to paste its relevant text. Identify the
versions your answer applies to; main may be newer than my release. Resolve
disagreements using code and tests, and flag unverified claims. Use synthetic
credentials and redacted examples; explain proposed checks before any changes.

Build tests for assigned member, assigned nonmember, provider-unassigned
account, lookalike group, reserved-role injection, and changed membership with
fresh login. Explain local logout versus Okta SSO and what local fixtures
cannot establish about live tenant policy.

Source Code References​

Start with the code search, then follow the parser, runtime, and tests relevant to this topic. These links target main; use GitHub's branch/tag selector to compare them with your installed release.

  1. Search this topic in both repositories — searches topic-specific symbols and paths across both codebases.
  2. caddy-security: caddyfile_identity_provider_oauth.go — adapts OAuth/OIDC provider settings, scopes, endpoints, and trust options.
  3. go-authcrunch: pkg/idp/oauth/config.go — validates generic and named-driver defaults and endpoint settings.
  4. go-authcrunch: pkg/idp/oauth/provider.go — loads discovery metadata, provider readiness, and driver setup.
  5. go-authcrunch: pkg/idp/oauth/jwt.go — checks upstream token signatures, issuer, audience, and transaction trust.
  6. go-authcrunch: pkg/idp/oauth/claim_parser.go — maps supported token claims into the normalized provider identity.
  7. go-authcrunch: pkg/idp/oauth/config_test.go — tests generic/named provider configuration and validation.