What are Keycloak's OAuth2 / OpenID Connect endpoints? - keycloak

We are trying to evaluate Keycloak as an SSO solution, and it looks good in many respects, but the documentation is painfully lacking in the basics.
For a given Keycloak installation on http://localhost:8080/ for realm test, what are the OAuth2 Authorization Endpoint, OAuth2 Token Endpoint and OpenID Connect UserInfo Endpoint ?
We are not interested in using Keycloak's own client library, we want to use standard OAuth2 / OpenID Connect client libraries, as the client applications using the keycloak server will be written in a wide range of languages (PHP, Ruby, Node, Java, C#, Angular). Therefore the examples that use the Keycloak client aren't of use for us.

For Keycloak 1.2 the above information can be retrieved via the url
http://keycloakhost:keycloakport/auth/realms/{realm}/.well-known/openid-configuration
For example, if the realm name is demo:
http://keycloakhost:keycloakport/auth/realms/demo/.well-known/openid-configuration
An example output from above url:
{
"issuer": "http://localhost:8080/auth/realms/demo",
"authorization_endpoint": "http://localhost:8080/auth/realms/demo/protocol/openid-connect/auth",
"token_endpoint": "http://localhost:8080/auth/realms/demo/protocol/openid-connect/token",
"userinfo_endpoint": "http://localhost:8080/auth/realms/demo/protocol/openid-connect/userinfo",
"end_session_endpoint": "http://localhost:8080/auth/realms/demo/protocol/openid-connect/logout",
"jwks_uri": "http://localhost:8080/auth/realms/demo/protocol/openid-connect/certs",
"grant_types_supported": [
"authorization_code",
"refresh_token",
"password"
],
"response_types_supported": [
"code"
],
"subject_types_supported": [
"public"
],
"id_token_signing_alg_values_supported": [
"RS256"
],
"response_modes_supported": [
"query"
]
}
Found information at https://issues.jboss.org/browse/KEYCLOAK-571
Note: You might need to add your client to the Valid Redirect URI list

Actually link to .well-known is on the first tab of your realm settings - but link doesn't look like link, but as value of text box... bad ui design.
Screenshot of Realm's General Tab

You can also see this information by going into Admin Console -> Realm Settings -> Clicking the hyperlink on the Endpoints field.

