OpenID Connect (1.0) plugin allows the integration with a 3rd party identity provider (IdP) in a standardized way. This plugin can be used to implement Kong as a (proxying) OAuth 2.0 resource server (RS) and/or as an OpenID Connect relying party (RP) between the client, and the upstream service.

The plugin supports several types of credentials and grants:

  • Signed JWT access tokens (JWS)
  • Opaque access tokens
  • Refresh tokens
  • Authorization code
  • Username and password
  • Client credentials
  • Session cookies

The plugin has been tested with several OpenID Connect providers:

As long as your provider supports OpenID Connect standards, the plugin should work, even if it is not specifically tested against it. Let Kong know if you want your provider to be tested and added to the list.

Once applied, any user with a valid credential can access the Service.

This plugin can be used for authentication in conjunction with the Application Registration plugin.

Important Configuration Parameters

This plugin contains many configuration parameters that might seem overwhelming at the start. Here is a list of parameters that you should focus on first:

  1. The first parameter you should configure is: config.issuer.

    This parameter tells the plugin where to find discovery information, and it is the only required parameter. You should specify the realm or iss for this parameter if you don’t have a discovery endpoint.

    Note: This does not have to match the URL of the iss claim in the access tokens being validated. To set URLs supported in the iss claim, use config.issuers_allowed.

  2. Next, you should decide what authentication grants you want to use with this plugin, so configure: config.auth_methods.

    That parameter should contain only the grants that you want to use; otherwise, you inadvertently widen the attack surface.

  3. In many cases, you also need to specify config.client_id, and if your identity provider requires authentication, such as on a token endpoint, you will need to specify the client authentication credentials too, for example config.client_secret.

  4. If you are using a public identity provider, such as Google, you should limit the audience with config.audience_required to contain only your config.client_id. You may also need to adjust config.audience_claim in case your identity provider uses a non-standard claim (other than aud as specified in JWT standard). This is because, for example Google, shares the public keys with different clients.

  5. If you are using Kong in DB-less mode with the declarative configuration, you should set up config.session_secret if you are also using the session cookie authentication. Otherwise, each of your Nginx workers across all your nodes will encrypt and sign the cookies with their own secrets.

In summary, start with the following parameters:

  1. config.issuer
  2. config.auth_methods
  3. config.client_id (and in many cases the client authentication credentials)
  4. config.audience_required (if using a public identity provider)
  5. config.session_secret (if using the Kong in DB-less mode)

Configuration Reference

This plugin is compatible with DB-less mode.

In DB-less mode, you configure Kong Gateway declaratively. Therefore, the Admin API is mostly read-only. The only tasks it can perform are all related to handling the declarative config, including:

  • Setting a target’s health status in the load balancer
  • Validating configurations against schemas
  • Uploading the declarative configuration using the /config endpoint

Enable the plugin on a service

Admin API

Kubernetes

Declarative (YAML)

Konnect Cloud

Kong Manager

For example, configure this plugin on a service by making the following request:

  1. curl -X POST http://{HOST}:8001/services/{SERVICE}/plugins \
  2. --data "name=openid-connect" \
  3. --data "config.auth_methods=authorization_code" \
  4. --data "config.auth_methods=session" \
  5. --data "config.hide_credentials=true" \
  6. --data "config.issuer=<discovery-uri>" \
  7. --data "config.client_id=<client-id>" \
  8. --data "config.client_secret=<client-secret>" \
  9. --data "config.session_secret=<session-secret>" \
  10. --data "config.response_mode=form_post"

SERVICE is the id or name of the service that this plugin configuration will target.

First, create a KongPlugin resource:

  1. apiVersion: configuration.konghq.com/v1
  2. kind: KongPlugin
  3. metadata:
  4. name: <openid-connect-example>
  5. config:
  6. auth_methods:
  7. - authorization_code
  8. - session
  9. hide_credentials: true
  10. issuer: <discovery-uri>
  11. client_id:
  12. - <client-id>
  13. client_secret:
  14. - <client-secret>
  15. session_secret: <session-secret>
  16. response_mode: form_post
  17. plugin: openid-connect

Next, apply the KongPlugin resource to a Service by annotating the Service as follows:

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: {SERVICE}
  5. labels:
  6. app: {SERVICE}
  7. annotations:
  8. konghq.com/plugins: <openid-connect-example>
  9. spec:
  10. ports:
  11. - port: 80
  12. targetPort: 80
  13. protocol: TCP
  14. name: {SERVICE}
  15. selector:
  16. app: {SERVICE}

{SERVICE} is the id or name of the service that this plugin configuration will target.

Note: The KongPlugin resource only needs to be defined once and can be applied to any service, consumer, or route in the namespace. If you want the plugin to be available cluster-wide, create the resource as a KongClusterPlugin instead of KongPlugin.

For example, configure this plugin on a service by adding this section to your declarative configuration file:

  1. plugins:
  2. - name: openid-connect
  3. service: {SERVICE}
  4. config:
  5. auth_methods:
  6. - authorization_code
  7. - session
  8. hide_credentials: true
  9. issuer: <discovery-uri>
  10. client_id:
  11. - <client-id>
  12. client_secret:
  13. - <client-secret>
  14. session_secret: <session-secret>
  15. response_mode: form_post

SERVICE is the id or name of the service that this plugin configuration will target.

Configure this plugin on a service:

  1. In Konnect Cloud, select the service on the ServiceHub page.
  2. Scroll down to Versions and select the version.
  3. Scroll down to Plugins and click New Plugin.
  4. Find and select the OpenID Connect plugin.
  5. Enter the following parameters, updating the default or sample values as needed:

    • Config.Hide Credentials: true
    • Config.Issuer: <discovery-uri>
  6. Click Create.

Configure this plugin on a service:

  1. In Kong Manager, select the workspace.
  2. From the Dashboard, scroll down to Services and click View for the service row.
  3. Scroll down to plugins and click Add Plugin.
  4. Find and select the OpenID Connect plugin.

    Note: If the plugin is greyed out, then it is not available for your product tier. See Kong Gateway tiers.

  5. If the option is available, select Scoped.

  6. Add the service name and ID to the Service field if it is not already prefilled.
  7. Enter the following parameters, updating the default or sample values as needed:

    • Config.Hide Credentials: true
    • Config.Issuer: <discovery-uri>
  8. Click Create.

Enable the plugin on a route

Admin API

Kubernetes

Declarative (YAML)

Konnect Cloud

Kong Manager

For example, configure this plugin on a route with:

  1. $ curl -X POST http://{HOST}:8001/routes/{ROUTE}/plugins \
  2. --data "name=openid-connect" \
  3. --data "config.auth_methods=authorization_code" \
  4. --data "config.auth_methods=session" \
  5. --data "config.hide_credentials=true" \
  6. --data "config.issuer=<discovery-uri>" \
  7. --data "config.client_id=<client-id>" \
  8. --data "config.client_secret=<client-secret>" \
  9. --data "config.session_secret=<session-secret>" \
  10. --data "config.response_mode=form_post"

ROUTE is the id or name of the route that this plugin configuration will target.

First, create a KongPlugin resource:

  1. apiVersion: configuration.konghq.com/v1
  2. kind: KongPlugin
  3. metadata:
  4. name: <openid-connect-example>
  5. config:
  6. auth_methods:
  7. - authorization_code
  8. - session
  9. hide_credentials: true
  10. issuer: <discovery-uri>
  11. client_id:
  12. - <client-id>
  13. client_secret:
  14. - <client-secret>
  15. session_secret: <session-secret>
  16. response_mode: form_post
  17. plugin: openid-connect

Then, apply it to an ingress (Route or Routes) by annotating the ingress as follows:

  1. apiVersion: networking/v1beta1
  2. kind: Ingress
  3. metadata:
  4. name: {ROUTE}
  5. annotations:
  6. kubernetes.io/ingress.class: kong
  7. konghq.com/plugins: <openid-connect-example>
  8. spec:
  9. rules:
  10. - host: examplehostname.com
  11. http:
  12. paths:
  13. - path: /bar
  14. backend:
  15. serviceName: echo
  16. servicePort: 80

ROUTE is the id or name of the route that this plugin configuration will target.

Note: The KongPlugin resource only needs to be defined once and can be applied to any service, consumer, or route in the namespace. If you want the plugin to be available cluster-wide, create the resource as a KongClusterPlugin instead of KongPlugin.

For example, configure this plugin on a route by adding this section to your declarative configuration file:

  1. plugins:
  2. - name: openid-connect
  3. route: <route>
  4. config:
  5. auth_methods:
  6. - authorization_code
  7. - session
  8. hide_credentials: true
  9. issuer: <discovery-uri>
  10. client_id:
  11. - <client-id>
  12. client_secret:
  13. - <client-secret>
  14. session_secret: <session-secret>
  15. response_mode: form_post

ROUTE is the id or name of the route that this plugin configuration will target.

Configure this plugin on a route:

  1. In Konnect Cloud, select the service from the ServiceHub page.
  2. Scroll down to Versions and select the version.
  3. Select the route.
  4. Scroll down to Plugins and click Add Plugin.
  5. Find and select the OpenID Connect plugin.
  6. Enter the following parameters, updating the default or sample values as needed:

    • Config.Hide Credentials: true
    • Config.Issuer: <discovery-uri>
  7. Click Create.

Configure this plugin on a route:

  1. In Kong Manager, select the workspace.
  2. From the Dashboard, select Routes in the left navigation.
  3. Click View for the route row.
  4. Scroll down to plugins and click Add Plugin.
  5. Find and select the OpenID Connect plugin.

    Note: If the plugin is greyed out, then it is not available for your product tier. See Kong Gateway tiers.

  6. If the option is available, select Scoped.

  7. Add the Route ID if it is not already prefilled.
  8. Enter the following parameters, updating the default or sample values as needed:

    • Config.Hide Credentials: true
    • Config.Issuer: <discovery-uri>
  9. Click Create.

Enable the plugin globally

A plugin which is not associated to any service, route, or consumer is considered global, and will be run on every request. Read the Plugin Reference and the Plugin Precedence sections for more information.

Admin API

Kubernetes

Declarative (YAML)

Kong Manager

For example, configure this plugin globally with:

  1. $ curl -X POST http://{HOST}:8001/plugins/ \
  2. --data "name=openid-connect" \
  3. --data "config.auth_methods=authorization_code" \
  4. --data "config.auth_methods=session" \
  5. --data "config.hide_credentials=true" \
  6. --data "config.issuer=<discovery-uri>" \
  7. --data "config.client_id=<client-id>" \
  8. --data "config.client_secret=<client-secret>" \
  9. --data "config.session_secret=<session-secret>" \
  10. --data "config.response_mode=form_post"

Create a KongClusterPlugin resource and label it as global:

  1. apiVersion: configuration.konghq.com/v1
  2. kind: KongClusterPlugin
  3. metadata:
  4. name: <global-openid-connect>
  5. annotations:
  6. kubernetes.io/ingress.class: kong
  7. labels:
  8. global: \"true\"
  9. config:
  10. auth_methods:
  11. - authorization_code
  12. - session
  13. hide_credentials: true
  14. issuer: <discovery-uri>
  15. client_id:
  16. - <client-id>
  17. client_secret:
  18. - <client-secret>
  19. session_secret: <session-secret>
  20. response_mode: form_post
  21. plugin: openid-connect

For example, configure this plugin using the plugins: entry in the declarative configuration file:

  1. plugins:
  2. - name: openid-connect
  3. config:
  4. auth_methods:
  5. - authorization_code
  6. - session
  7. hide_credentials: true
  8. issuer: <discovery-uri>
  9. client_id:
  10. - <client-id>
  11. client_secret:
  12. - <client-secret>
  13. session_secret: <session-secret>
  14. response_mode: form_post

