Skip to main content

Version: 3.10.x

a7-plugin-openid-connect

Overview

The openid-connect plugin integrates API7 EE with external OpenID Connect identity providers (Keycloak, Auth0, Okta, etc.). It supports the full authorization code flow for browser-based applications, bearer token validation for API clients, and token introspection or local JWKS verification.

When to Use

  • Integrate with enterprise identity providers (Keycloak, Auth0, Okta, Azure AD)
  • Browser-based SSO with authorization code flow
  • API protection with bearer access tokens
  • Centralized authentication across multiple routes

Plugin Configuration Reference (Route/Service)

Required Fields

FieldTypeRequiredDefaultDescription
client_idstringYesOAuth 2.0 client ID
client_secretstringYesOAuth 2.0 client secret (encrypted in the database)
discoverystringYesOIDC well-known discovery URL

Authentication & Scopes

FieldTypeRequiredDefaultDescription
scopestringNo"openid"Space-delimited OIDC scopes
bearer_onlybooleanNofalseRequire bearer access token only (no redirect)
required_scopesarrayNoScopes required in access token
realmstringNo"apisix"Realm in WWW-Authenticate header

URIs & Redirects

FieldTypeRequiredDefaultDescription
redirect_uristringNo{route_uri}/.apisix/redirectRedirect URI after auth
logout_pathstringNo"/logout"Path to trigger logout
post_logout_redirect_uristringNoURL to redirect after logout
unauth_actionstringNo"auth"Action on unauth: "auth" (redirect), "deny" (401), "pass" (allow)

Token Verification

FieldTypeRequiredDefaultDescription
introspection_endpointstringNoToken introspection endpoint URL
public_keystringNoPEM public key for local JWT verification
use_jwksbooleanNofalseUse JWKS from discovery for local JWT verification
token_signing_alg_values_expectedstringNoExpected JWT signing algorithm

Session Management

FieldTypeRequiredDefaultDescription
session.secretstringYes*16+ char key for session encryption (*required for auth code flow)
session.cookie.lifetimeintegerNo3600Session cookie lifetime in seconds
session.storagestringNo"cookie""cookie" or "redis"

Headers to Upstream

FieldTypeRequiredDefaultDescription
set_access_token_headerbooleanNotrueSet X-Access-Token header
access_token_in_authorization_headerbooleanNofalseSet token in Authorization header
set_id_token_headerbooleanNotrueSet X-ID-Token header
set_userinfo_headerbooleanNotrueSet X-Userinfo header
hide_credentialsbooleanNofalseRemove auth headers before upstream

Advanced

FieldTypeRequiredDefaultDescription
ssl_verifybooleanNofalseVerify IdP SSL certificates
timeoutintegerNo3Request timeout to IdP in seconds
use_pkcebooleanNofalseEnable PKCE (RFC 7636)
renew_access_token_on_expirybooleanNotrueAuto-refresh expiring tokens

Token Verification Modes

1. Token Introspection (default for bearer_only)

API7 EE calls the IdP's introspection endpoint for every request.

  • Pros: Real-time validation, handles token revocation
  • Cons: Added latency (network call to IdP)
{
"openid-connect": {
"client_id": "my-app",
"client_secret": "secret",
"discovery": "https://keycloak.example.com/realms/my/.well-known/openid-configuration",
"bearer_only": true,
"introspection_endpoint": "https://keycloak.example.com/realms/my/protocol/openid-connect/token/introspect"
}
}

2. Local JWKS Verification

API7 EE fetches JWKS from the discovery document and validates JWT locally.

  • Pros: Fast (no per-request IdP call), scalable
  • Cons: Cannot detect revoked tokens until JWKS cache refreshes
{
"openid-connect": {
"client_id": "my-app",
"client_secret": "secret",
"discovery": "https://keycloak.example.com/realms/my/.well-known/openid-configuration",
"bearer_only": true,
"use_jwks": true
}
}

3. Static Public Key Verification

Provide the public key directly. No discovery or introspection calls.

{
"openid-connect": {
"client_id": "my-app",
"client_secret": "secret",
"discovery": "https://keycloak.example.com/realms/my/.well-known/openid-configuration",
"bearer_only": true,
"public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjAN...\n-----END PUBLIC KEY-----"
}
}

Step-by-Step: Authorization Code Flow (Keycloak)

1. Create a route with openid-connect