I'm currently experimenting with Keycloak 18.0.0, and I found that the "/auth" part is removed from the OIDC discovery URL:
https://{keycloakhost}:{keycloakport}/realms/{realm}/.well-known/openid-configuration
This returns a JSON data structure that contains the endpoints:
{
"issuer": "https://{keycloakhost}:{keycloakport}/realms/{realm}",
"authorization_endpoint": "https://{keycloakhost}:{keycloakport}/realms/{realm}/protocol/openid-connect/auth",
"token_endpoint": "https://{keycloakhost}:{keycloakport}/realms/{realm}/protocol/openid-connect/token",
"introspection_endpoint": "https://{keycloakhost}:{keycloakport}/realms/{realm}/protocol/openid-connect/token/introspect",
"userinfo_endpoint": "https://{keycloakhost}:{keycloakport}/realms/{realm}/protocol/openid-connect/userinfo",
"end_session_endpoint": "https://{keycloakhost}:{keycloakport}/realms/{realm}/protocol/openid-connect/logout",
"frontchannel_logout_session_supported": true,
"frontchannel_logout_supported": true,
"jwks_uri": "https://{keycloakhost}:{keycloakport}/realms/{realm}/protocol/openid-connect/certs",
"check_session_iframe": "https://{keycloakhost}:{keycloakport}/realms/{realm}/protocol/openid-connect/login-status-iframe.html",
"grant_types_supported": [
"authorization_code",
"implicit",
"refresh_token",
"password",
"client_credentials",
"urn:ietf:params:oauth:grant-type:device_code",
"urn:openid:params:grant-type:ciba"
],
"response_types_supported": [
"code",
"none",
"id_token",
"token",
"id_token token",
"code id_token",
"code token",
"code id_token token"
],
"subject_types_supported": [
"public",
"pairwise"
],
"id_token_signing_alg_values_supported": [
"PS384",
"ES384",
"RS384",
"HS256",
"HS512",
"ES256",
"RS256",
"HS384",
"ES512",
"PS256",
"PS512",
"RS512"
],
"id_token_encryption_alg_values_supported": [
"RSA-OAEP",
"RSA-OAEP-256",
"RSA1_5"
],
"id_token_encryption_enc_values_supported": [
"A256GCM",
"A192GCM",
"A128GCM",
"A128CBC-HS256",
"A192CBC-HS384",
"A256CBC-HS512"
],
"userinfo_signing_alg_values_supported": [
"PS384",
"ES384",
"RS384",
"HS256",
"HS512",
"ES256",
"RS256",
"HS384",
"ES512",
"PS256",
"PS512",
"RS512",
"none"
],
"request_object_signing_alg_values_supported": [
"PS384",
"ES384",
"RS384",
"HS256",
"HS512",
"ES256",
"RS256",
"HS384",
"ES512",
"PS256",
"PS512",
"RS512",
"none"
],
"request_object_encryption_alg_values_supported": [
"RSA-OAEP",
"RSA-OAEP-256",
"RSA1_5"
],
"request_object_encryption_enc_values_supported": [
"A256GCM",
"A192GCM",
"A128GCM",
"A128CBC-HS256",
"A192CBC-HS384",
"A256CBC-HS512"
],
"response_modes_supported": [
"query",
"fragment",
"form_post",
"query.jwt",
"fragment.jwt",
"form_post.jwt",
"jwt"
],
"registration_endpoint": "https://{keycloakhost}:{keycloakport}/realms/{realm}/clients-registrations/openid-connect",
"token_endpoint_auth_methods_supported": [
"private_key_jwt",
"client_secret_basic",
"client_secret_post",
"tls_client_auth",
"client_secret_jwt"
],
"token_endpoint_auth_signing_alg_values_supported": [
"PS384",
"ES384",
"RS384",
"HS256",
"HS512",
"ES256",
"RS256",
"HS384",
"ES512",
"PS256",
"PS512",
"RS512"
],
"introspection_endpoint_auth_methods_supported": [
"private_key_jwt",
"client_secret_basic",
"client_secret_post",
"tls_client_auth",
"client_secret_jwt"
],
"introspection_endpoint_auth_signing_alg_values_supported": [
"PS384",
"ES384",
"RS384",
"HS256",
"HS512",
"ES256",
"RS256",
"HS384",
"ES512",
"PS256",
"PS512",
"RS512"
],
"authorization_signing_alg_values_supported": [
"PS384",
"ES384",
"RS384",
"HS256",
"HS512",
"ES256",
"RS256",
"HS384",
"ES512",
"PS256",
"PS512",
"RS512"
],
"authorization_encryption_alg_values_supported": [
"RSA-OAEP",
"RSA-OAEP-256",
"RSA1_5"
],
"authorization_encryption_enc_values_supported": [
"A256GCM",
"A192GCM",
"A128GCM",
"A128CBC-HS256",
"A192CBC-HS384",
"A256CBC-HS512"
],
"claims_supported": [
"aud",
"sub",
"iss",
"auth_time",
"name",
"given_name",
"family_name",
"preferred_username",
"email",
"acr"
],
"claim_types_supported": [
"normal"
],
"claims_parameter_supported": true,
"scopes_supported": [
"openid",
"phone",
"roles",
"microprofile-jwt",
"email",
"web-origins",
"offline_access",
"address",
"profile"
],
"request_parameter_supported": true,
"request_uri_parameter_supported": true,
"require_request_uri_registration": true,
"code_challenge_methods_supported": [
"plain",
"S256"
],
"tls_client_certificate_bound_access_tokens": true,
"revocation_endpoint": "https://{keycloakhost}:{keycloakport}/realms/{realm}/protocol/openid-connect/revoke",
"revocation_endpoint_auth_methods_supported": [
"private_key_jwt",
"client_secret_basic",
"client_secret_post",
"tls_client_auth",
"client_secret_jwt"
],
"revocation_endpoint_auth_signing_alg_values_supported": [
"PS384",
"ES384",
"RS384",
"HS256",
"HS512",
"ES256",
"RS256",
"HS384",
"ES512",
"PS256",
"PS512",
"RS512"
],
"backchannel_logout_supported": true,
"backchannel_logout_session_supported": true,
"device_authorization_endpoint": "https://{keycloakhost}:{keycloakport}/realms/{realm}/protocol/openid-connect/auth/device",
"backchannel_token_delivery_modes_supported": [
"poll",
"ping"
],
"backchannel_authentication_endpoint": "https://{keycloakhost}:{keycloakport}/realms/{realm}/protocol/openid-connect/ext/ciba/auth",
"backchannel_authentication_request_signing_alg_values_supported": [
"PS384",
"ES384",
"RS384",
"ES256",
"RS256",
"ES512",
"PS256",
"PS512",
"RS512"
],
"require_pushed_authorization_requests": false,
"pushed_authorization_request_endpoint": "https://{keycloakhost}:{keycloakport}/realms/{realm}/protocol/openid-connect/ext/par/request",
"mtls_endpoint_aliases": {
"token_endpoint": "https://{keycloakhost}:{keycloakport}/realms/{realm}/protocol/openid-connect/token",
"revocation_endpoint": "https://{keycloakhost}:{keycloakport}/realms/{realm}/protocol/openid-connect/revoke",
"introspection_endpoint": "https://{keycloakhost}:{keycloakport}/realms/{realm}/protocol/openid-connect/token/introspect",
"device_authorization_endpoint": "https://{keycloakhost}:{keycloakport}/realms/{realm}/protocol/openid-connect/auth/device",
"registration_endpoint": "https://{keycloakhost}:{keycloakport}/realms/{realm}/clients-registrations/openid-connect",
"userinfo_endpoint": "https://{keycloakhost}:{keycloakport}/realms/{realm}/protocol/openid-connect/userinfo",
"pushed_authorization_request_endpoint": "https://{keycloakhost}:{keycloakport}/realms/{realm}/protocol/openid-connect/ext/par/request",
"backchannel_authentication_endpoint": "https://{keycloakhost}:{keycloakport}/realms/{realm}/protocol/openid-connect/ext/ciba/auth"
}
}