Configure this plugin globally:

  1. In Kong Manager, select the workspace.
  2. From the Dashboard, select Plugins in the left navigation.
  3. Click New Plugin.
  4. Find and select the OpenID Connect plugin.

    Note: If the plugin is greyed out, then it is not available for your product tier. See Kong Gateway tiers.

  5. If the option is available, set the plugin scope to Global.

  6. Enter the following parameters, updating the default/sample values as needed:

    • Config.Hide Credentials: true
    • Config.Issuer: <discovery-uri>
  7. Click Create.

Parameters

Here’s a list of all the parameters which can be used in this plugin’s configuration:

Form ParameterDescription
name
required

Type: string
The name of the plugin, in this case openid-connect.
service.id

Type: string
The ID of the Service the plugin targets.
route.id

Type: string
The ID of the Route the plugin targets.
enabled
required

Type: boolean

Default value: true
Whether this plugin will be applied.


Authentication Grants
Parameters for enabling only grants/credentials that you want to use.
Form ParameterDescription
config.authmethods
optional

Type: array of string elements

Default value: [“password”, “client_credentials”, “authorization_code”, “bearer”, “introspection”, “userinfo”, “kong_oauth2”, “refresh_token”, “session”]

Types of credentials/grants to enable:

  • password: OAuth legacy password grant
  • client_credentials: OAuth client credentials grant
  • authorization_code: authorization code flow
  • bearer: JWT access token verification
  • introspection: OAuth introspection
  • userinfo: OpenID Connect user info endpoint authentication
  • kong_oauth2: Kong OAuth plugin issued tokens verification
  • refresh_token: OAuth refresh token grant
  • session: session cookie authentication



Anonymous Access
Parameter for allowing anonymous access. This parameter is disabled by default.
Form ParameterDescription
config.anonymous
optional

Type: uuid

Let unauthenticated requests pass or skip the plugin if another authentication plugin has already authenticated the request by setting the value to anonymous Consumer.



General Settings
Parameters for settings that affect different grants and flows.
Form ParameterDescription
config.preserve_query_args
optional

Type: boolean

Default value: false

With this parameter, you can preserve request query arguments even when doing authorization code flow.

When this parameter is used with the config.login_action=redirect parameter, the browser location will change and display the original query arguments. Otherwise, the upstream request is modified to include the original query arguments, and the browser will not display them in the location field.

config.refresh_tokens
optional

Type: boolean

Default value: true

Specifies whether the plugin should try to refresh (soon to be) expired access tokens if the plugin has a refresh_token available.

config.hide_credentials
required

Type: boolean

Default value: true

Remove the credentials used for authentication from the request.

If multiple credentials are sent with the same request, the plugin will remove those that were used for successful authentication.

config.search_user_info
optional

Type: boolean

Default value: false

Specify whether to use the user info endpoint to get addition claims for consumer mapping, credential mapping, authenticated groups, and upstream and downstream headers.

This requires an extra round-trip and can add latency, but the plugin can also cache user info requests (see: config.cache_user_info).



Discovery
Parameters for auto-configuring most of the settings and providing the means for key rotation.
Form ParameterDescription
config.issuer
required

Type: url

The discovery endpoint (or just the issuer identifier).

When using Kong with the database, the discovery information and the JWKS are cached to the Kong configuration database.

config.rediscovery_lifetime
optional

Type: integer

Default value: 30

Specifies how often (in seconds) the plugin completes a re-discovery.

The re-discovery usually happens when the plugin cannot find a key for verifying the signature.



Client
Form ParameterDescription
config.client_id
optional

Type: array of string elements (the plugin supports multiple clients)

The client id(s) that the plugin uses when it calls authenticated endpoints on the identity provider. Other settings that are associated with the client are:

  • config.client_secret
  • config.client_auth
  • config.client_jwk
  • config.client_alg
  • config.redirect_uri
  • config.login_redirect_uri
  • config.logout_redirect_uri
  • config.unauthorized_redirect_uri
  • config.forbidden_redirect_uri
  • config.unexpected_redirect_uri

Use the same array index when configuring related settings for the client.

This field is referenceable, which means it can be securely stored as a secret in a vault. References must follow a specific format.

If keyring database encryption is enabled, this value will be encrypted.

config.client_arg
optional

Type: string

The client to use for this request (the selection is made with a request parameter with the same name). For example, setting this value to Client, and sending the request header Client: 1 will cause the plugin to use the first client (see: config.client_id) from the client array.



Client Authentication
Parameters for configuring how the client should authenticate with the identity provider.
Form ParameterDescription
config.client_auth
optional

Type: array of string elements (one for each client)

Default value: (discovered or “client_secret_basic”)

The authentication method used by the client (plugin) when calling the endpoints:

  • client_secret_basic: send client_id and client_secret in Authorization: Basic header
  • client_secret_post: send client_id and client_secret as part of the body
  • client_secret_jwt: send client assertion signed with the client_secret as part of the body
  • private_key_jwt: send client assertion signed with the private key as part of the body
  • none: do not authenticate

Private keys can be stored in a database, and they are by the default automatically generated in the database. It is also possible to specify private keys with config.client_jwk directly in the plugin configuration.

config.client_secret
optional

Type: array of string elements (one for each client)

The client secret.

Specify one if using client_secret authentication with the client on the identity provider endpoints.

This field is referenceable, which means it can be securely stored as a secret in a vault. References must follow a specific format.

If keyring database encryption is enabled, this value will be encrypted.

config.client_jwk
optional

Type: array of JWK records (one for each client)

Default value: (plugin managed)

The JWK used for the private_key_jwt authentication.

config.client_alg
optional

Type: array of string elements (one for each client)

Default value: (client_secret_jwt: “HS256”, private_key_jwt: “RS256”)

The algorithm to use for client_secret_jwt (only HS**) or private_key_jwt authentication:

  • HS256: HMAC using SHA-256
  • HS384: HMAC using SHA-384
  • HS512: HMAC using SHA-512
  • RS256: RSASSA-PKCS1-v1_5 using SHA-256
  • RS512: RSASSA-PKCS1-v1_5 using SHA-512
  • ES256: ECDSA using P-256 and SHA-256
  • ES384: ECDSA using P-384 and SHA-384
  • ES512: ECDSA using P-521 and SHA-512
  • PS256: RSASSA-PSS using SHA-256 and MGF1 with SHA-256
  • PS384: RSASSA-PSS using SHA-384 and MGF1 with SHA-384
  • PS512: RSASSA-PSS using SHA-512 and MGF1 with SHA-512
  • EdDSA: EdDSA with Ed25519



JWT Access Token Authentication
Parameters for setting where to search for the bearer token and whether to introspect them.
Form ParameterDescription
config.bearer_token_param_type
optional

Type: array of string elements

Default value: [“header”, “query”, “body”]

Where to search for the bearer token:

  • header: search the HTTP headers
  • query: search the URL’s query string
  • body: search the HTTP request body
  • cookie: search the HTTP request cookies specified with config.bearer_token_cookie_name

config.bearer_token_cookie_name
optional

Type: string

The name of the cookie in which the bearer token is passed.

config.introspect_jwt_tokens
optional

Type: boolean

Default value: false

Specifies whether to introspect the JWT access tokens (can be used to check for revocations).



Client Credentials Grant
Parameters for where to search for the client credentials.
Form ParameterDescription
config.client_credentials_param_type
optional

Type: array of string elements

Default value: [“header”, “query”, “body”]

Where to search for the client credentials:

  • header: search the HTTP headers
  • query: search the URL’s query string
  • body: search from the HTTP request body



Password Grant
Parameters for where to search for the username and password.
Form ParameterDescription
config.password_param_type
optional

Type: array of string elements

Default value: [“header”, “query”, “body”]

Where to search for the username and password:

  • header: search the HTTP headers
  • query: search the URL’s query string
  • body: search the HTTP request body



Refresh Token Grant
Parameters for where to search for the refresh token (rarely used as the refresh tokens are in many cases bound to the client).
Form ParameterDescription
config.refresh_token_param_type
optional

Type: array of string elements

Default value: [“header”, “query”, “body”]

Where to search for the refresh token:

  • header: search the HTTP headers
  • query: search the URL’s query string
  • body: search the HTTP request body

config.refresh_token_param_name
optional

Type: string

The name of the parameter used to pass the refresh token.



ID Token
Parameters for where to search for the id token (rarely sent as part of the request).
Form ParameterDescription
config.id_token_param_type
optional

Type: array of string elements

Default value: [“header”, “query”, “body”]

Where to search for the id token:

  • header: search the HTTP headers
  • query: search the URL’s query string
  • body: search the HTTP request body

config.id_token_param_name
optional

Type: string

The name of the parameter used to pass the id token.



Consumer Mapping
Parameters for mapping external identity provider managed identities to Kong managed ones.
Form ParameterDescription
config.admin_claim
optional

Type: string

The claim used for admin mapping for Kong Manager. Required if mapping IdP claims to Kong Manager admins.

config.consumer_claim
optional

Type: array of string elements

The claim used for consumer mapping.

config.consumer_by
optional

Type: array of string elements

Default value: [“username”, “custom_id”]

Consumer fields used for mapping:

  • id: try to find the matching Consumer by id
  • username: try to find the matching Consumer by username
  • custom_id: try to find the matching Consumer by custom_id

config.by_username_ignore_case
optional

Type: boolean

Default value: false

If consumer_by is set to username, specify whether username can match consumers case-insensitively.

config.consumer_optional
optional

Type: boolean

Default value: false

Do not terminate the request if consumer mapping fails.



Credential Mapping
Parameters for mapping external identity provider managed identities to a Kong credential (virtual in this case).
Form ParameterDescription
config.credential_claim
optional

Type: array of string elements

Default value: [“sub”]

The claim used to derive a virtual credential (for instance, for the rate-limiting plugin), in case the Consumer mapping is not used.



Issuer Verification
Form ParameterDescription
config.issuers_allowed
optional

Type: array of string elements

Default value: (discovered issuer)

The issuers allowed to be present in the tokens (iss claim).



Authorization
Form ParameterDescription
config.authenticated_groups_claim
optional

Type: array of string elements

The claim that contains authenticated groups. This setting can be used together with ACL plugin, but it also enables IdP managed groups with other applications and integrations (for example, Kong Manager and Dev Portal). The OpenID Connect plugin itself does not do anything other than set the context value.

config.scopes_required
optional

Type: array of string elements

Default value: (discovered issuer)

The scopes (scopes_claim claim) required to be present in the access token (or introspection results) for successful authorization. This config parameter works in both AND / OR cases.

  • When [“scope1 scope2”] are in the same array indices, both scope1 AND scope2 need to be present in access token (or introspection results).
  • When [“scope1”, “scope2”] are in different array indices, either scope1 OR scope2 need to be present in access token (or introspection results).

config.scopes_claim
optional

Type: array of string elements

Default value: [“scope”]

The claim that contains the scopes.

config.audience_required
optional

Type: array of string elements

The audiences (audience_claim claim) required to be present in the access token (or introspection results) for successful authorization. This config parameter works in both AND / OR cases.

  • When [“audience1 audience2”] are in the same array indices, both audience1 AND audience2 need to be present in access token (or introspection results).
  • When [“audience1”, “audience2”] are in different array indices, either audience1 OR audience2 need to be present in access token (or introspection results).

config.audience_claim
optional

Type: array of string elements

Default value: [“aud”]

The claim that contains the audience.

config.groups_required
optional

Type: array of string elements

The groups (groups_claim claim) required to be present in the access token (or introspection results) for successful authorization. This config parameter works in both AND / OR cases.

  • When [“group1 group2”] are in the same array indices, both group1 AND group2 need to be present in access token (or introspection results).
  • When [“group1”, “group2”] are in different array indices, either group1 OR group2 need to be present in access token (or introspection results).

config.groups_claim
optional

Type: array of string elements

Default value: [“groups”]

The claim that contains the groups.

config.roles_required
optional

