How do you discover the OAuth2 server configuration?
This article is the second post in my blog series about the OAuth2; reading the first post may help you to understand this current topic easily.
Although I intended to provide an overview above the OAuth2 and related specifications, I have extensively discussed the Authorization Code grant type in the previous post. The Authorization Code grant type consists of two distinct steps:
- The application (OAuth2 client ) redirects the end-user who is accessing the application into the Authorization Endpoint of the Authorization Server (AS) with an authorization request to obtain an authorization grant (a.k.a ‘code’).
- Once the authorization grant (a.k.a ‘code’) is received by the application (OAuth2 client ), it makes a direct HTTP POST request to the Token Endpoint of the Authorization Server (AS) with a token request to obtain an access token.
Although we haven’t explicitly discussed, in both cases, we assumed that the locations of Authorization Endpoint and Token Endpoint of the Authorization Server (AS) are known to the application (OAuth2 client); Yet, how does this work in the real world?
The application should also know about the other configuration details about the Authorization Server (AS), such as supported grant types, supported scopes, etc. Note that these configuration data are also called as the metadata.
In this post, I’m trying to answer the above questions; basically, there are two approaches available:
- Use out-of-band channels to communicate the above configuration details.
- Use OAuth 2.0 Authorization Server Metadata specification.
Server Metadata via Out-of-band channels
In this approach, there is no standard methodology to define and communicate the AS configuration metadata. It’s up to the AS and the application to agree on an approach to communicate this data. Following are some of the possible methods:
- The AS maintains a human-readable page with the configuration metadata.
- Application developers can log in to a portal maintained by the AS to figure out the configuration metadata.
- The AS uses e-mail/text to communicate the configuration metadata to the application developers.
Although this is not a standard, it is still a pretty popular option due to the simplicity. The main drawback of this approach is that the configuration data are static or hard-coded within the application. The client can’t discover and establish the communication according to that dynamically. For example, once the Authorization Endpoint and Token Endpoint locations have been changed, the application must reconfigure to call new locations.
OAuth 2.0 Authorization Server Metadata
In contrast to the above approach, the OAuth 2.0 Authorization Server Metadata specification defines an automated approach for the applications to discover the AS’s configuration metadata. For instance, the application can automatically retrieve confirmation metadata as a machine-readable document frequently and change the Authorization Endpoint and Token Endpoint location dynamically.
There is a strong overlap between OAuth 2.0 Authorization Server Metadata and OpenID Connect Discovery specification. OpenID Connect Discovery specification was developed first. Then, the OAuth2 working group generalised the OpenID Connect Discovery specification to support use cases other than the OpenID Connect protocol. Due to this reason, you can find a great level of overlap with the JSON structures used to define server metadata and semantics of metadata request and response flows.
In addition to the server metadata structure and request-response semantics, OpenID Connect Discovery specification defines a discovery mechanism so that the client application can discover the AS based on an identifier provided by the end-user. Once the discovery process has taken place, the client application can send a metadata request to the discovered AS to figure out server metadata. However, in contrast to the OpenID Connect Discovery specification, the OAuth 2.0 Authorization Server Metadata specification does not define any particular discovery mechanism. It defines server metadata structure and request-response semantics only, which is significantly different between these two specifications. Note that most of the post examples are based on OpenID Connect Discovery specification that covers both of the specifications.
This specification defines several aspects related to the AS configuration, its capabilities and endpoint locations as follows.
- Server metadata format that covers endpoint locations, server capabilities and configuration. This metadata configuration document can be a plain JSON document exposed over HTTPS or JWT document signed by the AS.
- The metadata endpoint to query the server as mentioned above for configuration data.
- Metadata request and response semantics.
The best way to understand the metadata format is to look at a real-world example; here, let’s look at a part of the metadata from the Google authorization service.
{
"issuer": "https://accounts.google.com","authorization_endpoint":
"https://accounts.google.com/o/oauth2/v2/auth","token_endpoint": "https://oauth2.googleapis.com/token","revocation_endpoint": "https://oauth2.googleapis.com/revoke","response_types_supported": [
"code",
"token",
"none"
],"scopes_supported": [
"openid",
"email",
"profile"
],"token_endpoint_auth_methods_supported": [
"client_secret_post",
"client_secret_basic"
],"grant_types_supported": [
"authorization_code",
"refresh_token",
"urn:ietf:params:oauth:grant-type:device_code",
"urn:ietf:params:oauth:grant-type:jwt-bearer"
]
}
Let’s look at some of the values of the above metadata document.
Issuer — This mandatory element is the issuer identifier of the AS and used to identify the AS uniquely. This takes the URL format and starts with HTTPS.
example: https://accounts.google.com
example: https://sts.windows.net/{tenantid}
authorization_endpoint — The location of the OAuth2 authorization endpoint.
token_endpoint — The location of the OAuth2 token endpoint.
revocation_endpoint — The location of the OAuth2 revocation endpoint.
grant_types_supported — List of supported grant types.
token_endpoint_auth_methods_supported — List of supported client authentication mechanisms.
scopes_supported — List of supported grant types.
You can find the complete list of supported values from here. In addition to that, the specification allows properly defining custom values. For instance, there are OpenID Connect specific additional values defined in the OpenID Connect Discovery specification.
This is another example from Microsoft Azure. In this example document, you can find some OpenID Connect metadata and Microsoft specific metadata in addition to OAuth2 metadata elements.
{"issuer": "https://sts.windows.net/{tenantid}/","token_endpoint": "https://login.windows.net/common/oauth2/token","token_endpoint_auth_methods_supported": [
"client_secret_post",
"private_key_jwt",
"client_secret_basic"
],"jwks_uri": "https://login.windows.net/common/discovery/keys","response_types_supported": [
"code",
"id_token",
"code id_token",
"token id_token",
"token"
],"scopes_supported": [
"openid"
],
"microsoft_multi_refresh_token": true,"authorization_endpoint":
"https://login.windows.net/common/oauth2/authorize","http_logout_supported": true,"frontchannel_logout_supported": true,"end_session_endpoint":
"https://login.windows.net/common/oauth2/logout"
"check_session_iframe":
"https://login.windows.net/common/oauth2/checksession",
}
As mentioned previously, the above metadata document can be communicated using one of the following two approaches.
- A plain JSON document over a HTTPS channel — This is the most common approach due to its simplicity. For instance, as per the above examples, Microsoft Azure and Google use this approach to define the AS metadata.
- A signed JWT document — A set of metadata claims can be bundled as a JWT and signed using JWS. This singed JWT is placed within the plain JSON document as the value of signed_metadata element. The main advantage of this approach is that the receiving party can validate the issuer via signature verification.
Metadata request & response flow
This flow initiates when a client makes a metadata request call to the metadata endpoint of the AS. To make this possible, the client should know the location of the metadata endpoint of the AS. The OAuth 2.0 Authorization Server Metadata specification defines the following URL format based on IETF Defining Well-Known Uniform Resource Identifiers specification; however, it does not specify any discovery mechanism for clients to discover this metadata endpoint location. The ASs can use out-of-band mechanisms such as web page, portal, email to communicate this location or use the server discovery mechanism defined in the OpenID Connect Discovery specification, based on WebFinger.
Metadata endpoint location
According to the specification, the metadata endpoint URL takes the following format, which includes .well-known literal value.
/.well-known/oauth-authorization-server
Examples:
https://accounts.google.com/.well-known/openid-configurationhttps://login.windows.net/common/.well-known/openid-configuration
Step1 — The client makes a HTTP GET to the known metadata endpoint of the AS.
Examples:
curl https://accounts.google.com/.well-known/openid-configuration
Step 2 — The AS returns a JSON response with the metadata elements that we have discussed in the previous section.
Examples:
curl https://accounts.google.com/.well-known/openid-configuration{
"issuer": "https://accounts.google.com",
"authorization_endpoint": "https://accounts.google.com/o/oauth2/v2/auth",
"device_authorization_endpoint": "https://oauth2.googleapis.com/device/code",
"token_endpoint": "https://oauth2.googleapis.com/token",...............}
We have already discussed a few publically available OAuth2 services; now, let’s look at some popular open-source OAuth2 implementations and their OAuth2 metadata configurations.
Keycloak OAuth2 implementation
You can start Keycloak server instance by running the following Docker run command.
docker run -p 8080:8080 -p 9990:9990 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin quay.io/keycloak/keycloak:9.0.0
Once the Keycloak server started, you can access its OAuth2/OpenID Connect metadata using the following URL.
http://127.0.0.1:8080/auth/realms/master/.well-known/openid-configuration
Example :
curl -k http://127.0.0.1:8080/auth/realms/master/.well-known/openid-configuration{
"issuer": "http://127.0.0.1:8080/auth/realms/master","authorization_endpoint": "http://127.0.0.1:8080/auth/realms/master/protocol/openid-connect/auth","token_endpoint": "http://127.0.0.1:8080/auth/realms/master/protocol/openid-connect/token","token_introspection_endpoint": "http://127.0.0.1:8080/auth/realms/master/protocol/openid-connect/token/introspect","userinfo_endpoint": "http://127.0.0.1:8080/auth/realms/master/protocol/openid-connect/userinfo","end_session_endpoint": "http://127.0.0.1:8080/auth/realms/master/protocol/openid-connect/logout","jwks_uri": "http://127.0.0.1:8080/auth/realms/master/protocol/openid-connect/certs","check_session_iframe": "http://127.0.0.1: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",
],...}
WSO2 Identity Server OAuth2 implementation
You can start WSO2 Identity Server instance by running the following Docker command.
docker run --rm -it -p 9443:9443 --name is wso2/wso2is:5.10.0
Once the Keycloak server started, you can access its OAuth2/OpenID Connect metadata using the following URL.
https://localhost:9443/oauth2/token/.well-known/openid-configuration
Example :
curl -k https://localhost:9443/oauth2/token/.well-known/openid-configuration{"issuer": "https://localhost:9443/oauth2/token","introspection_endpoint": "https://localhost:9443/oauth2/introspect","Response_modes_supported": [
"query",
"fragment",
"form_post"
],"scopes_supported": [
"openid",
"email",
"profile",
"phone",
"address"
],"check_session_iframe": "https://localhost:9443/oidc/checksession","backchannel_logout_supported": true,"authorization_endpoint": "https://localhost:9443/oauth2/authorize","grant_types_supported": [
"refresh_token",
"urn:ietf:params:oauth:grant-type:saml2-bearer",
"password",
"client_credentials",
"iwa:ntlm",
"urn:ietf:params:oauth:grant-type:device_code",
"authorization_code",
"urn:ietf:params:oauth:grant-type:uma-ticket",
"account_switch",
"urn:ietf:params:oauth:grant-type:jwt-bearer"
],...}
There you have it! I have discussed OAuth 2.0 Authorization Server Metadata in detail and its relationship to the OpenID Connect Discovery specification in this post. If you’re enjoying what you’re reading now — just wait until you check out my next article! This is where I will be discussing the OAuth2 DCR and DCRM specifications; these also play an essential role in the OAuth2 eco-system.