With version 1.9.3.Final, Keycloak has a number of OpenID endpoints available. These can be found at /auth/realms/{realm}/.well-known/openid-configuration. Assuming your realm is named demo, that endpoint will produce a JSON response similar to this.
{
"issuer": "http://localhost:8080/auth/realms/demo",
"authorization_endpoint": "http://localhost:8080/auth/realms/demo/protocol/openid-connect/auth",
"token_endpoint": "http://localhost:8080/auth/realms/demo/protocol/openid-connect/token",
"token_introspection_endpoint": "http://localhost:8080/auth/realms/demo/protocol/openid-connect/token/introspect",
"userinfo_endpoint": "http://localhost:8080/auth/realms/demo/protocol/openid-connect/userinfo",
"end_session_endpoint": "http://localhost:8080/auth/realms/demo/protocol/openid-connect/logout",
"jwks_uri": "http://localhost:8080/auth/realms/demo/protocol/openid-connect/certs",
"grant_types_supported": [
"authorization_code",
"implicit",
"refresh_token",
"password",
"client_credentials"
],
"response_types_supported": [
"code",
"none",
"id_token",
"token",
"id_token token",
"code id_token",
"code token",
"code id_token token"
],
"subject_types_supported": [
"public"
],
"id_token_signing_alg_values_supported": [
"RS256"
],
"response_modes_supported": [
"query",
"fragment",
"form_post"
],
"registration_endpoint": "http://localhost:8080/auth/realms/demo/clients-registrations/openid-connect"
}
As far as I have found, these endpoints implement the Oauth 2.0 spec.