Type: array of string elements

The roles (roles_claim claim) required to be present in the access token (or introspection results) for successful authorization. This config parameter works in both AND / OR cases.

  • When [“role1 role2”] are in the same array indices, both role1 AND role2 need to be present in access token (or introspection results).
  • When [“role1”, “role2”] are in different array indices, either role1 OR role2 need to be present in access token (or introspection results).

config.roles_claim
optional

Type: array of string elements

Default value: [“roles”]

The claim that contains the roles.



Claims Verification
Parameters for verification rules for standard claims.
Form ParameterDescription
config.verify_claims
optional

Type: boolean

Default value: true

Verify tokens for standard claims.

config.leeway
optional

Type: integer

Default value: 0

Allow some leeway on the ttl / expiry verification.

config.domains
optional

Type: array of string elements

The allowed values for the hd claim.

config.max_age
optional

Type: integer

The maximum age (in seconds) compared to the auth_time claim.

config.jwt_session_claim
optional

Type: string

Default value: “sid”

The claim to match against the JWT session cookie.

config.jwt_session_cookie
optional

Type: string

The name of the JWT session cookie.



Signature Verification
Form ParameterDescription
config.verify_signature
optional

Type: boolean

Default value: true

Verify signature of tokens.

config.enable_hs_signatures
optional

Type: boolean

Default value: false

Enable shared secret, for example, HS256, signatures (when disabled they will not be accepted).

config.ignore_signature
optional

Type: array of string elements

Skip the token signature verification on certain grants:

  • password: OAuth password grant
  • client_credentials: OAuth client credentials grant
  • authorization_code: authorization code flow
  • refresh_token: OAuth refresh token grant
  • session: session cookie authentication
  • introspection: OAuth introspection
  • userinfo: OpenID Connect user info endpoint authentication

config.extra_jwks_uris
optional

Type: array of string elements

JWKS URIs whose public keys are trusted (in addition to the keys found with the discovery).



Authorization Code Flow Verification
Form ParameterDescription
config.verify_nonce
optional

Type: boolean

Default value: true

Verify nonce on authorization code flow.



Introspection Verification
Form ParameterDescription
config.introspection_check_active
optional

Type: boolean

Default value: true

Check that the introspection response has an active claim with a value of true.



Configuration Verification
Form ParameterDescription
config.verify_parameters
optional

Type: boolean

Default value: false

Verify plugin configuration against discovery.



Upstream Headers
Parameters for the headers for the upstream service request.
Form ParameterDescription
config.upstream_headers_claims
optional

Type: array of string elements

The upstream header claims.

config.upstream_headers_names
optional

Type: array of string elements

The upstream header names for the claim values.

config.upstream_access_token_header
optional

Type: string

Default value: authorization:bearer

The upstream access token header.

config.upstream_access_token_jwk_header
optional

Type: string

The upstream access token JWK header.

config.upstream_id_token_header
optional

Type: string

The upstream id token header.

config.upstream_id_token_jwk_header
optional

Type: string

The upstream id token JWK header.

config.upstream_refresh_token_header
optional

Type: string

The upstream refresh token header.

config.upstream_user_info_header
optional

Type: string

The upstream user info header.

config.upstream_user_info_jwt_header
optional

Type: string

The upstream user info JWT header (in case the user info returns a JWT response).

config.upstream_introspection_header
optional

Type: string

The upstream introspection header.

config.upstream_introspection_jwt_header
optional

Type: string

The upstream introspection header (in case the introspection returns a JWT response).

config.upstream_session_id_header
optional

Type: string

The upstream session id header.



Downstream Headers
Parameters for the headers for the downstream response.
Form ParameterDescription
config.downstream_headers_claims
optional

Type: array of string elements

The downstream header claims.

config.downstream_headers_names
optional

Type: array of string elements

The downstream header names for the claim values.

config.downstream_access_token_header
optional

Type: string

Default value: authorization:bearer

The downstream access token header.

config.downstream_access_token_jwk_header
optional

Type: string

The downstream access token JWK header.

config.downstream_id_token_header
optional

Type: string

The downstream id token header.

config.downstream_id_token_jwk_header
optional

Type: string

The downstream id token JWK header.

config.downstream_refresh_token_header
optional

Type: string

The downstream refresh token header.

config.downstream_user_info_header
optional

Type: string

The downstream user info header.

config.downstream_user_info_jwt_header
optional

Type: string

The downstream user info JWT header (in case the user info returns a JWT response).

config.downstream_introspection_header
optional

Type: string

The downstream introspection header.

config.downstream_introspection_jwt_header
optional

Type: string

The downstream introspection header (in case the introspection returns a JWT response).

config.downstream_session_id_header
optional

Type: string

The downstream session id header.



Cross-Origin Resource Sharing (CORS)
Form ParameterDescription
config.run_on_preflight
optional

Type: boolean

Default value: true

Specifies whether to run this plugin on pre-flight (OPTIONS) requests.



Login
Parameters for what action the plugin completes after a successful login.
Form ParameterDescription
config.login_methods
optional

Type: array of string elements

Default value: [“authorization_code”]

Enable login functionality with specified grants:

  • password: enable for OAuth password grant
  • client_credentials: enable OAuth client credentials grant
  • authorization_code: enable for authorization code flow
  • bearer: enable for JWT access token authentication
  • introspection: enable for OAuth introspection authentication
  • userinfo: enable for OpenID Connect user info endpoint authentication
  • kong_oauth2: enable for Kong OAuth Plugin authentication
  • refresh_token: enable for OAuth refresh token grant
  • session: enable for session cookie authentication

config.login_action
optional

Type: string

Default value: “upstream”

What to do after successful login:

  • upstream: proxy request to upstream service
  • response: terminate request with a response
  • redirect: redirect to a different location

config.login_tokens
optional

Type: array of string elements

Default value: [“id_token”]

What tokens to include in response body or redirect query string or fragment:

  • id_token: include id token
  • access_token: include access token
  • refresh_token: include refresh token
  • tokens: include the full token endpoint response
  • introspection: include introspection response

config.login_redirect_mode
optional

Type: string

Default value: “fragment”

Where to place login_tokens when using redirect login_action:

  • query: place tokens in query string
  • fragment: place tokens in url fragment (not readable by servers)

config.login_redirect_uri
optional

Type: array of urls (one for each client)

Where to redirect the client when login_action is set to redirect.

Tip: Leave this empty and the plugin will redirect the client to the URL that originally initiated the flow with possible query args preserved from the original request when config.preserve_query_args is enabled.



Logout
Parameters for triggering logout with the plugin and the actions to take on logout.
Form ParameterDescription
config.logout_query_arg
optional

Type: string

The request query argument that activates the logout.

config.logout_post_arg
optional

Type: string

The request body argument that activates the logout.

config.logout_uri_suffix
optional

Type: string

The request URI suffix that activates the logout.

config.logout_methods
optional

Type: array of string elements

The request methods that can activate the logout:

  • POST: HTTP POST method
  • GET: HTTP GET method
  • DELETE: HTTP DELETE method

config.logout_revoke
optional

Type: boolean

Default value: false

Revoke tokens as part of the logout.

config.logout_revoke_access_token
optional

Type: boolean

Default value: true

Revoke the access token as part of the logout.

config.logout_revoke_refresh_token
optional

Type: boolean

Default value: true

Revoke the refresh token as part of the logout.

config.logout_redirect_uri
optional

Type: array of urls (one for each client)

Where to redirect the client after the logout.



Unauthorized
Parameters for how to handle unauthorized requests.
Form ParameterDescription
config.unauthorized_redirect_uri
optional

Type: array of urls (one for each client)

Where to redirect the client on unauthorized requests.

config.unauthorized_error_message
optional

Type: string

Default value: “Forbidden”

The error message for the unauthorized requests (when not using the redirection).



Forbidden
Parameters for how to handle forbidden requests.
Form ParameterDescription
config.forbidden_redirect_uri
optional

Type: array of urls (one for each client)

Where to redirect the client on forbidden requests.

config.forbidden_error_message
optional

Type: string

Default value: “Forbidden”

The error message for the forbidden requests (when not using the redirection).

config.forbidden_destroy_session
optional

Type: boolean

Default value: true

Destroy the possible session for the forbidden requests.



Errors
Parameters for how to handle unexpected errors.
Form ParameterDescription
config.unexpected_redirect_uri
optional

Type: array of urls (one for each client)

Where to redirect the client when unexpected errors happen with the requests.

config.display_errors
optional

Type: boolean

Default value: false

Display errors on failure responses.



Authorization Cookie
Parameters used during authorization code flow for verification and preserving settings.
Form ParameterDescription
config.authorization_cookie_name
optional

Type: string

Default value: “authorization”

The authorization cookie name.

config.authorization_cookie_lifetime
optional

Type: integer

Default value: 600

The authorization cookie lifetime in seconds.

config.authorization_cookie_path
optional

Type: string

Default value: ”/”

The authorization cookie Path flag.

config.authorization_cookie_domain
optional

Type: string

The authorization cookie Domain flag.

config.authorization_cookie_samesite
optional

Type: string

Default value: “off”

Controls whether a cookie is sent with cross-origin requests, providing some protection against cross-site request forgery attacks:

  • Strict: Cookies will only be sent in a first-party context and not be sent along with requests initiated by third party websites.
  • Lax: Cookies are not sent on normal cross-site subrequests (for example to load images or frames into a third party site), but are sent when a user is navigating to the origin site (for instance, when following a link).
  • None: Cookies will be sent in all contexts, for example in responses to both first-party and cross-origin requests. If SameSite=None is set, the cookie Secure attribute must also be set (or the cookie will be blocked).
  • off: Do not set the Same-Site flag.

config.authorization_cookie_httponly
optional

Type: boolean

Default value: true

Forbids JavaScript from accessing the cookie, for example, through the Document.cookie property.

config.authorization_cookie_secure
optional

Type: boolean

Default value: (from the request scheme)

Cookie is only sent to the server when a request is made with the https: scheme (except on localhost), and therefore is more resistant to man-in-the-middle attacks.



Session Cookie
Parameters used with the session cookie authentication.
Form ParameterDescription
config.session_cookie_name
optional

Type: string

Default value: “session”

The session cookie name.

config.session_cookie_lifetime
optional

Type: integer

Default value: 3600

The session cookie lifetime in seconds.

config.session_cookie_idletime
optional

Type: integer

The session cookie idle time in seconds.

config.session_cookie_renew
optional

Type: integer

Default value: 600

The session cookie renew time.

config.session_cookie_path
optional

Type: string

Default value: ”/”

The session cookie Path flag.

config.session_cookie_domain
optional

Type: string

The session cookie Domain flag.

config.session_cookie_samesite
optional

Type: string

Default value: “Lax”

Controls whether a cookie is sent with cross-origin requests, providing some protection against cross-site request forgery attacks:

  • Strict: Cookies will only be sent in a first-party context and not be sent along with requests initiated by third party websites.
  • Lax: Cookies are not sent on normal cross-site subrequests (for example to load images or frames into a third party site), but are sent when a user is navigating to the origin site (for example, when following a link).
  • None: Cookies will be sent in all contexts, for example in responses to both first-party and cross-origin requests. If SameSite=None is set, the cookie Secure attribute must also be set (or the cookie will be blocked)
  • off: Do not set the Same-Site flag.

config.session_cookie_httponly
optional

Type: boolean

Default value: true

Forbids JavaScript from accessing the cookie, for example, through the Document.cookie property.

config.session_cookie_secure
optional

Type: boolean

Default value: (from the request scheme)

Cookie is only sent to the server when a request is made with the https: scheme (except on localhost), and therefore is more resistant to man-in-the-middle attacks.

config.session_cookie_maxsize
optional

Type: integer

Default value: 4000

The maximum size of each cookie chunk in bytes.



Session Settings
Form ParameterDescription
config.session_secret
optional