a7 route create -g default -f - <<'EOF'
{
"id": "oidc-webapp",
"uri": "/app/*",
"plugins": {
"openid-connect": {
"client_id": "apisix-client",
"client_secret": "your-client-secret",
"discovery": "https://keycloak.example.com/realms/myrealm/.well-known/openid-configuration",
"scope": "openid email profile",
"redirect_uri": "http://127.0.0.1:9080/app/redirect",
"session": {
"secret": "my-16-char-secret"
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": [{"host": "webapp", "port": 3000, "weight": 1}]
}
}
EOF

2. Flow

  1. User visits http://127.0.0.1:9080/app/dashboard → no session
  2. API7 EE redirects to Keycloak login page
  3. User authenticates → Keycloak redirects to http://127.0.0.1:9080/app/redirect?code=...
  4. API7 EE exchanges code for tokens, stores in session cookie
  5. Subsequent requests use the session cookie automatically

Step-by-Step: Bearer Token API Protection

1. Create a route for API protection

a7 route create -g default -f - <<'EOF'
{
"id": "oidc-api",
"uri": "/api/*",
"plugins": {
"openid-connect": {
"client_id": "apisix-client",
"client_secret": "your-client-secret",
"discovery": "https://keycloak.example.com/realms/myrealm/.well-known/openid-configuration",
"bearer_only": true,
"use_jwks": true
}
},
"upstream": {
"type": "roundrobin",
"nodes": [{"host": "backend", "port": 8080, "weight": 1}]
}
}
EOF

2. Obtain and use token

# Get token from IdP
TOKEN=$(curl -s -X POST \
"https://keycloak.example.com/realms/myrealm/protocol/openid-connect/token" \
-d "client_id=apisix-client" \
-d "client_secret=your-client-secret" \
-d "grant_type=client_credentials" \
| jq -r '.access_token')

# Call the API
curl -i http://127.0.0.1:9080/api/resource \
-H "Authorization: Bearer ${TOKEN}"

Provider Discovery URLs

ProviderDiscovery URL Pattern
Keycloakhttps://{host}/realms/{realm}/.well-known/openid-configuration
Auth0https://{tenant}.auth0.com/.well-known/openid-configuration
Oktahttps://{org}.okta.com/.well-known/openid-configuration
Azure ADhttps://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration
Googlehttps://accounts.google.com/.well-known/openid-configuration

Common Patterns

Redis session storage (distributed deployment)

{
"openid-connect": {
"client_id": "my-app",
"client_secret": "secret",
"discovery": "https://idp.example.com/.well-known/openid-configuration",
"session": {
"secret": "my-16-char-secret",
"storage": "redis",
"redis": {
"host": "redis.example.com",
"port": 6379,
"password": "redis-pass",
"database": 0
}
}
}
}

Allow unauthenticated access (optional auth)

{
"openid-connect": {
"client_id": "my-app",
"client_secret": "secret",
"discovery": "https://idp.example.com/.well-known/openid-configuration",
"bearer_only": true,
"unauth_action": "pass"
}
}

Authenticated requests get identity headers; unauthenticated requests pass through without identity.

PKCE for public clients

{
"openid-connect": {
"client_id": "spa-client",
"client_secret": "secret",
"discovery": "https://idp.example.com/.well-known/openid-configuration",
"use_pkce": true,
"session": {
"secret": "my-16-char-secret"
}
}
}

Troubleshooting

SymptomCauseFix
Redirect loop after loginredirect_uri same as route URISet redirect_uri to a sub-path (e.g., /app/redirect)
"no session state found"Session cookie not savedCheck session.secret length (16+ chars), check SameSite cookie policy
401 on valid bearer tokenIntrospection failingVerify introspection_endpoint URL, check client credentials
SSL errors to IdPssl_verify: true but certs invalidFix certs or set ssl_verify: false for testing
Large cookie errorsSession too big for cookieSwitch to session.storage: "redis"
Token not refreshingrenew_access_token_on_expiry: falseSet to true (default)

Config Sync Example

version: "1"
gateway_groups:
- name: default
routes:
- id: oidc-webapp
uri: /app/*
plugins:
openid-connect:
client_id: apisix-client
client_secret: your-client-secret
discovery: https://keycloak.example.com/realms/myrealm/.well-known/openid-configuration
scope: openid email profile
redirect_uri: http://127.0.0.1:9080/app/redirect
session:
secret: my-16-char-secret
upstream:
type: roundrobin
nodes:
- host: webapp
port: 3000
weight: 1

This page is generated from a7-plugin-openid-connect/SKILL.md in the api7/a7 repository. Browse all skills on the AI Agent Skills page.

API7.ai Logo

The digital world is connected by APIs,
API7.ai exists to make APIs more efficient, reliable, and secure.

Sign up for API7 newsletter

Product

API7 Gateway

SOC2 Type IIISO 27001HIPAAGDPRRed Herring

Copyright © APISEVEN PTE. LTD 2019 – 2026. Apache, Apache APISIX, APISIX, and associated open source project names are trademarks of the Apache Software Foundation