After much digging around we were able to scrape the info more or less (mainly from Keycloak's own JS client lib):
Authorization Endpoint: /auth/realms/{realm}/tokens/login
Token Endpoint: /auth/realms/{realm}/tokens/access/codes
As for OpenID Connect UserInfo, right now (1.1.0.Final) Keycloak doesn't implement this endpoint, so it is not fully OpenID Connect compliant. However, there is already a patch that adds that as of this writing should be included in 1.2.x.
But - Ironically Keycloak does send back an id_token in together with the access token. Both the id_token and the access_token are signed JWTs, and the keys of the token are OpenID Connect's keys, i.e:
"iss": "{realm}"
"sub": "5bf30443-0cf7-4d31-b204-efd11a432659"
"name": "Amir Abiri"
"email: "..."
So while Keycloak 1.1.x is not fully OpenID Connect compliant, it does "speak" in OpenID Connect language.

In version 1.9.0 json with all endpoints is at address /auth/realms/{realm}
Authorization Endpoint: /auth/realms/{realm}/account
Token Endpoint: /auth/realms/{realm}/protocol/openid-connect

Following link Provides JSON document describing metadata about the Keycloak
/auth/realms/{realm-name}/.well-known/openid-configuration
Following information reported with Keycloak 6.0.1 for master realm
{
"issuer":"http://localhost:8080/auth/realms/master",
"authorization_endpoint":"http://localhost:8080/auth/realms/master/protocol/openid-connect/auth",
"token_endpoint":"http://localhost:8080/auth/realms/master/protocol/openid-connect/token",
"token_introspection_endpoint":"http://localhost:8080/auth/realms/master/protocol/openid-connect/token/introspect",
"userinfo_endpoint":"http://localhost:8080/auth/realms/master/protocol/openid-connect/userinfo",
"end_session_endpoint":"http://localhost:8080/auth/realms/master/protocol/openid-connect/logout",
"jwks_uri":"http://localhost:8080/auth/realms/master/protocol/openid-connect/certs",
"check_session_iframe":"http://localhost:8080/auth/realms/master/protocol/openid-connect/login-status-iframe.html",
"grant_types_supported":[
"authorization_code",
"implicit",
"refresh_token",
"password",
"client_credentials"
],
"response_types_supported":[
"code",
"none",
"id_token",
"token",
"id_token token",
"code id_token",
"code token",
"code id_token token"
],
"subject_types_supported":[
"public",
"pairwise"
],
"id_token_signing_alg_values_supported":[
"PS384",
"ES384",
"RS384",
"HS256",
"HS512",
"ES256",
"RS256",
"HS384",
"ES512",
"PS256",
"PS512",
"RS512"
],
"userinfo_signing_alg_values_supported":[
"PS384",
"ES384",
"RS384",
"HS256",
"HS512",
"ES256",
"RS256",
"HS384",
"ES512",
"PS256",
"PS512",
"RS512",
"none"
],
"request_object_signing_alg_values_supported":[
"PS384",
"ES384",
"RS384",
"ES256",
"RS256",
"ES512",
"PS256",
"PS512",
"RS512",
"none"
],
"response_modes_supported":[
"query",
"fragment",
"form_post"
],
"registration_endpoint":"http://localhost:8080/auth/realms/master/clients-registrations/openid-connect",
"token_endpoint_auth_methods_supported":[
"private_key_jwt",
"client_secret_basic",
"client_secret_post",
"client_secret_jwt"
],
"token_endpoint_auth_signing_alg_values_supported":[
"RS256"
],
"claims_supported":[
"aud",
"sub",
"iss",
"auth_time",
"name",
"given_name",
"family_name",
"preferred_username",
"email"
],
"claim_types_supported":[
"normal"
],
"claims_parameter_supported":false,
"scopes_supported":[
"openid",
"address",
"email",
"microprofile-jwt",
"offline_access",
"phone",
"profile",
"roles",
"web-origins"
],
"request_parameter_supported":true,
"request_uri_parameter_supported":true,
"code_challenge_methods_supported":[
"plain",
"S256"
],
"tls_client_certificate_bound_access_tokens":true,
"introspection_endpoint":"http://localhost:8080/auth/realms/master/protocol/openid-connect/token/introspect"
}

keycloak version: 4.6.0
TokenUrl: [domain]/auth/realms/{REALM_NAME}/protocol/openid-connect/token
AuthUrl: [domain]/auth/realms/{REALM_NAME}/protocol/openid-connect/auth

For Hostname Endpoints:
https://keycloak.{HOSTNAME}/realms/{REALM}/.well-known/openid-configuration

FQDN/auth/realms/{realm_name}/.well-known/openid-configuration
you will see everything here, plus if the identity provider is also Keycloak then feeding this URL will setup everything also true with other identity providers if they support and they already handled it

TL;DR:
KC below 18.0.0: https://${hostname}/auth/realms/${realm}/.well-known/openid-configuration
KC 18.0.0 and up: https://${hostname}/realms/${realm}/.well-known/openid-configuration
A more in depth explanation. According to the openid-connect standard
Obtaining OpenID Provider Configuration Information
Using the Issuer location discovered (...) the OpenID Provider's configuration information can be
retrieved.
OpenID Providers supporting Discovery MUST make a JSON document
available at the path formed by concatenating the string
/.well-known/openid-configuration to the Issuer. (..)
So according to the standard the endpoint is on ${issuer_url}/.well-known/openid-configuration.
For Keycloak versions before 18.0.0:
The issuer is https://${host}:${port}/auth/realms/${realm}/ so the openid-configuration is on:
https://${host}:${port}/auth/realms/${realm}/.well-known/openid-configuration
Or via UI:
Go to your realm, then realm settings:
and then click on OpenID Endpoint Configuration.
For Keycloak version 18.0.0 and onwards (auth was removed)
The issuer is https://${host}:${port}/realms/${realm}/ so the openid-configuration is on:
https://${host}:${port}/realms/${realm}/.well-known/openid-configuration
Go to your realm, then realm settings:
and then click on OpenID Endpoint Configuration.

Related

Keycloak JWT to contain user real and client role

I'm using Keycloak version 20.0.1 (also tried on 19.0.0).
I have a realm configured and under the Client Scopes -> realm roles -> Mappers I have added the realm_access.roles mapping.
For some reasons that I don't understand, the JWT token that I get as a response doesn't contain the Realm Roles (I have also assigned a realm role to the user that it's used for testing).
The response that I get is:
{
"exp": 1669579902,
"iat": 1669579602,
"auth_time": 1669577841,
"jti": "9dfe2638-a9f8-4094-8691-7a1423b629f7",
"iss": "https://auth.xxxx.com/realms/xxxx.com",
"sub": "6fe1b9b9-5ddd-478d-9b38-bd11698295cf",
"typ": "Bearer",
"azp": "spring-client",
"nonce": "d14b168b-3c77-489b-85dd-192dba533624",
"session_state": "55d938d4-42e7-4c2b-9038-f808c917c366",
"acr": "0",
"allowed-origins": [
"*"
],
"scope": "openid email profile roles",
"sid": "55d938d4-42e7-4c2b-9038-f808c917c366",
"email_verified": true,
"name": "first last",
"preferred_username": "user#email.com",
"given_name": "first",
"family_name": "last",
"email": "user#email.com"
}
How should I add the roles into the JWT response returned by Keycloak?
I have tried to configure the Client Scopes -> ream roles -> Mappers and I was expecting to receive in the JWT response the roles field.
In the JWT of Keycloak, two roles information.
It is not represented user's assigned role. Just assigned client role are included but realm's roles is possible list of realm.
If you want to get all of assigned role, have to call role mapping of user API (see #3.1)
I decoded JWT by jwo.io after get access token by Postman with Keycloak v 19.0.2
#1 realm roles list - It is not assigned realm role list, it is possible role list
User JWT(access token), get grant_type = password
{
"exp": 1669599866,
"iat": 1669596266,
"jti": "ad4e3b51-b23e-4abb-aba6-0099bb5213cf",
"iss": "http://localhost:8080/auth/realms/example",
"aud": "account",
"sub": "fae8bf9b-2209-4f01-ab32-629e029941ba",
"typ": "Bearer",
"azp": "spring-client",
"session_state": "8debdcfa-4252-4a27-8190-2a4981e6a795",
"acr": "1",
"realm_access": {
"roles": [
"offline_access",
"admin",
"default-roles-example",
"uma_authorization",
"user"
]
},
"resource_access": {
"spring-client": {
"roles": [
"client role2"
]
}
},
"scope": "openid profile email",
"sid": "8debdcfa-4252-4a27-8190-2a4981e6a795",
"email_verified": false,
"name": "first last",
"preferred_username": "user",
"given_name": "first",
"family_name": "last",
"email": "user#test.com"
}
five realm's roles are possible realm's role not assigned user's roles
User just assigned three realm's roles
Client JWT(access token), get grant_type = client_credentials
{
"exp": 1669597154,
"iat": 1669593554,
"jti": "ff6ae9db-7e05-4f9a-a538-0755a7f55125",
"iss": "http://localhost:8080/auth/realms/example",
"aud": "account",
"sub": "9db11aa2-6862-4ebb-9ee6-b03b51d7814d",
"typ": "Bearer",
"azp": "spring-client",
"acr": "1",
"realm_access": {
"roles": [
"offline_access",
"default-roles-example",
"uma_authorization"
]
},
"scope": "openid profile email",
"clientId": "spring-client",
"clientHost": "172.19.0.1",
"email_verified": false,
"preferred_username": "service-account-spring-client",
"clientAddress": "172.19.0.1"
}
Those are client's roles, it has three roles but not matched JWT's realm list
In the JWT (client access token), that list is possible realm list(not assigned client realm roles)
#2 client role - It is assigned client list
GET {KEYCLOAK-IP}/auth/admin/realms/{REALM-NAME}/clients/{client-UUID}/roles
http://localhost:8080/auth/admin/realms/example/clients/1cb76d56-b96f-42a7-91c0-c201a7761e9e/roles
[
{
"id": "e5171eb5-976e-429f-914c-0d63d7b394fd",
"name": "client role2",
"composite": false,
"clientRole": true,
"containerId": "1cb76d56-b96f-42a7-91c0-c201a7761e9e"
},
{
"id": "293c9c9c-bb76-4192-be09-ede769458394",
"name": "uma_protection",
"composite": false,
"clientRole": true,
"containerId": "1cb76d56-b96f-42a7-91c0-c201a7761e9e"
},
{
"id": "e1441ceb-7ea8-436b-9a55-30999c6de744",
"name": "client role1",
"description": "",
"composite": false,
"clientRole": true,
"containerId": "1cb76d56-b96f-42a7-91c0-c201a7761e9e"
}
]
#3 user's role list can get the separate API
3.1 all of user's role
GET {KEYCLOAK-IP}/auth/admin/realms/{REALM-NAME}/users/{USER-UUID}/role-mappings
UI:
It seems to block, UI not allow to assign directly a user into client role from UI. I use REST API call. Here
Example, get user's roles:
http://localhost:8080/auth/admin/realms/example/users/fae8bf9b-2209-4f01-ab32-629e029941ba/role-mappings
Response
{
"realmMappings": [
{
"id": "c31bd5ce-e400-4546-b633-d4d5bde596d8",
"name": "admin",
"description": "Administrator privileges",
"composite": false,
"clientRole": false,
"containerId": "e78f0c77-b44b-48da-850b-9d157e24a439"
},
{
"id": "d99f61be-bacd-438d-974d-06a006704a1e",
"name": "default-roles-example",
"description": "${role_default-roles}",
"composite": true,
"clientRole": false,
"containerId": "e78f0c77-b44b-48da-850b-9d157e24a439"
},
{
"id": "8d250d6c-e249-4b63-b86f-390b4550b12e",
"name": "user",
"description": "User privileges",
"composite": false,
"clientRole": false,
"containerId": "e78f0c77-b44b-48da-850b-9d157e24a439"
}
],
"clientMappings": {
"spring-client": {
"id": "1cb76d56-b96f-42a7-91c0-c201a7761e9e",
"client": "spring-client",
"mappings": [
{
"id": "e5171eb5-976e-429f-914c-0d63d7b394fd",
"name": "client role2",
"composite": false,
"clientRole": true,
"containerId": "1cb76d56-b96f-42a7-91c0-c201a7761e9e"
}
]
}
}
}
If you want to see, how to set the role into client or user,here
to get roles or anything in token we had protocol mappers in version 18.0 and earlier. for version 19 and above it is removed but only from ui
you can add protocol mapper by rest api
/POST {keycloak_url}/admin/realms/demo/clients/<clientId>/protocol-mappers/models
authorization:Bearer token //should be admin token
{
"protocol":"openid-connect",
"config{
"multivalued":"true",
"id.token.claim":"true",
"access.token.claim":"true",
"userinfo.token.claim":"true",
"usermodel.realmRoleMapping.rolePrefix":"",
"claim.name":"realmRoles"
},
"name":"roleNameMapper",
"protocolMapper":"oidc-usermodel-realm-role-mapper"
}

JWKS URI missing in JWT based on Keycloak Client

I have activated the JWKS_URI in my OAuth client (within Keycloak).
[]
Now, my expectation was that besides the KID an field JWKS_UIR will be part of the JWT for that client. But, I see only KID. The CERTS endpoint works and response with a JWKS Json format.
Is my understanding correct that the JWKS_URI should be in the Token? (see https://www.rfc-editor.org/rfc/rfc8414.html)
From rfc8414.html , in 3.2. Authorization Server Metadata Response section.
The JWKS_URI is in the Authorization Server Metadata Response
It is response of 3.1. Authorization Server Metadata Request
and request example is
GET /.well-known/oauth-authorization-server HTTP/1.1
Host: example.com
example response
{
"issuer":
"https://server.example.com",
"authorization_endpoint":
"https://server.example.com/authorize",
"token_endpoint":
"https://server.example.com/token",
"token_endpoint_auth_methods_supported":
["client_secret_basic", "private_key_jwt"],
"token_endpoint_auth_signing_alg_values_supported":
["RS256", "ES256"],
"userinfo_endpoint":
"https://server.example.com/userinfo",
"jwks_uri":
"https://server.example.com/jwks.json",
"registration_endpoint":
"https://server.example.com/register",
"scopes_supported":
["openid", "profile", "email", "address",
"phone", "offline_access"],
"response_types_supported":
["code", "code token"],
"service_documentation":
"http://server.example.com/service_documentation.html",
"ui_locales_supported":
["en-US", "en-GB", "en-CA", "fr-FR", "fr-CA"]
}
In the Keycloak, provide this API
http://keycloakhost:keycloakport/auth/realms/{realm}/.well-known/openid-configuration
"jwks_uri" (Certificate endpoint) is it response as following JSON.
{
"issuer": "http://localhost:8080/auth/realms/my-realm",
"authorization_endpoint": "http://localhost:8080/auth/realms/my-realm/protocol/openid-connect/auth",
"token_endpoint": "http://localhost:8080/auth/realms/my-realm/protocol/openid-connect/token",
"introspection_endpoint": "http://localhost:8080/auth/realms/my-realm/protocol/openid-connect/token/introspect",
"userinfo_endpoint": "http://localhost:8080/auth/realms/my-realm/protocol/openid-connect/userinfo",
"end_session_endpoint": "http://localhost:8080/auth/realms/my-realm/protocol/openid-connect/logout",
"frontchannel_logout_session_supported": true,
"frontchannel_logout_supported": true,
"jwks_uri": "http://localhost:8080/auth/realms/my-realm/protocol/openid-connect/certs",
"check_session_iframe": "http://localhost:8080/auth/realms/my-realm/protocol/openid-connect/login-status-iframe.html",
"grant_types_supported": [
"authorization_code",
"implicit",
"refresh_token",
"password",
"client_credentials",
"urn:ietf:params:oauth:grant-type:device_code",
"urn:openid:params:grant-type:ciba"
],
"response_types_supported": [
"code",
"none",
"id_token",
"token",
"id_token token",
"code id_token",
"code token",
"code id_token token"
],
"subject_types_supported": [
"public",
"pairwise"
],
"id_token_signing_alg_values_supported": [
"PS384",
"ES384",
"RS384",
"HS256",
"HS512",
"ES256",
"RS256",
"HS384",
"ES512",
"PS256",
"PS512",
"RS512"
],
...
You shows header of JWT
In the specification JWT RFC 7519,
The example shows only "typ" and "alg" not "jwks_uri"
{"typ":"JWT",
"alg":"HS256"}

How to get the roles in Auth0's user management to be added in the JWT?

I have an Auth0 application and I'm maintaining roles through the User Management. I would like to get those roles that are assigned to a user to be added to the JWT returned.
I do have the following in the openid_connect_configuration.conf
map $host $oidc_scopes {
default "openid+profile+email+offline_access+openid roles";
}
i have the following in the /.well-known/openid-configuration
{
...
"scopes_supported": [
"openid",
"profile",
"offline_access",
"name",
"given_name",
"family_name",
"nickname",
"email",
"email_verified",
"picture",
"created_at",
"identities",
"phone",
"address"
],
"response_types_supported": [
"code",
"token",
"id_token",
"code token",
"code id_token",
"token id_token",
"code token id_token"
],
"code_challenge_methods_supported": [
"S256",
"plain"
],
"response_modes_supported": [
"query",
"fragment",
"form_post"
],
"subject_types_supported": ["public"],
"id_token_signing_alg_values_supported": [
"HS256",
"RS256"
],
"token_endpoint_auth_methods_supported": [
"client_secret_basic",
"client_secret_post"
],
"claims_supported": [
"aud",
"auth_time",
"created_at",
"email",
"email_verified",
"exp",
"family_name",
"given_name",
"iat",
"identities",
"iss",
"name",
"nickname",
"phone_number",
"picture",
"sub"
],
"request_uri_parameter_supported": false
}
How do I set things in Auth0 to return the roles assigned to the logged in user? I have tried looking into the documentation, but I had no luck.
I found my answer through exploring the extensions in Auth0. I installed the Auth0 Authorization extension. I enabled the groups and roles.
I then added the following rule:
function setRolesToUser(user, context, callback) {
// Roles should only be set to verified users.
if (!user.email || !user.email_verified) {
return callback(null, user, context);
}
user.app_metadata = user.app_metadata || {};
auth0.users
.updateAppMetadata(user.user_id, user.app_metadata)
.then(function () {
context.idToken['https://example.com/auth'] = user.app_metadata.authorization;
callback(null, user, context);
})
.catch(function (err) {
callback(err);
});
}
I get the following as the JWT payload:
{
"https://example.com/auth": {
"groups": ["Samples"],
"roles": ["Editor"]
},
"sub": "auth0|xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"nickname": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"email_verified": true,
"iss": "https://dev-xxxxxxxxxx.us.auth0.com/",
"updated_at": "2022-04-29T20:01:14.585Z",
"iat": 1.651330616E9,
"picture": "https://s.gravatar.com/avatar/a705adb3d5d8530c35c41a9de260cd3c?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Flo.png",
"exp": 1.651366616E9,
"name": "xxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxx",
"aud": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"nonce": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"email": "xxxxx.xxxxxxxxx#example.com"
}

Configuring keycloak as IDP in another keycloak

I am trying to configure a keycloak as an IDP in another keycloak. In my test setup there are 2 keycloak containers - keycloak-1 and keycloak-2.
In keycloak-1, I have created an openid client called idp-client. The configuration exported as JSON is shown below,
{
"clientId": "idp-client",
"surrogateAuthRequired": false,
"enabled": true,
"alwaysDisplayInConsole": false,
"clientAuthenticatorType": "client-secret",
"redirectUris": [
"http://localhost:8081/auth/realms/master/broker/oidc/endpoint"
],
"webOrigins": [],
"notBefore": 0,
"bearerOnly": false,
"consentRequired": false,
"standardFlowEnabled": true,
"implicitFlowEnabled": false,
"directAccessGrantsEnabled": true,
"serviceAccountsEnabled": false,
"publicClient": false,
"frontchannelLogout": false,
"protocol": "openid-connect",
"attributes": {
"saml.assertion.signature": "false",
"saml.force.post.binding": "false",
"saml.multivalued.roles": "false",
"saml.encrypt": "false",
"saml.server.signature": "false",
"saml.server.signature.keyinfo.ext": "false",
"exclude.session.state.from.auth.response": "false",
"saml_force_name_id_format": "false",
"saml.client.signature": "false",
"tls.client.certificate.bound.access.tokens": "false",
"saml.authnstatement": "false",
"display.on.consent.screen": "false",
"saml.onetimeuse.condition": "false"
},
"authenticationFlowBindingOverrides": {},
"fullScopeAllowed": true,
"nodeReRegistrationTimeout": -1,
"defaultClientScopes": [
"web-origins",
"role_list",
"profile",
"roles",
"email"
],
"optionalClientScopes": [
"address",
"phone",
"offline_access",
"microprofile-jwt"
],
"access": {
"view": true,
"configure": true,
"manage": true
}
}
In keycloak-2, I have added keycloak-1 as an identity provider. I have attached the images of the configuration for reference.
Now when I try to login to keycloak-2 using keycloak-1's user, after successful login, I am redirected to keycloak-2's but to an error page, its showing "Unexpected error when authenticating with identity provider"
Stacktrace in the keycloak-2's terminal is as below,
keycloak2_1 | 08:21:17,079 TRACE [org.keycloak.events] (default task-10) type=CODE_TO_TOKEN_ERROR, realmId=master, clientId=idp-client, userId=null, ipAddress=127.0.0.1, error=invalid_client_credentials, grant_type=authorization_code, requestUri=http://localhost:8080/auth/realms/master/protocol/openid-connect/token, cookies=[]
...
...
keycloak2_1 | 08:21:17,081 TRACE [org.keycloak.events] (default task-12) type=LOGIN_ERROR, realmId=master, clientId=null, userId=null, ipAddress=172.21.0.1, error=identity_provider_login_failure, requestUri=http://localhost:8081/auth/realms/master/broker/oidc/endpoint?state=MOz5_i2-SpoSLRtS4IWkXtUBsSzGciBysUrdYq8gGy0.k0e5WlQElRw.security-admin-console&session_state=1cc90330-cf3c-45c3-a44e-53fc71b17bb1&code=be12828b-3408-4822-b275-31afeb1c0405.1cc90330-cf3c-45c3-a44e-53fc71b17bb1.eb068c43-9f4e-45b7-b2e8-ac346f139141, cookies=[KEYCLOAK_SESSION_LEGACY=master/ce30941f-407f-4344-9019-58d2f26ea832/1cc90330-cf3c-45c3-a44e-53fc71b17bb1, PrivacyPolicy=accepted, KEYCLOAK_IDENTITY_LEGACY=eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIxNjgzNzMzNi1mMTA3LTRiMTktODk1Yi0wNWJmZDliZGIzYTUifQ.eyJleHAiOjE2MDk3ODQ0NzcsImlhdCI6MTYwOTc0ODQ3NywianRpIjoiNTQ3YmRlZGQtOGQyYy00MTJkLWJhMzYtZjkyNzAwNjlhYzQxIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsInN1YiI6ImNlMzA5NDFmLTQwN2YtNDM0NC05MDE5LTU4ZDJmMjZlYTgzMiIsInR5cCI6IlNlcmlhbGl6ZWQtSUQiLCJzZXNzaW9uX3N0YXRlIjoiMWNjOTAzMzAtY2YzYy00NWMzLWE0NGUtNTNmYzcxYjE3YmIxIiwic3RhdGVfY2hlY2tlciI6IkZFT3psWkRScXhqREVVOGV6MFd6MU5menZGYU1jNHRzV1J4TnlrNUc5NDQifQ.YeBB6vJYZ9Z4IUXY2-og17EMRodUdeqTBTQ31pY3P1s, AUTH_SESSION_ID_LEGACY=1cc90330-cf3c-45c3-a44e-53fc71b17bb1.4c93e8da0ca1]
In keycloak-1, the user is logged in i.e. a session is shown for idp-client.
The mentioned issue was rectified once the SSL was enabled.

Keycloak: Access token client-1 to manage client-2 resources

I have two clients in Keycloak:
CP: Client public
CC: Client confidential with Service Accounts enabled and several resources.
Resources owners are users who created them and they manage the access too.
The User (U) who created the Resource (R) can log in to CC and use the access token for call endpoints on CP.
Now I would like U will be able to set UMA policies, but the access token is from CP, not from CC where the resources are, so Keycloak is complaining about de token.
org.keycloak.authorization.client.util.HttpResponseException: Unexpected response from server: 403 / Forbidden / Response from server: {\"error\":\"invalid_clientId\",\"error_description\":\"Client application [CP] is not registered as a resource server.\"}
fun onlyOwner(accessToken: String, id: String, resourceId: String) {
val request = UmaPermissionRepresentation()
request.name = "Only owner can view $id"
request.description = "Only owner can view this resource"
request.scopes = setOf(ResourceScope.VIEW)
request.condition = ONLY_OWNER_CONDITION
authzClient.protection(accessToken).policy(resourceId).create(request)
}
Keycloak docs mention the following:
"
The Policy API is available at:
http://${host}:${port}/auth/realms/${realm_name}/authz/protection/uma-policy/{resource_id} This API is protected by a bearer token that must represent a consent granted by the user to the resource server to manage permissions on his behalf. The bearer token can be a regular access token obtained from the token endpoint using:
Resource Owner Password Credentials Grant Type
Token Exchange, in order to exchange an access token granted to some client (public client) for a token where audience is the resource server
I exchanged the CP client to CC client:
Original token:
{
"exp": 1606687405,
"iat": 1606651407,
"auth_time": 1606651405,
"jti": "1e4075a9-ce49-4462-91f7-33b8963f56dd",
"iss": "http://localhost/auth/realms/test",
"aud": "account",
"sub": "8381b629-5f10-401c-ae90-bb37769e5f70",
"typ": "Bearer",
"azp": "CP",
"session_state": "6c2d73e7-a4bd-44da-b242-cdf26ec812bc",
"acr": "1",
"allowed-origins": [
"*"
],
"realm_access": {
"roles": [
"offline_access",
"uma_authorization"
]
},
"resource_access": {
"account": {
"roles": [
"manage-account",
"manage-account-links",
"view-profile"
]
}
},
"scope": "openid email profile",
"email_verified": true,
"name": "Test First",
"preferred_username": "test",
"given_name": "Test",
"family_name": "First",
"email": "test#invent.com"
}
Exchanged token:
{
"exp": 1606687405,
"iat": 1606652039,
"auth_time": 1606651405,
"jti": "0c84f42a-973e-4bc7-9a6d-2c4fec548512",
"iss": "http://localhost/auth/realms/test",
"aud": [
"account",
"CC"
],
"sub": "8381b629-5f10-401c-ae90-bb37769e5f70",
"typ": "Bearer",
"azp": "CP",
"session_state": "6c2d73e7-a4bd-44da-b242-cdf26ec812bc",
"acr": "1",
"allowed-origins": [
"http://localhost"
],
"realm_access": {
"roles": [
"offline_access",
"uma_authorization"
]
},
"resource_access": {
"account": {
"roles": [
"manage-account",
"manage-account-links",
"view-profile"
]
}
},
"scope": "email profile",
"email_verified": true,
"name": "Test First",
"preferred_username": "test",
"given_name": "Test",
"family_name": "First",
"email": "test#invent.com"
}
But the error persists alghout aud changed from account to [account,cc].
The solution is exchanging the token using as client_id and client_secret the target client (cc). After that, you can use the access_token returned by Keycloak as bearer token for creating the UMA_Policy.
Exchange public client token to the confidential client token
Create a policy with the new access token