Type: string

Default value: (with database, or traditional mode, the value is auto-generated and stored along the issuer discovery information in the database)

The session secret.

This field is referenceable, which means it can be securely stored as a secret in a vault. References must follow a specific format.

If keyring database encryption is enabled, this value will be encrypted.

config.disable_session
optional

Type: array of string elements

Disable issuing the session cookie with the specified grants:

  • password: do not start a session with the password grant
  • client_credentials: do not start a session with the client credentials grant
  • authorization_code: do not start a session after authorization code flow
  • bearer: do not start session with JWT access token authentication
  • introspection: do not start session with introspection authentication
  • userinfo: do not start session with user info authentication
  • kong_oauth2: do not start session with Kong OAuth authentication
  • refresh_token do not start session with refresh token grant
  • session: do not renew the session with session cookie authentication

config.session_strategy
optional

Type: string

Default value: “default”

The session strategy:

  • default: reuses session identifiers over modifications (but can be problematic with single-page applications with a lot of concurrent asynchronous requests)
  • regenerate: generates a new session identifier on each modification and does not use expiry for signature verification (useful in single-page applications or SPAs)

config.session_compressor
optional

Type: string

Default value: “default”

The session strategy:

  • none: no compression
  • zlib: use zlib to compress cookie data

config.session_storage
optional

Type: string

Default value: “cookie”

The session storage for session data:

  • cookie: stores session data with the session cookie (the session cannot be invalidated or revoked without changing session secret, but is stateless, and doesn’t require a database)
  • memcache: stores session data in memcached
  • redis: stores session data in Redis

config.reverify
optional

Type: boolean

Default value: false

Specifies whether to always verify tokens stored in the session.



Session Settings for Memcached
Form ParameterDescription
config.session_memcache_prefix
optional

Type: string

Default value: “sessions”

The memcached session key prefix.

config.session_memcache_socket
optional

Type: string

The memcached unix socket path.

config.session_memcache_host
optional

Type: string

Default value: “127.0.0.1”

The memcached host.

config.session_memcache_port
optional

Type: integer

Default value: 11211

The memcached port.



Session Settings for Redis
Form ParameterDescription
config.session_redis_prefix
optional

Type: string

Default value: “sessions”

The Redis session key prefix.

config.session_redis_socket
optional

Type: string

The Redis unix socket path.

config.session_redis_host
optional

Type: string

Default value: “127.0.0.1”

The Redis host

config.session_redis_port
optional

Type: integer

Default value: 6379

The Redis port.

config.session_redis_username
optional

Type: string

Username to use for Redis connection when the redis session storage is defined and ACL authentication is desired. If undefined, ACL authentication will not be performed. This requires Redis v6.0.0+.

This field is referenceable, which means it can be securely stored as a secret in a vault. References must follow a specific format.

config.session_redis_password
optional

Type: string

Default value: (from kong)

Password to use for Redis connection when the redis session storage is defined. If undefined, no AUTH commands are sent to Redis.

This field is referenceable, which means it can be securely stored as a secret in a vault. References must follow a specific format.

If keyring database encryption is enabled, this value will be encrypted.

config.session_redis_auth
optional

Type: string

Default value: (from kong)

Password to use for Redis connection when the redis session storage is defined. If undefined, no AUTH commands are sent to Redis.

If keyring database encryption is enabled, this value will be encrypted.

config.session_redis_connect_timeout
optional

Type: integer

Default value: (from kong)

The Redis connection timeout in milliseconds.

config.session_redis_read_timeout
optional

Type: integer

Default value: (from kong)

The Redis read timeout in milliseconds.

config.session_redis_send_timeout
optional

Type: integer

Default value: (from kong)

The Redis send timeout in milliseconds.

config.session_redis_ssl
optional

Type: boolean

Default value: false

Use SSL/TLS for Redis connection.

config.session_redis_ssl_verify
optional

Type: boolean

Default value: false

Verify Redis server certificate.

config.session_redis_server_name
optional

Type: string

The SNI used for connecting the Redis server.

config.session_redis_cluster_nodes
optional

Type: array of host records

The Redis cluster node host. Takes an array of host records, with either ip or host, and port values.

config.session_redis_cluster_maxredirections
optional

Type: integer

The Redis cluster maximum redirects.



Endpoints
Parameters normally not needed as the endpoints are discovered.
Form ParameterDescription
config.authorization_endpoint
optional

Type: url

Default value: (discovered uri)

The authorization endpoint.

config.token_endpoint
optional

Type: url

Default value: (discovered uri)

The token endpoint.

config.introspection_endpoint
optional

Type: url

Default value: (discovered uri)

The introspection endpoint.

config.revocation_endpoint
optional

Type: url

Default value: (discovered uri)

The revocation endpoint.

config.userinfo_endpoint
optional

Type: url

Default value: (discovered uri)

The user info endpoint.

config.end_session_endpoint
optional

Type: url

Default value: (discovered uri)

The end session endpoint.

config.token_exchange_endpoint
optional

Type: url

Default value: (discovered uri)

The token exchange endpoint.



Endpoint Authentication
Parameters normally not needed as the client authentication can be specified for the client.
Form ParameterDescription
config.token_endpoint_auth_method
optional

Type: string

Default value: (see: config.client_auth)

The token endpoint authentication method:

  • client_secret_basic: send client_id and client_secret in Authorization: Basic header
  • client_secret_post: send client_id and client_secret as part of the body
  • client_secret_jwt: send client assertion signed with the client_secret as part of the body
  • private_key_jwt: send client assertion signed with the private key as part of the body
  • none: do not authenticate

config.introspection_endpoint_auth_method
optional

Type: string

Default value: (see: config.client_auth)

The introspection endpoint authentication method:

  • client_secret_basic: send client_id and client_secret in Authorization: Basic header
  • client_secret_post: send client_id and client_secret as part of the body
  • client_secret_jwt: send client assertion signed with the client_secret as part of the body
  • private_key_jwt: send client assertion signed with the private key as part of the body
  • none: do not authenticate

config.revocation_endpoint_auth_method
optional

Type: string

Default value: (see: config.client_auth)

The revocation endpoint authentication method:

  • client_secret_basic: send client_id and client_secret in Authorization: Basic header
  • client_secret_post: send client_id and client_secret as part of the body
  • client_secret_jwt: send client assertion signed with the client_secret as part of the body
  • private_key_jwt: send client assertion signed with the private key as part of the body
  • none: do not authenticate



Discovery Endpoint Arguments
Form ParameterDescription
config.discovery_headers_names
optional

Type: array of string elements

Extra header names passed to the discovery endpoint.

config.discovery_headers_values
optional

Type: array of string elements

Extra header values passed to the discovery endpoint.



Authorization Endpoint Arguments
Form ParameterDescription
config.response_mode
optional

Type: string

Default value: “query”

The response mode passed to the authorization endpoint:

  • query: Instructs the identity provider to pass parameters in query string
  • form_post: Instructs the identity provider to pass parameters in request body
  • fragment: Instructs the identity provider to pass parameters in uri fragment (rarely useful as the plugin itself cannot read it)

config.response_type
optional

Type: array of string elements

Default value: [“code”]

The response type passed to the authorization endpoint.

config.scopes
optional

Type: array of string elements

Default value: [“openid”]

The scopes passed to the authorization and token endpoints.

config.audience
optional

Type: array of string elements

The audience passed to the authorization endpoint.

config.redirect_uri
optional

Type: array of urls (one for each client)

Default value: (request uri)

The redirect URI passed to the authorization and token endpoints.

config.authorization_query_args_names
optional

Type: array of string elements

Extra query argument names passed to the authorization endpoint.

config.authorization_query_args_values
optional

Type: array of string elements

Extra query argument values passed to the authorization endpoint.

config.authorization_query_args_client
optional

Type: array of string elements

Extra query arguments passed from the client to the authorization endpoint.



Token Endpoint Arguments
Form ParameterDescription
config.token_headers_names
optional

Type: array of string elements

Extra header names passed to the token endpoint.

config.token_headers_values
optional

Type: array of string elements

Extra header values passed to the token endpoint.

config.token_headers_client
optional

Type: array of string elements

Extra headers passed from the client to the token endpoint.

config.token_post_args_names
optional

Type: array of string elements

Extra post argument names passed to the token endpoint.

config.token_post_args_values
optional

Type: array of string elements

Extra post argument values passed to the token endpoint.

config.token_post_args_client
optional

Type: array of string elements

Extra post arguments passed from the client to the token endpoint.



Token Endpoint Response Headers
Parameters for an uncommon use case of sending certain token endpoint headers to the downstream client.
Form ParameterDescription
config.token_headers_replay

Type: array of string elements

The names of token endpoint response headers to forward to the downstream client.

config.token_headers_prefix

Type: string

Add a prefix to the token endpoint response headers before forwarding them to the downstream client.

config.token_headers_grants

Type: array of string elements

Enable the sending of the token endpoint response headers only with certain granst:

  • password: with OAuth password grant
  • client_credentials: with OAuth client credentials grant
  • authorization_code: with authorization code flow
  • refresh_token with refresh token grant



Introspection Endpoint Arguments
Form ParameterDescription
config.introspection_hint
optional

Type: string

Default value: “access_token”

Introspection hint parameter value passed to the introspection endpoint.

config.introspection_accept
optional

Type: string

Default value: “application/json”

The value of Accept header for introspection requests:

  • application/json: introspection response as JSON
  • application/token-introspection+jwt: introspection response as JWT (from the current IETF draft document)
  • application/jwt: introspection response as JWT (from the obsolete IETF draft document)

config.introspection_headers_names
optional

Type: array of string elements

Extra header names passed to the introspection endpoint.

config.introspection_headers_values
optional

Type: array of string elements

Extra header values passed to the introspection endpoint.

config.introspection_headers_client
optional

Type: array of string elements

Extra headers passed from the client to the introspection endpoint.

config.introspection_post_args_names
optional

Type: array of string elements

Extra post argument names passed to the introspection endpoint.

config.introspection_post_args_values
optional

Type: array of string elements

Extra post argument values passed to the introspection endpoint.

config.introspection_post_args_client
optional

Type: array of string elements

Extra post arguments passed from the client to the introspection endpoint.



User Info Endpoint Arguments
Form ParameterDescription
config.userinfo_accept
optional

Type: string

Default value: “application/json”

The value of Accept header for user info requests:

  • application/json: user info response as JSON
  • application/jwt: user info response as JWT (from the obsolete IETF draft document)

config.userinfo_headers_names
optional

Type: array of string elements

Extra header names passed to the user info endpoint.

config.userinfo_headers_values
optional

Type: array of string elements

Extra header values passed to the user info endpoint.

config.userinfo_headers_client
optional

Type: array of string elements

Extra headers passed from the client to the user info endpoint.

config.userinfo_query_args_names
optional

Type: array of string elements

Extra query argument names passed to the user info endpoint.

config.userinfo_query_args_values
optional

Type: array of string elements

Extra query argument values passed to the user info endpoint.

config.userinfo_query_args_client
optional

Type: array of string elements

Extra query arguments passed from the client to the user info endpoint.



HTTP Client
Parameters for generic settings for the HTTP client when the plugin needs to interact with the identity provider.
Form ParameterDescription
config.keepalive
optional

Type: boolean

Default value: true

Use keepalive with the HTTP client.

config.ssl_verify
optional

Type: boolean

Default value: false

Verify identity provider server certificate.

config.timeout
optional

Type: integer

Default value: 10000

Network IO timeout in milliseconds.

config.http_version
optional

Type: number

Default value: 1.1

The HTTP version used for the requests by this plugin:

  • 1.1: HTTP 1.1 (the default)
  • 1.0: HTTP 1.0



HTTP Client Proxy Settings
Parameters only needed if the HTTP(S) requests to identity provider need to go through a proxy server.
Form ParameterDescription
config.http_proxy
optional

