Validate access tokens from a third-party OAuth 2.0 Authorization Server (including OpenID Connect) by leveraging JWT verification (RFC 7519) and/or OAuth2 Introspection (RFC 7662) and associate the external OAuth2 client with an existing Kong consumer based on the audience parameter.
Each consumer can have multiple audiences. At the same time, each registered audience can only be associated with a specific issuer (iss claim) and client id (client_id claim). This allow for complete control over the list of extenal OAuth2 Client that can be associated with the consumer.
From Luarocks:
luarocks install kong-plugin-oauth2-audienceFrom source:
git clone https://github.com/TelkomIndonesia/kong-plugin-oauth2-audience
cd kong-plugin-oauth2-audience
luarocks make *.rockspecThis plugin is compatible with requests with the following protocols:
httphttps
This plugin is partially compatible with DB-less mode.
In DB-less mode, Kong does not have an Admin API. If using this mode, configure the plugin using declarative configuration.
Consumers and Credentials can be created with declarative configuration.
Admin API endpoints which do POST, PUT, PATCH or DELETE on Credentials are not available on DB-less mode.
For example, configure this plugin on a Service by making the following request:
$ curl -X POST http://<admin-hostname>:8001/services/<service>/plugins \
--data "name=oauth2-audience" \
--data "config.issuer=https://issuer.tld"<service> is the id or name of the Service that this plugin configuration will target.
For example, configure this plugin on a Route with:
$ curl -X POST http://<admin-hostname>:8001/routes/<route>/plugins \
--data "name=oauth2-audience" \
--data "config.issuer=https://issuer.tld"<route> is the id or name of the Route that this plugin configuration will target.
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.
$ curl -X POST http://<admin-hostname>:8001/routes/<route>/plugins \
--data "name=oauth2-audience" \
--data "config.issuer=https://issuer.tld"<route> is the id or name of the Route that this plugin configuration will target.
Here's a list of all the parameters which can be used in this plugin's configuration:
| Form Parameter | Description |
|---|---|
nameType: string |
The name of the plugin to use, in this case oauth2-audience. |
service.idType: string |
The ID of the Service the plugin targets. |
route.idType: string |
The ID of the Route the plugin targets. |
enabledType: boolean Default value: true |
Whether this plugin will be applied. |
config.issuerrequired |
OAuth2 issuer identifier that needs to be present in iss claim on the OAuth2 token. |
config.oidc_conf_discoveryoptional Default value: true |
A boolean value that indicates whether the plugin should send OpenID Connect Discovery request to obtain information regarding JWT Verfication or OAuth2 Token Instropection. If set to false then appropriate jwt_* or introspection_* settings are required. |
config.required_scopeoptional |
Describes an array of scope names that must be available on the OAuth2 token. |
config.required_audiencesoptional |
Describes an array of audience value that must be available in the OAuth2 token aud claim. |
config.audience_prefixoptional |
Prefix string that must be added in the aud claim to be recognized as kong credential. For example if the audience associated with a consumer is nCztu5Jrz18YAWmkwOGJkQe9T8lB99l4 and the prefix is kong:, then aud claim should contains kong:nCztu5Jrz18YAWmkwOGJkQe9T8lB99l4 |
config.jwt_signature_secretsemi-optional |
Secret key used in Symmetric JWT verification. |
config.jwt_signature_public_keysemi-optional |
Public key used in Asymmetric JWT verification. If left empty and oidc_conf_discovery is not false, then this plugin will try to extract it from endpoint specified in jwks_uri metadata in OpenID Connect Discovery response. |
config.jwt_signature_algorithmoptional Default value: ["HS256", "HS512", "RS256"] |
A list of allowed JWT signature algorithm. This plugin only support HS256, HS512, and RS256 algorithm. |
config.jwt_introspectionoptional Default value: false |
If true and introspection_endpoint is available, then verified JWT will also be introspected. |
config.introspection_endpointsemi-optional |
Oauth2 Instrospection Endpoint for introspecting non-JWT token or if jwt_introspection is set to true. If left empty and oidc_conf_discovery is not false, then this plugin will use introspection_endpoint metadata in OpenID Connect Discovery response. |
config.introspection_auth_methodsemi-optional Default value: client_secret_basic |
Authentication method used to contact the introspection endpoint. The valid value is one of (1) client_secret_basic for basic auth, (2) client_secret_post for using credential in URL-Encoded body, (3) private_key_jwt for using Asymetric JWT or (4) client_secret_jwt for using Symetric JWT. |
config.introspection_client_idsemi-optional |
Client ID information to be used in introspection request. Depending on introspection_auth_method, it will be used as basic auth username, client_id form param, or iss JWT claim. |
config.introspection_client_secretsemi-optional |
Client Secret information to be used in introspection request when using client_secret_basic, client_secret_post, or client_secret_jwt authentication method. |
config.introspection_client_rsa_private_keysemi-optional |
Client Secret information to be used in introspection request when using private_key_jwt authentication method. |
config.introspection_client_rsa_private_key_idsemi-optional |
The value of kid JWT Header when using private_key_jwt authentication method. |
config.introspection_param_name_tokenoptional Default value: token |
URL-Encoded Form parameter name to contain the OAuth2 token to be introspected. |
config.introspection_paramsoptional |
Additional parameter to be included in OAuth2 Token Introspection request. |
config.introspection_claim_expiryoptional Default value: exp |
OAuth2 Token expiry claim. The value will be used in caching mechanism. |
config.introspection_cache_max_ttloptional Default value: 900 |
Maximum TTL to cache introspection result. |
config.auth_header_mapoptional Default value: {"consumer_id":"X-Consumer-ID","consumer_custom_id":"X-Consumer-Custom-ID","consumer_username":"X-Consumer-Username","credential":"x-authenticated-audience","anonymous":"X-Anonymous-Consumer"} |
Map containing upstream header name to be passed to upstream server. |
config.claim_header_mapoptional Default value: {"iss":"x-oauth2-issuer","client_id":"x-oauth2-client","sub":"x-oauth2-subject"} |
Mapping of OAuth2 Token claim to upstream header. |
config.auth_header_nameoptional Default value: authorization |
The name of the header supposed to carry the access token. |
config.hide_credentialsoptional Default value: false |
An optional boolean value telling the plugin to show or hide the credential from the upstream service. If true, the plugin will strip the credential from the request (i.e. the header or querystring containing the key) before proxying it. |
config.anonymousoptional |
An optional string (consumer uuid) value to use as an “anonymous” consumer if authentication fails. If empty (default), the request will fail with an authentication failure 4xx. Please note that this value must refer to the Consumer id attribute which is internal to Kong, and not its custom_id. |
config.run_on_preflightoptional Default value: true |
A boolean value that indicates whether the plugin should run (and try to authenticate) on OPTIONS preflight requests, if set to false then OPTIONS requests will always be allowed. |
config.ssl_verifyoptional Default value: true |
A boolean value that indicates whether the plugin should do SSL/TLS verification when sending OAuth2 Token Instrospection or OpenID Connect Discovery request |
Once applied, any user with a valid credential can access the Service. To restrict usage to only some of the authenticated users, also add the ACL plugin (not covered here) and create allowed or denied groups of users.
You need to associate an audience to an existing Consumer object. A Consumer can have many audiences.
To create a Consumer, you can execute the following request:
curl -d "username=user123&custom_id=SOME_CUSTOM_ID" http://kong:8001/consumers/Your declarative configuration file will need to have one or more Consumers. You can create them
on the consumers: yaml section:
consumers:
- username: user123
custom_id: SOME_CUSTOM_IDIn both cases, the parameters are as described below:
| parameter | description |
|---|---|
usernamesemi-optional |
The username of the consumer. Either this field or custom_id must be specified. |
custom_idsemi-optional |
A custom identifier used to map the consumer to another database. Either this field or username must be specified. |
If you are also using the ACL plugin and allow lists with this service, you must add the new consumer to the allowed group. See ACL: Associating Consumers for details.
You can provision new audience by making the following HTTP request:
$ curl -X POST http://kong:8001/consumers/{consumer}/oauth2-audiences \
--data "audience=62eb165c070a41d5c1b58d9d3d725ca1" \
--data "issuer=https://issuer.in.iss.claim.tld" \
--data "client_id=value-of-client-id-claim"
HTTP/1.1 201 Created
{
"consumer": { "id": "876bf719-8f18-4ce5-cc9f-5b5af6c36007" },
"created_at": 1443371053000,
"id": "62a7d3b7-b995-49f9-c9c8-bac4d781fb59",
"audience": "62eb165c070a41d5c1b58d9d3d725ca1",
"issuer": "https://issuer.in.iss.claim.tld",
"client_id": "value-of-client-id-claim"
}You can add audience on your declarative config file on the oauth2_audiences yaml entry:
oauth2_audiences:
- consumer: {consumer}
audience: "62eb165c070a41d5c1b58d9d3d725ca1"
issuer: "https://issuer.in.iss.claim.tld"
client_id: "value-of-client-id-claimIn both cases the fields/parameters work as follows:
| field/parameter | description |
|---|---|
{consumer} |
The id or username property of the Consumer entity to associate the audience to. |
audienceoptional |
This value that must be available in aud claim of the OAuth2 token. You can optionally set your own unique audience to associate the external OAuth2 client. If missing, the plugin will generate one. |
issuer |
The issuer identifier that must be available in iss claim of the OAuth2 token. |
client_id |
The client id that must be available in client_id claim of the OAuth2 token. |
You can delete an OAuth2 Audience by making the following HTTP request:
$ curl -X DELETE http://kong:8001/consumers/{consumer}/oauth2-audiences/{id}
HTTP/1.1 204 No Contentconsumer: Theidorusernameproperty of the Consumer entity to associate the credentials to.id: Theidattribute of the OAuth2 Audience object.
When a client has been authenticated, the plugin will append some headers to the request before proxying it to the upstream service, so that you can identify the Consumer in your code:
X-Consumer-ID, the ID of the Consumer on KongX-Consumer-Custom-ID, thecustom_idof the Consumer (if set)X-Consumer-Username, theusernameof the Consumer (if set)x-authenticated-audience, the identifier of the Credential (only if the consumer is not the 'anonymous' consumer)X-Anonymous-Consumer, will be set totruewhen authentication failed, and the 'anonymous' consumer was set instead.x-oauth2-issuer, the value ofissclaim from the OAauth2 Token.x-oauth2-client, the value ofclient_idclaim from the OAauth2 Token.
You can use this information on your side to implement additional logic. You can use the X-Consumer-ID value to query the Kong Admin API and retrieve more information about the Consumer. Additonally you can control the name of headers used and additional claims to be forwarded via auth_header_map and claim_header_map configuration.
You can paginate through the OAuth2 Audiences for all Consumers using the following request:
$ curl -X GET http://kong:8001/oauth2-audiences
{
"data":[
{
"id":"17ab4e95-9598-424f-a99a-ffa9f413a821",
"created_at":1507941267000,
"audience":"Qslaip2ruiwcusuSUdhXPv4SORZrfj4L",
"issuer": "https://issuer.in.iss.claim.tld",
"client_id": "value-of-client-id-claim",
"consumer": { "id": "c0d92ba9-8306-482a-b60d-0cfdd2f0e880" }
},
{
"id":"6cb76501-c970-4e12-97c6-3afbbba3b454",
"created_at":1507936652000,
"audience":"nCztu5Jrz18YAWmkwOGJkQe9T8lB99l4",
"issuer": "https://issuer.in.iss.claim.tld",
"client_id": "value-of-client-id-claim",
"consumer": { "id": "c0d92ba9-8306-482a-b60d-0cfdd2f0e880" }
},
{
"id":"b1d87b08-7eb6-4320-8069-efd85a4a8d89",
"created_at":1507941307000,
"audience":"26WUW1VEsmwT1ORBFsJmLHZLDNAxh09l",
"issuer": "https://issuer.in.iss.claim.tld",
"client_id": "value-of-client-id-claim",
"consumer": { "id": "3c2c8fc1-7245-4fbb-b48b-e5947e1ce941" }
}
]
"next":null,
}You can filter the list by consumer by using this other path:
$ curl -X GET http://kong:8001/consumers/{username or id}/oauth2-audiences
{
"data": [
{
"id":"6cb76501-c970-4e12-97c6-3afbbba3b454",
"created_at":1507936652000,
"audience":"nCztu5Jrz18YAWmkwOGJkQe9T8lB99l4",
"issuer": "https://issuer.in.iss.claim.tld",
"client_id": "value-of-client-id-claim",
"consumer": { "id": "c0d92ba9-8306-482a-b60d-0cfdd2f0e880" }
}
]
"next":null,
}username or id: The username or id of the consumer whose credentials need to be listed
It is possible to retrieve a Consumer associated with an API Key using the following request:
curl -X GET http://kong:8001/oauth2-audiences/{audience or id}/consumer
{
"created_at":1507936639000,
"username":"foo",
"id":"c0d92ba9-8306-482a-b60d-0cfdd2f0e880"
}audience or id: Theidoraudienceproperty of the OAuth2 Audience for which to get the associated Consumer.
To change the current plugin version, use the rename.sh script.
chmod +x ./rename.sh && ./rename.sh oauth2-audience oauth2-audience <new_plugin_version>If you are not on linux or somehow not able to run this script, utilize docker and run this script:
docker run \
-it \
--rm \
-v $PWD:/tmp/rename \
-w /tmp/rename \
--entrypoint /bin/bash \
debian:stretch-slim \
-c "chmod +x ./rename.sh && ./rename.sh oauth2-audience oauth2-audience <new_plugin_version>"docker-compose builddocker-compose up kongdocker-compose up bustedAssuming you mount ./volumes/kong/usr/local/share/lua/5.1 into $KONG_LUA_PATH/$KONG_LUA_VERSION container path
-
Click "Project" > "Project Directory" > "choose" and poin the project directory to ./volumes/kong/usr/local/share/lua/5.1.
-
Click "Project" > "Start Debugger Server"
-
Invoke the mockbin API