--- title: openid-connect --- ## Summary - [**Name**](#name) - [**Attributes**](#attributes) - [**Modes of operation**](#modes-of-operation) - [**Token Introspection**](#token-introspection) - [**Introspecting with public key**](#introspecting-with-public-key) - [**Troubleshooting**](#troubleshooting) ## Name The OAuth 2 / Open ID Connect(OIDC) plugin provides authentication and introspection capability to APISIX. ## Attributes | Name | Type | Requirement | Default | Valid | Description | | ------------------------------------ | ------- | ----------- | --------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------- | | client_id | string | required | | | OAuth client ID | | client_secret | string | required | | | OAuth client secret | | discovery | string | required | | | URL of the discovery endpoint of the identity server | | scope | string | optional | "openid" | | Scope used for the authentication | | realm | string | optional | "apisix" | | Realm used for the authentication | | bearer_only | boolean | optional | false | | Setting this `true` will check for the authorization header in the request with a bearer token | | logout_path | string | optional | "/logout" | | | | redirect_uri | string | optional | "ngx.var.request_uri" | | | | timeout | integer | optional | 3 | [1,...] | Timeout in seconds | | ssl_verify | boolean | optional | false | | | | introspection_endpoint | string | optional | | | URL of the token verification endpoint of the identity server | | introspection_endpoint_auth_method | string | optional | "client_secret_basic" | | Authentication method name for token introspection | | public_key | string | optional | | | The public key to verify the token | | token_signing_alg_values_expected | string | optional | | | Algorithm used to sign the token | | set_access_token_header | boolean | optional | true | | Whether to ensure the access token is set in a request header. | | access_token_in_authorization_header | boolean | optional | false | | If set to `true`, ensure that the access token is set in the `Authorization` header, otherwise use the `X-Access-Token` header. | | set_id_token_header | boolean | optional | true | | Whether to ensure the ID token, if available, is set in the `X-ID-Token` request header. | | set_userinfo_header | boolean | optional | true | | Whether to ensure the UserInfo object, if available, is set in the `X-Userinfo` request header. | ## Modes of operation The plugin supports different modes of operation. 1) It can be configured to just validate an access token that is expected to be present in a request header. In this case, requests without a token or where the token is invalid are always rejected. This requires `bearer_only` be set to `true` and that either an introspection endpoint has been configured through `introspection_endpoint`, or that a public key has been configured through `public_key`. See the relevant sections below. 2) Alternatively, the plugin can also be configured to authenticate a request without a valid token against an identity provider by going through the OIDC Authorization Code flow. The plugin then acts as an OIDC Relying Party. In this scenario, when the requesting user has authenticated successfully, the plugin will obtain and manage an access token and further user claims on behalf of the user in a session cookie. Subsequent requests that contain the cookie will use the access token stored in the cookie. In this case, `bearer_only` must be set to `false`. The first option is typically appropriate for service-to-service communication where the requesting side can be reasonably expected to obtain and manage a valid access token by itself. The second option is convenient to support web browser interaction with endpoints through a human user that may still need to be authenticated when accessing for the first time. The plugin can also be configured to support both scenarios by setting `bearer_only` to false, but still configuring either an introspection endpoint or a public key. In this case, introspection of an existing token from a request header takes precedence over the Relying Party flow. That is, if a request contains an invalid token, the request will be rejected without redirecting to the ID provider to obtain a valid token. The method used to authenticate a request also affects the headers that can be enforced on the request before sending it to upstream. The headers that can be enforced are mentioned below in each relevant section. ### Token Introspection Token introspection helps to validate a request by verifying the token against an Oauth 2 authorization server. As prerequisite, you should create a trusted client in the identity server and generate a valid token(JWT) for introspection. The following image shows an example(successful) flow of the token introspection via the gateway. ![token introspection](../../../assets/images/plugin/oauth-1.png) The following is the curl command to enable the plugin to an external service. This route will protect `https://httpbin.org/get`(echo service) by introspecting the token provided in the header of the request. ```bash curl http://127.0.0.1:9080/apisix/admin/routes/5 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' { "uri": "/get", "plugins": { "proxy-rewrite": { "scheme": "https" }, "openid-connect": { "client_id": "api_six_client_id", "client_secret": "client_secret_code", "discovery": "full_URL_of_the_discovery_endpoint", "introspection_endpoint": "full_URL_of_introspection_endpoint", "bearer_only": true, "realm": "master", "introspection_endpoint_auth_method": "client_secret_basic" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:443": 1 } } }' ``` The following command can be used to access the new route. ```bash curl -i -X GET http://127.0.0.1:9080/get -H "Host: httpbin.org" -H "Authorization: Bearer {replace_jwt_token}" ``` In this case, the plugin can enforce that the access token and the UserInfo object get set in respective configured request headers. When the Oauth 2 authorization server returns an expire time with the token, the token will be cached in APISIX until it is expired. For more details, please read: 1. [lua-resty-openidc](https://github.com/zmartzone/lua-resty-openidc)'s doc and source code. 2. `exp` field in the RFC's [Introspection Response](https://tools.ietf.org/html/rfc7662#section-2.2) section. ### Introspecting with public key You can also provide the public key of the JWT token to verify the token. In case if you have provided a public key and a token introspection endpoint, the public key workflow will be executed instead of verifying with the identity server. This method can be used if you want to reduce additional network calls and to speedup the process. The following configurations shows how to add a public key introspection to a route. ```bash curl http://127.0.0.1:9080/apisix/admin/routes/5 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' { "uri": "/get", "plugins": { "proxy-rewrite": { "scheme": "https" }, "openid-connect": { "client_id": "api_six_client_id", "client_secret": "client_secret_code", "discovery": "full_URL_of_the_discovery_endpoint", "bearer_only": true, "realm": "master", "token_signing_alg_values_expected": "RS256", "public_key" : "-----BEGIN CERTIFICATE----- {public_key} -----END CERTIFICATE-----" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:443": 1 } } }' ``` In this case, the plugin can only enforce that the access token gets set in the configured request headers. #### Authentication through OIDC Relying Party flow When an incoming request does not contain an access token in a header, nor in an appropriate session cookie, the plugin can act as an OIDC Relying Party and redirect to the authorization endpoint of the identity provider to go through the OIDC Authorization Code flow; see https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth. Once the user has authenticated against the identity provider, the plugin will obtain and manage an access token and further information from the identity provider on behalf of the user. The information is currently stored in a session cookie that the user agent can submit on subsequent requests. The plugin will recognize the cookie and use the information therein to avoid having to go through the flow again. The following command adds this mode of operation to a route. ```bash curl http://127.0.0.1:9080/apisix/admin/routes/5 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' { "uri": "/get", "plugins": { "proxy-rewrite": { "scheme": "https" }, "openid-connect": { "client_id": "api_six_client_id", "client_secret": "client_secret_code", "discovery": "full_URL_of_the_discovery_endpoint", "bearer_only": false, "realm": "master" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:443": 1 } } }' ``` In this case, the plugin can enforce that the access token, the ID token, and the UserInfo object get set in respective configured request headers. ## Troubleshooting Check/modify the DNS settings (`conf/config.yaml`) if APISIX cannot resolve/connect to the identity provider.