Type: url

The HTTP proxy

config.http_proxy_authorization
optional

Type: string

The HTTP proxy authorization.

config.https_proxy
optional

Type: url

The HTTPS proxy

config.https_proxy_authorization
optional

Type: string

The HTTPS proxy authorization.

config.no_proxy
optional

Type: array of string elements

Do not use proxy with these hosts.



Cache TTLs
Form ParameterDescription
config.cache_ttl
optional

Type: integer

Default value: 3600

The default cache ttl in seconds that is used in case the cached object does not specify the expiry.

config.cache_ttl_max
optional

Type: integer

The maximum cache ttl in seconds (enforced).

config.cache_ttl_min
optional

Type: integer

The minimum cache ttl in seconds (enforced).

config.cache_ttl_neg
optional

Type: integer

Default value: (derived from Kong configuration)

The negative cache ttl in seconds.

config.cache_ttl_resurrect
optional

Type: integer

Default value: (derived from Kong configuration)

The resurrection ttl in seconds.



Cache Settings for the Endpoints
Form ParameterDescription
config.cache_tokens
optional

Type: boolean

Default value: true

Cache the token endpoint requests.

config.cache_tokens_salt
optional

Type: string

Default value: (auto generated)

Salt used for generating the cache key that us used for caching the token endpoint requests.

If you use multiple plugin instances of the OpenID Connect plugin and want to share token endpoint caches between the plugin instances, set the salt to the same value on each plugin instance.

config.cache_introspection
optional

Type: boolean

Default value: true

Cache the introspection endpoint requests.

config.cache_token_exchange
optional

Type: boolean

Default value: true

Cache the token exchange endpoint requests.

config.cache_user_info
optional

Type: boolean

Default value: true

Cache the user info requests.

config.resolve_distributed_claims
optional

Type: boolean

Default value: false

Distributed claims are represented by the _claim_names and _claim_sources members of the JSON object containing the claims. If this parameter is set to true, the plugin explicitly resolves these distributed claims.


Records

In the above parameter list, two configuration settings used an array of records as a data type:

  • config.client_jwk: array of JWK records (one for each client)
  • config.session_redis_cluster_nodes: array of host records, either as IP addresses or hostnames, and their ports.

Below are descriptions of the record types.

JWK Record

The JSON Web Key (JWK) record is specified in RFC7571. This record is used with the config.client_jwk when using private_key_jwk client authentication.

Here is an example of JWK record generated by the plugin itself (see: JSON Web Key Set:

  1. {
  2. "kid": "B2FxBJ8G_e61tnZEfaYpaMLjswjNO3dbVEQhR7-i_9s",
  3. "kty": "RSA",
  4. "alg": "RS256",
  5. "use": "sig"
  6. "e": "AQAB",
  7. "n": "…",
  8. "d": "…",
  9. "p": "…",
  10. "q": "…",
  11. "dp": "…",
  12. "dq": "…",
  13. "qi": "…"
  14. }

Host Record

The Host record used with the config.session_redis_cluster_nodes is simple. It contains ip or host, and the port where the port defaults to 6379.

Here is an example of Host the record:

  1. {
  2. "ip": "127.0.0.1"
  3. "port": 6379
  4. }

Admin API

The OpenID Connect plugin extends the Kong Admin API with a few endpoints.

Discovery Cache

When configuring the plugin using config.issuer, the plugin will store the fetched discovery information to the Kong database, or in the worker memory with Db-less.

Discovery Cache Object
  1. {
  2. "id": "<uuid>",
  3. "issuer": "<config.issuer>"
  4. "created_at": <timestamp>,
  5. "configuration": {
  6. <discovery>
  7. },
  8. "keys": [
  9. <keys>
  10. ]
  11. }

List All Discovery Cache Objects

/openid-connect/issuers

Response
  1. HTTP 200 OK
  1. {
  2. "data": [{
  3. "id": "<uuid>",
  4. "issuer": "<config.issuer>"
  5. "created_at": <timestamp>,
  6. "configuration": {
  7. <discovery>
  8. },
  9. "keys": [
  10. <keys>
  11. ]
  12. }],
  13. "next": null
  14. }

Retrieve Discovery Cache Object

/openid-connect/issuers/{issuer or id}

AttributesDescription
issuer or id
required
The unique identifier or the value of config.issuer
Response
  1. HTTP 200 OK
  1. {
  2. "id": "<uuid>",
  3. "issuer": "<config.issuer>"
  4. "created_at": <timestamp>,
  5. "configuration": {
  6. <discovery>
  7. },
  8. "keys": [
  9. <keys>
  10. ]
  11. }

Delete All Discovery Cache Objects

/openid-connect/issuers

Response
  1. HTTP 204 No Content

Note: The automatically generated session secret (that can be overridden with the config.session_secret) is stored with the discovery cache objects. Deleting discovery cache objects will invalidate all the sessions created with the associated secret.

Delete Discovery Cache Object

/openid-connect/issuers/{issuer or id}

AttributesDescription
issuer or id
required
The unique identifier or the value of config.issuer
Response
  1. HTTP 204 No Content

JSON Web Key Set

When the OpenID Connect client (the plugin) is set to communicate with the identity provider endpoints using private_key_jwt, the plugin needs to use public key cryptography. Thus, the plugin needs to generate the needed keys. Identity provider on the other hand has to verify that the assertions used for the client authentication.

The plugin will automatically generate the key pairs for the different algorithms. It will also publish the public keys with the admin api where the identity provider could fetch them.

  1. {
  2. "keys": [{
  3. <keys>
  4. }]
  5. }

Retrieve JWKS

/openid-connect/jwks

This endpoint will return a standard JWK Set document with the private keys stripped out.

Response
  1. HTTP 200 OK
  1. {
  2. "keys": [{
  3. <keys>
  4. }]
  5. }

Rotate JWKS

/openid-connect/jwks

Deleting JWKS will also cause auto-generation of a new JWK set, so DELETE will actually cause a key rotation.

Response
  1. HTTP 204 No Content

Preparations

The OpenID Connect plugin relies in most cases on a 3rd party identity provider. In this section, we explain configuration of Keycloak and Kong.

All the *.test domains in the following examples point to the localhost (127.0.0.1 and/or ::1).

Keycloak Configuration

We use Keycloak as the identity provider in the following examples, but the steps will be similar in other standard identity providers. If you encounter difficulties during this phase, please refer to the Keycloak documentation.

  1. Create a confidential client kong with private_key_jwt authentication and point the Keycloak to download the public keys from the OpenID Connect Plugin JWKS endpoint:

    OpenID Connect Plugin Reference - 图1
    OpenID Connect Plugin Reference - 图2

  2. Create another confidential client service with client_secret_basic authentication, and the secret of cf4c655a-0622-4ce6-a0de-d3353ef0b714 (Keycloak auto-generates one), and enable the client credentials grant for the client:

    OpenID Connect Plugin Reference - 图3
    OpenID Connect Plugin Reference - 图4

  3. Create verified user john with the non-temporary password doe that we can use with the password grant:

    OpenID Connect Plugin Reference - 图5

Alternatively you can download the exported Keycloak configuration, and use it to configure the Keycloak. Please refer to Keycloak import documentation for more information.

You need to modify Keycloak standalone.xml configuration file, and change the socket binding from:

  1. <socket-binding name="https" port="${jboss.https.port:8443}"/>

to

  1. <socket-binding name="https" port="${jboss.https.port:8440}"/>

The Keycloak default https port conflicts with the default Kong TLS proxy port, and that can be a problem if both are started on a single host.

Kong Configuration

Create a Service

  1. http -f put :8001/services/openid-connect url=http://httpbin.org/anything
  1. HTTP/1.1 200 OK
  1. {
  2. "id": "5fa9e468-0007-4d7e-9aeb-49ca9edd6ccd",
  3. "name": "openid-connect",
  4. "protocol": "http",
  5. "host": "httpbin.org",
  6. "port": 80,
  7. "path": "/anything"
  8. }

Create a Route

  1. http -f put :8001/services/openid-connect/routes/openid-connect paths=/
  1. HTTP/1.1 200 OK
  1. {
  2. "id": "ac1e86bd-4bce-4544-9b30-746667aaa74a",
  3. "name": "openid-connect",
  4. "paths": [ "/" ]
  5. }

Create a Plugin

You may execute this before patching the plugin (as seen on following examples) to reset the plugin configuration.

  1. http -f put :8001/plugins/5f35b796-ced6-4c00-9b2a-90eef745f4f9 \
  2. name=openid-connect \
  3. service.name=openid-connect \
  4. config.issuer=http://keycloak.test:8080/auth/realms/master \
  5. config.client_id=kong \
  6. config.client_auth=private_key_jwt
  1. HTTP/1.1 200 OK
  1. {
  2. "id": "5f35b796-ced6-4c00-9b2a-90eef745f4f9",
  3. "name": "openid-connect",
  4. "service": {
  5. "id": "5fa9e468-0007-4d7e-9aeb-49ca9edd6ccd"
  6. },
  7. "config": {
  8. "issuer": "http://keycloak.test:8080/auth/realms/master",
  9. "client_id": [ "kong" ],
  10. "client_auth": [ "private_key_jwt" ]
  11. }
  12. }

Also, check the discovery cache: http :8001/openid-connect/issuers. It should contain Keycloak OpenID Connect discovery document, and the keys.

Summary

At this point we have:

  1. Created a Service
  2. Routed traffic to the service
  3. Enabled OpenID Connect plugin on the service

Follow up on next sections to enable OpenID Connect plugin for specific grants or flows.

Authentication

Before you proceed, check that you have done the preparations.

We use HTTPie to execute the examples. The output is stripped for a better readability. httpbin.org is used as an upstream service.

Using Admin API is convenient when testing the plugin, but similar configs can be done in declarative format as well.

When plugin is configured with multiple grants / flows there is a hard-coded search order for the credentials:

  1. Session Authentication
  2. JWT Access Token Authentication
  3. Kong OAuth Token Authentication
  4. Introspection Authentication
  5. User Info Authentication
  6. Refresh Token Grant
  7. Password Grant
  8. Client Credentials Grant
  9. Authorization Code Flow

In case plugin finds credentials, it will stop searching other credentials. Some grants may use the same credentials, in other words, both password and client credentials grants can use credentials from basic authentication header.

Because the httpbin.org is used as an upstream service, it is highly recommend that you do not run these usage examples with a production identity provider as there is great a chance of leaking information. Also the examples below use the plain HTTP protocol that you should never use in production. The choices here are for simplicity.

Authorization Code Flow

The authorization code flow is the three-legged OAuth/OpenID Connect flow. The sequence diagram below, describes the participants, and their interactions for this usage scenario, including the use of session cookies:

OpenID Connect Plugin Reference - 图6

Patch the Plugin

Let’s patch the plugin that we created in the Kong configuration step:

  1. We want to only use the authorization code flow and the session authentication.
  2. We want to set the response mode to form_post so that authorization codes won’t get logged to the access logs.
  3. We want to preserve the original request query arguments over the authorization code flow redirections.
  4. We want to redirect the client to original request url after the authorization code flow so that the POST request (because of form_post) is turned to the GET request, and the browser address bar is updated with the original request query arguments.
  5. We don’t want to include any tokens in the browser address bar.

Reset the plugin configuration before patching.

  1. http -f patch :8001/plugins/5f35b796-ced6-4c00-9b2a-90eef745f4f9 \
  2. config.auth_methods=authorization_code \
  3. config.auth_methods=session \
  4. config.response_mode=form_post \
  5. config.preserve_query_args=true \
  6. config.login_action=redirect \
  7. config.login_tokens=
  1. HTTP/1.1 200 OK
  1. {
  2. "id": "5f35b796-ced6-4c00-9b2a-90eef745f4f9",
  3. "name": "openid-connect",
  4. "service": {
  5. "id": "5fa9e468-0007-4d7e-9aeb-49ca9edd6ccd"
  6. },
  7. "config": {
  8. "auth_methods": [
  9. "authorization_code",
  10. "session"
  11. ],
  12. "login_action": "redirect",
  13. "preserve_query_args": true,
  14. "login_tokens": null
  15. }
  16. }

Test the Authorization Code Flow

  1. Open the Service Page with some query arguments:

    1. open http://service.test:8000/?hello=world

    OpenID Connect Plugin Reference - 图7

  2. See that the browser is redirected to the Keycloak login page:

    OpenID Connect Plugin Reference - 图8

    You may examine the query arguments passed to Keycloak with the browser developer tools.

  3. And finally you will be presented a response from httpbin.org:

    OpenID Connect Plugin Reference - 图9

  4. Done.

It looks rather simple from the user point of view, but what really happened is described in the diagram above.

Password Grant

Password grant is a legacy authentication grant. The password grant is a less secure way to authenticate the end users than the authorization code flow. For example, the passwords get shared with 3rd parties. The grant is rather simple though:

OpenID Connect Plugin Reference - 图10

Patch the Plugin

Let’s patch the plugin that we created in the Kong configuration step:

  1. We want to only use the password grant.
  2. We want to search credentials for password grant from the headers only.

Reset the plugin configuration before patching.

  1. http -f patch :8001/plugins/5f35b796-ced6-4c00-9b2a-90eef745f4f9 \
  2. config.auth_methods=password \
  3. config.password_param_type=header
  1. HTTP/1.1 200 OK
  1. {
  2. "id": "5f35b796-ced6-4c00-9b2a-90eef745f4f9",
  3. "name": "openid-connect",
  4. "service": {
  5. "id": "5fa9e468-0007-4d7e-9aeb-49ca9edd6ccd"
  6. },
  7. "config": {
  8. "auth_methods": [ "password" ],
  9. "password_param_type": [ "header" ]
  10. }
  11. }

Test the Password Grant

  1. Request the service with basic authentication credentials created in the Keycloak configuration step:

    1. http -v -a john:doe :8000
    1. GET / HTTP/1.1
    2. Authorization: Basic BEkg3bHT0ERXFmKr1qelBQYrLBeHb5Hr
    1. HTTP/1.1 200 OK
    1. {
    2. "headers": {
    3. "Authorization": "Bearer <access-token>"
    4. },
    5. "method": "GET"
    6. }
  2. Done.

If you make another request using the same credentials, you should see that Kong adds less latency to the request as it has cached the token endpoint call to Keycloak.

Client Credentials Grant

Client credentials grant is almost the same as the password grant, but the biggest difference with the Kong OpenID Connect plugin is that the plugin itself does not try to authenticate. It just forwards the credentials passed by the client to the identity server’s token endpoint. The client credentials grant is visualized below:

OpenID Connect Plugin Reference - 图11

Patch the Plugin

Let’s patch the plugin that we created in the Kong configuration step:

  1. We want to only use the client credentials grant.
  2. We want to search credentials for client credentials from the headers only.

Reset the plugin configuration before patching.

  1. http -f patch :8001/plugins/5f35b796-ced6-4c00-9b2a-90eef745f4f9 \
  2. config.auth_methods=client_credentials \
  3. config.client_credentials_param_type=header
  1. HTTP/1.1 200 OK
  1. {
  2. "id": "5f35b796-ced6-4c00-9b2a-90eef745f4f9",
  3. "name": "openid-connect",
  4. "service": {
  5. "id": "5fa9e468-0007-4d7e-9aeb-49ca9edd6ccd"
  6. },
  7. "config": {
  8. "auth_methods": [ "client_credentials" ],
  9. "client_credentials_param_type": [ "header" ]
  10. }
  11. }

Test the Client Credentials Grant

  1. Request the service with client credentials created in the Keycloak configuration step:

    1. http -v -a service:cf4c655a-0622-4ce6-a0de-d3353ef0b714 :8000
    1. GET / HTTP/1.1
    2. Authorization: Basic c2VydmljZTpjZjRjNjU1YS0wNjIyLTRjZTYtYTBkZS1kMzM1M2VmMGI3MTQ=
    1. HTTP/1.1 200 OK
    1. {
    2. "headers": {
    3. "Authorization": "Bearer <access-token>"
    4. },
    5. "method": "GET"
    6. }
  2. Done.

If you make another request using the same credentials, you should see that Kong adds less latency to the request as it has cached the token endpoint call to Keycloak.

Refresh Token Grant

The refresh token grant can be used when the client has a refresh token available. There is a caveat with this: identity providers in general only allow refresh token grant to be executed with the same client that originally got the refresh token, and if there is a mismatch, it may not work. The mismatch is likely when Kong OpenID Connect is configured to use one client, and the refresh token is retrieved with another. The grant itself is very similar to password grant and client credentials grant:

OpenID Connect Plugin Reference - 图12

Patch the Plugin

Let’s patch the plugin that we created in the Kong configuration step:

  1. We want to only use the refresh token grant, but we also enable the password grant for demoing purposes
  2. We want to search the refresh token for the refresh token grant from the headers only.
  3. We want to pass refresh token from the client in Refresh-Token header.
  4. We want to pass refresh token to upstream in Refresh-Token header.

Reset the plugin configuration before patching.

  1. http -f patch :8001/plugins/5f35b796-ced6-4c00-9b2a-90eef745f4f9 \
  2. config.refresh_token_param_name=refresh_token \
  3. config.refresh_token_param_type=header \
  4. config.auth_methods=refresh_token \
  5. config.auth_methods=password \
  6. config.upstream_refresh_token_header=refresh_token
  1. HTTP/1.1 200 OK
  1. {
  2. "id": "5f35b796-ced6-4c00-9b2a-90eef745f4f9",
  3. "name": "openid-connect",
  4. "service": {
  5. "id": "5fa9e468-0007-4d7e-9aeb-49ca9edd6ccd"
  6. },
  7. "config": {
  8. "auth_methods": [
  9. "refresh_token",
  10. "password"
  11. ],
  12. "refresh_token_param_name": "refresh_token",
  13. "refresh_token_param_type": [ "header" ],
  14. "upstream_refresh_token_header": "refresh_token"
  15. }
  16. }

The config.auth_methods and config.upstream_refresh_token_header are only enabled for demoing purposes so that we can get a refresh token with:

  1. http -a john:doe :8000 | jq -r '.headers."Refresh-Token"'

Output:

  1. <refresh-token>

We can use the output in Refresh-Token header.

Test the Refresh Token Grant

  1. Request the service with a bearer token:

    1. http -v :8000 Refresh-Token:$(http -a john:doe :8000 | \
    2. jq -r '.headers."Refresh-Token"')

    or

    1. http -v :8000 Refresh-Token:"<refresh-token>"
    1. GET / HTTP/1.1
    2. Refresh-Token: <refresh-token>
    1. HTTP/1.1 200 OK
    1. {
    2. "headers": {
    3. "Authorization": "Bearer <access-token>",
    4. "Refresh-Token": "<refresh-token>"
    5. },
    6. "method": "GET"
    7. }
  2. Done.

JWT Access Token Authentication

For legacy reasons, the stateless JWT Access Token authentication is named bearer with the Kong OpenID Connect plugin (see: config.auth_methods). Stateless authentication basically means the signature verification using the identity provider published public keys and the standard claims’ verification (such as exp (or expiry)). The client may have received the token directly from the identity provider or by other means. It is simple:

OpenID Connect Plugin Reference - 图13

Patch the Plugin

Let’s patch the plugin that we created in the Kong configuration step:

  1. We want to only use the bearer authentication, but we also enable the password grant for demoing purposes
  2. We want to search the bearer token for the bearer authentication from the headers only.

Reset the plugin configuration before patching.

  1. http -f patch :8001/plugins/5f35b796-ced6-4c00-9b2a-90eef745f4f9 \
  2. config.bearer_token_param_type=header \
  3. config.auth_methods=bearer \
  4. config.auth_methods=password # only enabled for demoing purposes
  1. HTTP/1.1 200 OK
  1. {
  2. "id": "5f35b796-ced6-4c00-9b2a-90eef745f4f9",
  3. "name": "openid-connect",
  4. "service": {
  5. "id": "5fa9e468-0007-4d7e-9aeb-49ca9edd6ccd"
  6. },
  7. "config": {
  8. "auth_methods": [
  9. "bearer",
  10. "password"
  11. ],
  12. "bearer_token_param_type": [ "header" ]
  13. }
  14. }

The password grant is enabled so that we can get a JWT access token that we can use to show how the JWT access token authentication works. That is: we need a token. One way to get a JWT access token is to issue the following call (we use jq to filter the response):

  1. http -a john:doe :8000 | jq -r .headers.Authorization

Output:

  1. Bearer <access-token>

We can use the output in Authorization header.

Test the JWT Access Token Authentication

  1. Request the service with a bearer token:

    1. http -v :8000 Authorization:"$(http -a john:doe :8000 | \
    2. jq -r .headers.Authorization)"

    or

    1. http -v :8000 Authorization:"Bearer <access-token>"
    1. GET / HTTP/1.1
    2. Authorization: Bearer <access-token>
    1. HTTP/1.1 200 OK
    1. {
    2. "headers": {
    3. "Authorization": "Bearer <access-token>"
    4. },
    5. "method": "GET"
    6. }
  2. Done.

Introspection Authentication

As with JWT Access Token Authentication), the introspection authentication relies on a bearer token that the client has already gotten from somewhere. The difference to stateless JWT authentication is that the plugin needs to call the introspection endpoint of the identity provider to find out whether the token is valid and active. This makes it possible to issue opaque tokens to the clients.

OpenID Connect Plugin Reference - 图14

Patch the Plugin

Let’s patch the plugin that we created in the Kong configuration step:

  1. We want to only use the introspection authentication, but we also enable the password grant for demoing purposes
  2. We want to search the bearer token for the introspection from the headers only.

Reset the plugin configuration before patching.

  1. http -f patch :8001/plugins/5f35b796-ced6-4c00-9b2a-90eef745f4f9 \
  2. config.bearer_token_param_type=header \
  3. config.auth_methods=introspection \
  4. config.auth_methods=password # only enabled for demoing purposes
  1. HTTP/1.1 200 OK
  1. {
  2. "id": "5f35b796-ced6-4c00-9b2a-90eef745f4f9",
  3. "name": "openid-connect",
  4. "service": {
  5. "id": "5fa9e468-0007-4d7e-9aeb-49ca9edd6ccd"
  6. },
  7. "config": {
  8. "auth_methods": [
  9. "introspection",
  10. "password"
  11. ],
  12. "bearer_token_param_type": [ "header" ]
  13. }
  14. }

Test the Introspection Authentication

  1. Request the service with a bearer token:

    1. http -v :8000 Authorization:"$(http -a john:doe :8000 | \
    2. jq -r .headers.Authorization)"

    or

    1. http -v :8000 Authorization:"Bearer <access-token>"
    1. GET / HTTP/1.1
    2. Authorization: Bearer <access-token>
    1. HTTP/1.1 200 OK
    1. {
    2. "headers": {
    3. "Authorization": "Bearer <access-token>"
    4. },
    5. "method": "GET"
    6. }
  2. Done.

User Info Authentication

The user info authentication uses OpenID Connect standard user info endpoint to verify the access token. In most cases it is preferable to use Introspection Authentication as that is meant for retrieving information from the token itself, whereas the user info endpoint is meant for retrieving information about the user for whom the token was given. The sequence diagram below looks almost identical to introspection authentication:

OpenID Connect Plugin Reference - 图15

Patch the Plugin

Let’s patch the plugin that we created in the Kong configuration step:

  1. We want to only use the user info authentication, but we also enable the password grant for demoing purposes
  2. We want to search the bearer token for the user info from the headers only.

Reset the plugin configuration before patching.

  1. http -f patch :8001/plugins/5f35b796-ced6-4c00-9b2a-90eef745f4f9 \
  2. config.bearer_token_param_type=header \
  3. config.auth_methods=userinfo \
  4. config.auth_methods=password # only enabled for demoing purposes
  1. HTTP/1.1 200 OK
  1. {
  2. "id": "5f35b796-ced6-4c00-9b2a-90eef745f4f9",
  3. "name": "openid-connect",
  4. "service": {
  5. "id": "5fa9e468-0007-4d7e-9aeb-49ca9edd6ccd"
  6. },
  7. "config": {
  8. "auth_methods": [
  9. "userinfo",
  10. "password"
  11. ],
  12. "bearer_token_param_type": [ "header" ]
  13. }
  14. }

Test the User Info Authentication

  1. Request the service with a bearer token:

    1. http -v :8000 Authorization:"$(http -a john:doe :8000 | \
    2. jq -r .headers.Authorization)"

    or

    1. http -v :8000 Authorization:"Bearer <access-token>"
    1. GET / HTTP/1.1
    2. Authorization: Bearer <access-token>
    1. HTTP/1.1 200 OK
    1. {
    2. "headers": {
    3. "Authorization": "Bearer <access-token>"
    4. },
    5. "method": "GET"
    6. }
  2. Done.

Kong OAuth Token Authentication

The OpenID Connect plugin can also verify the tokens issued by Kong OAuth 2.0 Plugin. This is very similar to 3rd party identity provider issued JWT access token authentication or introspection authentication:

OpenID Connect Plugin Reference - 图16

Prepare Kong OAuth Application

  1. Create a Consumer:

    1. http -f put :8001/consumers/jane
  2. Create Kong OAuth Application for the consumer:

    1. http -f put :8001/consumers/jane/oauth2/client \
    2. name=demo \
    3. client_secret=secret \
    4. hash_secret=true
  3. Create a Route:

    1. http -f put :8001/routes/auth paths=/auth
  4. Apply OAuth plugin to the Route:

    1. http -f put :8001/plugins/7cdeaa2d-5faf-416d-8df5-533d1e4cd2c4 \
    2. name=oauth2 \
    3. route.name=auth \
    4. config.global_credentials=true \
    5. config.enable_client_credentials=true
  5. Test the token endpoint:

    1. https -f --verify no post :8443/auth/oauth2/token \
    2. client_id=client \
    3. client_secret=secret \
    4. grant_type=client_credentials
    1. HTTP/1.1 200 OK
    1. {
    2. "access_token": "<access-token>",
    3. "expires_in": 7200,
    4. "token_type": "bearer"
    5. }

At this point we should be able to retrieve a new access token with:

  1. https -f --verify no post :8443/auth/oauth2/token \
  2. client_id=client \
  3. client_secret=secret \
  4. grant_type=client_credentials | \
  5. jq -r .access_token

Output:

  1. <access-token>

Patch the Plugin

Let’s patch the plugin that we created in the Kong configuration step:

  1. We want to only use the Kong OAuth authentication
  2. We want to search the bearer token for the Kong OAuth authentication from the headers only.

Reset the plugin configuration before patching.

  1. http -f patch :8001/plugins/5f35b796-ced6-4c00-9b2a-90eef745f4f9 \
  2. config.auth_methods=kong_oauth2 \
  3. config.bearer_token_param_type=header
  1. HTTP/1.1 200 OK
  1. {
  2. "id": "5f35b796-ced6-4c00-9b2a-90eef745f4f9",
  3. "name": "openid-connect",
  4. "service": {
  5. "id": "5fa9e468-0007-4d7e-9aeb-49ca9edd6ccd"
  6. },
  7. "config": {
  8. "auth_methods": [ "kong_oauth2" ],
  9. "bearer_token_param_type": [ "header" ]
  10. }
  11. }

Test the Kong OAuth Token Authentication

  1. Request the service with Kong OAuth token:

    1. http -v :8000 Authorization:"Bearer $(https -f --verify no \
    2. post :8443/auth/oauth2/token \
    3. client_id=client \
    4. client_secret=secret \
    5. grant_type=client_credentials | \
    6. jq -r .access_token)"

    or

    1. http -v :8000 Authorization:"Bearer <access-token>"
    1. GET / HTTP/1.1
    2. Authorization: Bearer <access-token>
    1. HTTP/1.1 200 OK
    1. {
    2. "headers": {
    3. "Authorization": "Bearer <access-token>",
    4. "X-Consumer-Id": "<consumer-id>",
    5. "X-Consumer-Username": "jane"
    6. },
    7. "method": "GET"
    8. }
  2. Done.

Session Authentication

Kong OpenID Connect plugin can issue a session cookie that can be used for further session authentication. To make OpenID Connect issue a session cookie, you need to first authenticate with one of the other grant / flows described above. In authorization code flow we already demonstrated session authentication when we used the redirect login action. The session authentication is described below:

OpenID Connect Plugin Reference - 图17

Patch the Plugin

Let’s patch the plugin that we created in the Kong configuration step:

  1. We want to only use the session authentication, but we also enable the password grant for demoing purposes

Reset the plugin configuration before patching.

  1. http -f patch :8001/plugins/5f35b796-ced6-4c00-9b2a-90eef745f4f9 \
  2. config.auth_methods=session \
  3. config.auth_methods=password # only enabled for demoing purposes
  1. HTTP/1.1 200 OK
  1. {
  2. "id": "5f35b796-ced6-4c00-9b2a-90eef745f4f9",
  3. "name": "openid-connect",
  4. "service": {
  5. "id": "5fa9e468-0007-4d7e-9aeb-49ca9edd6ccd"
  6. },
  7. "config": {
  8. "auth_methods": [
  9. "session",
  10. "password"
  11. ]
  12. }
  13. }

Test the Session Authentication

  1. Request the service with basic authentication credentials (created in the Keycloak configuration step), and store the session:

    1. http -v -a john:doe --session=john :8000
    1. GET / HTTP/1.1
    2. Authorization: Basic BEkg3bHT0ERXFmKr1qelBQYrLBeHb5Hr
    1. HTTP/1.1 200 OK
    2. Set-Cookie: session=<session-cookie>; Path=/; SameSite=Lax; HttpOnly
    1. {
    2. "headers": {
    3. "Authorization": "Bearer <access-token>"
    4. },
    5. "method": "GET"
    6. }
  2. Make request with a session cookie (stored above):

    1. http -v --session=john :8000
    1. GET / HTTP/1.1
    2. Cookie: session=<session-cookie>
    1. HTTP/1.1 200 OK
    1. {
    2. "headers": {
    3. "Authorization": "Bearer <access-token>"
    4. },
    5. "method": "GET"
    6. }
  3. Done.

If you want to disable session creation with some grants, you can use the config.disable_session.

Authorization

Before you proceed, check that you have completed the preparations.

The OpenID Connect plugin has several features to do coarse grained authorization:

  1. Claims based authorization
  2. ACL plugin authorization
  3. Consumer authorization

Claims Based Authorization

With claims verification, you have a couple of configuration options that all work the same and that can be used for the authorization:

  1. config.scopes_claim and config.scopes_required
  2. config.audience_claim and config.audience_required
  3. config.groups_claim and config.groups_required
  4. config.roles_claim and config.roles_required

The first configuration option, for example config.scopes_claim, points to a source, from which the value is retrieved and checked against the value of the second configuration option, in this case config.scopes_required.

Let’s take a look at a JWT access token:

Reset the plugin configuration before patching.

  1. Patch the plugin to enable the password grant:

    1. http -f patch :8001/plugins/5f35b796-ced6-4c00-9b2a-90eef745f4f9 \
    2. config.auth_methods=password
  2. Retrieve the content of an access token:

    1. http -a john:doe :8000 | jq -r .headers.Authorization
    1. HTTP/1.1 200 OK
    1. Bearer <access-token>
  3. The signed JWT <access-token> (JWS) comes with three parts separated with a dot .: <header>.<payload>.<signature> (a JWS compact serialization format)

  4. We are interested with the <payload>, and you should have something similar to:

    1. eyJleHAiOjE2MjI1NTY3MTMsImF1ZCI6ImFjY291bnQiLCJ0eXAiOiJCZWFyZXIiLC
    2. JzY29wZSI6Im9wZW5pZCBlbWFpbCBwcm9maWxlIiwicHJlZmVycmVkX3VzZXJuYW1l
    3. Ijoiam9obiIsImdpdmVuX25hbWUiOiJKb2huIiwiZmFtaWx5X25hbWUiOiJEb2UifQ

    That can be base64 url decoded to the following JSON:

    1. {
    2. "exp": 1622556713,
    3. "aud": "account",
    4. "typ": "Bearer",
    5. "scope": "openid email profile",
    6. "preferred_username": "john",
    7. "given_name": "John",
    8. "family_name": "Doe"
    9. }

    This payload may contain arbitrary claims, such as user roles and groups, but as we didn’t configure them in Keycloak, let’s just use the claims that we have. In this case we want to authorize against the values in scope claim.

Let’s patch the plugin that we created in the Kong configuration step:

  1. We want to only use the password grant for demonstration purposes.
  2. We require the value openid and email to be present in scope claim of the access token.
  1. http -f patch :8001/plugins/5f35b796-ced6-4c00-9b2a-90eef745f4f9 \
  2. config.auth_methods=password \
  3. config.scopes_claim=scope \
  4. config.scopes_required="openid email"
  1. HTTP/1.1 200 OK
  1. {
  2. "id": "5f35b796-ced6-4c00-9b2a-90eef745f4f9",
  3. "name": "openid-connect",
  4. "service": {
  5. "id": "5fa9e468-0007-4d7e-9aeb-49ca9edd6ccd"
  6. },
  7. "config": {
  8. "auth_methods": [ "password" ],
  9. "scopes_claim": [ "scope" ],
  10. "scopes_required": [ "openid email" ]
  11. }
  12. }

Now let’s see if we can still access the service:

  1. http -v -a john:doe :8000
  1. GET / HTTP/1.1
  2. Authorization: Basic BEkg3bHT0ERXFmKr1qelBQYrLBeHb5Hr
  1. HTTP/1.1 200 OK
  1. {
  2. "headers": {
  3. "Authorization": "Bearer <access-token>"
  4. },
  5. "method": "GET"
  6. }

Works as expected, but let’s try to add another authorization:

  1. http -f patch :8001/plugins/5f35b796-ced6-4c00-9b2a-90eef745f4f9 \
  2. config.audience_claim=aud \
  3. config.audience_required=httpbin
  1. HTTP/1.1 200 OK
  1. {
  2. "id": "5f35b796-ced6-4c00-9b2a-90eef745f4f9",
  3. "name": "openid-connect",
  4. "service": {
  5. "id": "5fa9e468-0007-4d7e-9aeb-49ca9edd6ccd"
  6. },
  7. "config": {
  8. "auth_methods": [ "password" ],
  9. "audience_claim": [ "scope" ],
  10. "audience_required": [ "httpbin" ]
  11. }
  12. }

As we know, the access token has "aud": "account", and that does not match with "httpbin", so the request should now be forbidden:

  1. http -v -a john:doe :8000
  1. HTTP/1.1 403 Forbidden
  1. {
  2. "message": "Forbidden"
  3. }

A few words about config.scopes_claim and config.scopes_required (and the similar configuration options). You may have noticed that config.scopes_claim is an array of string elements. Why? It is used to traverse the JSON when looking up a claim, take for example this imaginary payload:

  1. {
  2. "user": {
  3. "name": "john",
  4. "groups": [
  5. "employee",
  6. "marketing"
  7. ]
  8. }
  9. }

In this case you would probably want to use config.groups_claim to point to groups claim, but that claim is not a top-level claim, so you need to traverse there:

  1. Find the user claim and under it.
  2. Find the the groups claim, and read the value:
  1. {
  2. "config": {
  3. "groups_claim": [
  4. "user",
  5. "groups"
  6. ]
  7. }
  8. }

or

  1. http -f patch :8001/plugins/5f35b796-ced6-4c00-9b2a-90eef745f4f9 \
  2. config.groups_claim=user \
  3. config.groups_claim=groups

The value of a claim can be the following:

  • a space separated string (such as scope claim usually is)
  • an JSON array of strings (such as the imaginary groups claim above)
  • a simple value, such as a string

What about the config.groups_required then? That is also an array?

That is correct, the required checks are arrays to allow logical and/or type of checks:

  1. and: use a space separated values
  2. or: specify value(s) in separate array indices

For example:

  1. {
  2. "config": {
  3. "groups_required": [
  4. "employee marketing",
  5. "super-admins"
  6. ]
  7. }
  8. }

or

  1. http -f patch :8001/plugins/5f35b796-ced6-4c00-9b2a-90eef745f4f9 \
  2. config.groups_required="employee marketing" \
  3. config.groups_required="super-admins"

The above means that a claim has to have:

  1. employee and marketing values in it, OR
  2. super-admins value in it

ACL Plugin Authorization

The plugin can also be integrated with Kong ACL Plugin that provides access control functionality in form of allow and deny lists.

Please read the claims verification section for a basic information, as a lot of that applies here too.

Let’s first configure the OpenID Connect plugin for integration with the ACL plugin (please remove other authorization if enabled):

Reset the plugin configuration before patching.

  1. http -f patch :8001/plugins/5f35b796-ced6-4c00-9b2a-90eef745f4f9 \
  2. config.auth_methods=password \
  3. config.authenticated_groups_claim=scope
  1. HTTP/1.1 200 OK
  1. {
  2. "id": "5f35b796-ced6-4c00-9b2a-90eef745f4f9",
  3. "name": "openid-connect",
  4. "service": {
  5. "id": "5fa9e468-0007-4d7e-9aeb-49ca9edd6ccd"
  6. },
  7. "config": {
  8. "auth_methods": [ "password" ],
  9. "authorized_groups_claim": [ "scope" ]
  10. }
  11. }

Before we apply the ACL plugin, let’s try it once:

  1. http -v -a john:doe :8000
  1. HTTP/1.1 200 OK
  1. {
  2. "headers": {
  3. "X-Authenticated-Groups": "openid, email, profile",
  4. }
  5. }

Interesting, the X-Authenticated-Groups header was injected in a request. This means that we are all good to add the ACL plugin:

  1. http -f put :8001/plugins/b238b64a-8520-4bbb-b5ff-2972165cf3a2 \
  2. name=acl \
  3. service.name=openid-connect \
  4. config.allow=openid

Let’s test it again:

  1. http -v -a john:doe :8000
  1. HTTP/1.1 200 OK

Let’s make it forbidden by changing it to a deny-list:

  1. http -f patch :8001/plugins/b238b64a-8520-4bbb-b5ff-2972165cf3a2 \
  2. config.allow= \
  3. config.deny=profile

And try again:

  1. http -v -a john:doe :8000
  1. HTTP/1.1 403 Forbidden
  1. {
  2. "message": "You cannot consume this service"
  3. }

Consumer Authorization

The third option for authorization is to use Kong consumers and dynamically map from a claim value to a Kong consumer. This means that we restrict the access to only those that do have a matching Kong consumer. Kong consumers can have ACL groups attached to them and be further authorized with the Kong ACL Plugin.

As a remainder our token payload looks like this:

  1. {
  2. "exp": 1622556713,
  3. "aud": "account",
  4. "typ": "Bearer",
  5. "scope": "openid email profile",
  6. "preferred_username": "john",
  7. "given_name": "John",
  8. "family_name": "Doe"
  9. }

Out of these the preferred_username claim looks promising for consumer mapping. Let’s patch the plugin:

Reset the plugin configuration before patching.

  1. http -f patch :8001/plugins/5f35b796-ced6-4c00-9b2a-90eef745f4f9 \
  2. config.auth_methods=password \
  3. config.consumer_claim=preferred_username \
  4. config.consumer_by=username
  1. HTTP/1.1 200 OK
  1. {
  2. "id": "5f35b796-ced6-4c00-9b2a-90eef745f4f9",
  3. "name": "openid-connect",
  4. "service": {
  5. "id": "5fa9e468-0007-4d7e-9aeb-49ca9edd6ccd"
  6. },
  7. "config": {
  8. "auth_methods": [ "password" ],
  9. "consumer_claim": [ "preferred_username" ],
  10. "consumer_by": [ "username" ]
  11. }
  12. }

Before we proceed, let’s make sure we don’t have consumer john:

  1. http delete :8001/consumers/john
  1. HTTP/1.1 204 No Content

Let’s try to access the service without a matching consumer:

  1. http -a john:doe :8000
  1. HTTP/1.1 403 Forbidden
  1. {
  2. "message": "Forbidden"
  3. }

Now, let’s add the consumer:

  1. http -f put :8001/consumers/john
  1. HTTP/1.1 200 OK
  1. {
  2. "id": "<consumer-id>",
  3. "username": "john"
  4. }

Let’s try to access the service again:

  1. http -a john:doe :8000
  1. HTTP/1.1 200 OK
  1. {
  2. "headers": {
  3. "Authorization": "Bearer <access-token>",
  4. "X-Consumer-Id": "<consumer-id>",
  5. "X-Consumer-Username": "john"
  6. },
  7. "method": "GET"
  8. }

Nice, as you can see the plugin even added the X-Consumer-Id and X-Consumer-Username as request headers.

It is possible to make consumer mapping optional and non-authorizing by setting the config.consumer_optional=true.

Headers

Before you proceed, check that you have completed the preparations.

The OpenID Connect plugin can pass claim values, tokens, JWKs, and the session identifier to the upstream service in request headers, and to the downstream client in response headers. By default, the plugin passes an access token in Authorization: Bearer <access-token> header to the upstream service (this can be controlled with config.upstream_access_token_header). The claim values can be taken from:

  • an access token,
  • an id token,
  • an introspection response, or
  • a user info response

Let’s take a look for an access token payload:

  1. {
  2. "exp": 1622556713,
  3. "aud": "account",
  4. "typ": "Bearer",
  5. "scope": "openid email profile",
  6. "preferred_username": "john",
  7. "given_name": "John",
  8. "family_name": "Doe"
  9. }

To pass the preferred_username claim’s value john to the upstream with an Authenticated-User header, we need to patch our plugin:

Reset the plugin configuration before patching.

  1. http -f patch :8001/plugins/5f35b796-ced6-4c00-9b2a-90eef745f4f9 \
  2. config.auth_methods=password \
  3. config.upstream_headers_claims=preferred_username \
  4. config.upstream_headers_names=authenticated_user
  1. HTTP/1.1 200 OK
  1. {
  2. "id": "5f35b796-ced6-4c00-9b2a-90eef745f4f9",
  3. "name": "openid-connect",
  4. "service": {
  5. "id": "5fa9e468-0007-4d7e-9aeb-49ca9edd6ccd"
  6. },
  7. "config": {
  8. "auth_methods": [ "password" ],
  9. "upstream_headers_claims": [ "preferred_username" ],
  10. "upstream_headers_names": [ "authenticated_user" ]
  11. }
  12. }

Let’s see if it had any effect:

  1. http -a john:doe :8000
  1. HTTP/1.1 200 OK
  1. {
  2. "headers": {
  3. "Authorization": "Bearer <access-token>",
  4. "Authenticated-User": "john"
  5. },
  6. "method": "GET"
  7. }

See the configuration parameters for other options.

Logout

The logout functionality is mostly useful together with session authentication that is mostly useful with authorization code flow.

As part of the logout, the OpenID Connect plugin implements several features:

  • session invalidation
  • token revocation
  • relying party (RP) initiated logout

Let’s patch the OpenID Connect plugin to provide the logout functionality:

Reset the plugin configuration before patching.

  1. http -f patch :8001/plugins/5f35b796-ced6-4c00-9b2a-90eef745f4f9 \
  2. config.auth_methods=session \
  3. config.auth_methods=password \
  4. config.logout_uri_suffix=/logout \
  5. config.logout_methods=POST \
  6. config.logout_revoke=true
  1. HTTP/1.1 200 OK
  1. {
  2. "id": "5f35b796-ced6-4c00-9b2a-90eef745f4f9",
  3. "name": "openid-connect",
  4. "service": {
  5. "id": "5fa9e468-0007-4d7e-9aeb-49ca9edd6ccd"
  6. },
  7. "config": {
  8. "auth_methods": [ "password", "session" ],
  9. "logout_uri_suffix": "/logout",
  10. "logout_methods": [ "POST" ],
  11. "logout_revoke": true
  12. }
  13. }

Login and establish a session:

  1. http -a john:doe --session=john :8000
  1. HTTP/1.1 200 OK

Test that session authentication works:

  1. http --session=john :8000
  1. HTTP/1.1 200 OK

Logout, and follow the redirections:

  1. http --session=john --follow -a john: post :8000/logout
  1. HTTP/1.1 200 OK

We needed to pass -a john: as there seems to be a feature with HTTPie that makes it to store the original basic authentication credentials in a session - not just the session cookies.

At this point the client has logged out from both Kong and the identity provider (Keycloak).

Check that the session is really gone:

  1. http --session=john :8000
  1. HTTP/1.1 401 Unauthorized

Debugging

The OpenID Connect plugin is pretty complex, and it has to integrate with a 3rd party identity provider. This makes it slightly more difficult to debug. If you have issues with the plugin or integration, try the following:

  1. Set Kong log level to debug, and check the Kong error.log (you can filter it with openid-connect)

    1. KONG_LOG_LEVEL=debug kong restart
  2. Set the Kong OpenID Connect plugin to display errors:

    1. {
    2. "config": {
    3. "display_errors": true
    4. }
    5. }
  3. Disable the Kong OpenID Connect plugin verifications and see if you get further, just for debugging purposes:

    1. {
    2. "config": {
    3. "verify_nonce": false,
    4. "verify_claims": false,
    5. "verify_signature": false
    6. }
    7. }
  4. See what kind of tokens the Kong OpenID Connect plugin gets:

    1. {
    2. "config": {
    3. "login_action": "response",
    4. "login_tokens": [ "tokens" ],
    5. "login_methods": [
    6. "password",
    7. "client_credentials",
    8. "authorization_code",
    9. "bearer",
    10. "introspection",
    11. "userinfo",
    12. "kong_oauth2",
    13. "refresh_token",
    14. "session"
    15. ]
    16. }
    17. }

With session related issues, you can try to store the session data in Redis or memcache as that will make the session cookie much smaller. It is rather common that big cookies do cause issues. You can also enable session compression.

Also try to eliminate indirection as that makes it easier to find out where the problem is. By indirection, we mean other gateways, load balancers, NATs, and such in front of Kong. If there is such, you may look at using:


Changelog

Kong Gateway 2.8.x (plugin version 2.2.1)

  • Added the session_redis_username and session_redis_password configuration parameters.

  • Added the resolve_distributed_claims configuration parameter.

  • The client_id, client_secret, session_secret, session_redis_username, and session_redis_password configuration fields are now marked as referenceable, which means they can be securely stored as secrets in a vault. References must follow a specific format.

Kong Gateway 2.7.x (plugin version 2.2.0)

  • Starting with Kong Gateway 2.7.0.0, if keyring encryption is enabled, the config.client_id, config.client_secret, config.session_auth, and config.session_redis_auth parameter values will be encrypted.

    Additionally, the d, p, q, dp, dq, qi, oth, r, t, and k fields inside openid_connect_jwks.previous[...]. and openid_connect_jwks.keys[...] will be marked as encrypted.