Supported response modes
When you buy something online, your order typically consists of two parts: 1) the item you want to buy; and, 2) how you want that item shipped (next-day air; ship to my home; ship to my local outlet for pickup; etc.)
The same thing is true (more or less) when it comes to making an authorization request: you need to specify what you’d like to get back (an authorization code, an access token, an identity token) as well as how you want those items returned to you. The latter request (how you want items returned to you) is known as the response mode, and is defined in the authorization request by using the response_mode parameter. The Identity Cloud supports three standard OAuth response modes, each of which is explained in more detail in this documentation:
- query
- fragment
- form_post
Before we do all that explaining, however, there are two things we need to point out. First, the response_mode parameter is optional; if you leave that parameter out of your authorization request then Hosted Login will select a response mode based on your authorization grant type . The table below lists the default response mode for the three primary grant types used by Hosted Login:
Grant Type | Default Response Mode | Notes |
---|---|---|
Authorization Code | query | The Authorization Code grant is limited to requests that use this syntax: response_type=code |
Hybrid | fragment | The Hybrid grant applies to all requests that include the code response type and the token and/or id_token types. For example: response_type=code id_token |
Implicit | fragment | The Implicit grant applies to all requests that don’t include the response type code. For example: response_type=token |
To show you how this works the following authorization request sets the response_type to code, but leaves out the response_mode parameter. As a result, the response is returned using the query response mode:
https://v1.api.us.janrain.com/e0a70b4f-1eef-4856-bcdb-f050fee66aae/login/authorize
?client_id=70a45721-c6ef-4d7c-91ff-f14e9346b8b6
&redirect_uri=https://oidc-playground.akamai.com/redirect_uri
&scope=openid
&response_type=code
&state=3bd5262737237ef4a
&code_challenge=RTg4QjMyRUJCNzdBRTQ1MkM2NTAzRTVDOEQ5OTg3QjIwMjVBNTcxQTU5RTJFNDYwMzJBQjYxRkM4NjQ0QzdBNw
&code_challenge_method=S256
In addition to that, it’s important to note that not all response modes can be used with all response types; for example, the query response mode can only be used only when the response_type is set to code. Anything else (e.g., response_type=token) generates an error. See the Response Type/Response Mode Interactions section of this article for more information.
query
The query response mode (so named because the server response is sent as query parameters in the redirect URI) is the least-secure of all the response mode methods. Consequently, query only can be used when an authorization request uses the authorization code grant (i.e., response_type=code). With the authorization code grant, the authorization endpoint only returns an authorization code: it does not send back an access token or an identity token. Because authorization codes are only minimally useful to a hacker, they can safely be returned as a query parameter. Due to inherent security risks, access and identity tokens can’t be returned as query parameters.
So why all the caution and concern when it comes to the query response mode? To explain that, let’s start by looking at a sample response returned from an authorization server to a client that making a response_type=code authorization request:
https://oidc-playground.akamai.com/redirect_uri
?code=8vDWHcKKe0TYtESvb45fglJJbssnNo8LV2-db4Tcu9tTXVqvDiG
&state=mdsb2JhbF9zdWIiOiJj
The preceding request consists of three parts:
-
The page that the client is redirected to (https://oidc-playground.akamai.com/redirect_uri), a page specified by the redirect_uri parameter in the original authorization request.
-
The query parameter designator (the question mark: ?).
-
The actual query parameters (in green). In this example, we have two such parameters: code (with a value of 8vDWHcKKe0TYtESvb45fglJJbssnNo8LV2-db4Tcu9tTXVqvDiG) and state (with a value of mdsb2JhbF9zdWIiOiJj).
That might look harmless enough, but embedding information in a query parameter opens up several security vulnerabilities:
-
The entire URI (including the query parameters) is accessible to the browser (i.e., the user-agent). In fact, these query parameters are accessible even when the client is redirected to another page (which is always the case following an authorization request). In our sample response, you can see that the client was redirected to the page https://oidc-playground.akamai.com/redirect_uri. If you look at the HTTP headers for that page, you’ll see an entry like this one:
Referer: https://oidc-playground.akamai.com/redirect_uri?code=8vDWHcKKe0TYtESvb45fglJJbssnNo8LV2-db4Tcu9tTXVqvDi&state=mdsb2JhbF9zdWIiOiJj
In other words, the complete URI (including query parameters) is available from the redirect page. Suppose our sample URI had included a username and password (not recommended, we hasten to add). In that case, the header on the redirect page might look like this:
Referer: https://oidc-playground.akamai.com/redirect_uri?username=karim.nafir@mail.com&password=p@ssw0rd
Not a very secure redirection, by any means.
-
The entire URI (including the query parameters) is maintained in the browser history. As a result, anyone who managed to get hold of your browser history would have access to those parameters and their values.
-
The entire URI (including the query parameters) is stored in server logs. This means that anyone who has access to the server logs has access to those parameters and their values.
These security vulnerabilities help explain why you can use query to return authorization codes but can’t use query to return access or identity tokens. By themselves, authorization codes are only moderately useful. Yes, authorization codes can be exchanged for access and identity tokens, but only if you can verify that the code truly belongs to you. For example, to exchange an authorization code for a set of tokens when using the authorization code + PKCE grant type you must present the token endpoint with the authorization code and with the code_verifier. The authorization code, by itself, is not enough.
But things are very different when it comes to tokens. In the OAuth/OIDC world, access tokens are “bearer” tokens: that means that a token can be used by anyone who happens to have possession of that token. For example, if a less-than-scrupulous person happened upon a still-valid access token while looking through server logs, they’d be able to use that access token themselves, no questions asked. Similarly, access tokens are clearly visible in the redirect URI when the response_mode is set to query:
http://localhost/
?access_token=haXcwJR1xarUHq54eyHuno5XU3Ub2nj34pXqMyjXR1ngLyjTTFkc3JOHgWYzqGme
&code=1Qbhq04fEvaIaUtC&expires_in=3600
&scope=openid+%252A%253Alogin%252Fauthorize+.%253Alogin%252Fprovider%252F%252A%252Fauthorize+.%253Alogin%252Fprovider%252F%252A%252Fcallback+%252A%253Alogin%252Ftoken+%252A%253Aprofiles%252Foidc%252Fuserinfo+.%253Aprofiles%252Foidc%252Fuserinfo+%252B%253Aprofiles%252Foidc%252Fuserinfo&state=LA6fKYw_1_7x_xrSpJQlStcu5YiqbycKE8QjVWEmeng
&token_type=Bearer
Identity tokens also appear in the redirect URI when using the query response mode. That’s a problem because identity tokens are easy to decode: anyone who gets hold of an identity token can see exactly what’s contained within that token, including any personally-identifiable (PII) information. (Which is a good reason why you shouldn’t include PII in your identity tokens.)
The long and short of it? You can’t use query to return access tokens or identity tokens.
fragment
At first glance, the fragment (short for URI fragment)response mode seems pretty much identical to the query response mode. For example, here’s what a query response (one that returns an authorization code) might look like:
https://oidc-playground.akamai.com/redirect_uri
?code=8vDWHcKKe0TYtESvb45fglJJbssnNo8LV2-db4Tcu9tTXVqvDiG
&state=mdsb2JhbF9zdWIiOiJj
And here’s what that same response looks like using the fragment response mode:
https://oidc-playground.akamai.com/redirect_uri
#code=8vDWHcKKe0TYtESvb45fglJJbssnNo8LV2-db4Tcu9tTXVqvDiG
&state=mdsb2JhbF9zdWIiOiJj
As you can see, query parameters are designated by using a question mark (?), while URI fragments are designated by using a hashtag (#); other than that, the two URIs are identical. So does using a hashtag rather than a question mark really make that much difference?
As it turns out, yes, it does. Like query parameters, URI fragments are visible to the user-agent; this makes the fragment response type less-secure than form-post (see below). However, and unlike query parameters, URI fragments aren’t passed along when the client is redirected. As we saw elsewhere, if the response mode is set to query then the query parameters and their values are all passed to the page the client is redirected to; if you look at the HTTP headers, you’ll see something similar to this:
Referer: https://oidc-playground.akamai.com/redirect_uri
?code=8vDWHcKKe0TYtESvb45fglJJbssnNo8LV2-db4Tcu9tTXVqvDi
&state=mdsb2JhbF9zdWIiOiJj
But URI fragments aren’t included when redirecting the client. As a result, the HTTP headers on the redirect page will show an entry like this:
Referer: https://oidc-playground.akamai.com/redirect_uri
The access code is nowhere to be found.
That’s why it’s OK to use the fragment response mode when acquiring access tokens or identity tokens: those tokens are issued to the client but aren’t exposed in the HTTP headers when the client is redirected. Keep in mind, however, that URI fragments are stored in your browser’s history and in server logs, which increases the security risk. In addition, these tokens also appear in the redirect URI:
http://localhost/
#access_token=haXcwJR1xarUHq54eyHuno5XU3Ub2nj34pXqMyjXR1ngLyjTTFkc3JOHgWYzqGme
&code=1Qbhq04fEvaIaUtC
&expires_in=3600
&scope=openid+%252A%253Alogin%252Fauthorize+.%253Alogin%252Fprovider%252F%252A%252Fauthorize+.%253Alogin%252Fprovider%252F%252A%252Fcallback+%252A%253Alogin%252Ftoken+%252A%253Aprofiles%252Foidc%252Fuserinfo+.%253Aprofiles%252Foidc%252Fuserinfo+%252B%253Aprofiles%252Foidc%252Fuserinfo
&state=LA6fKYw_1_7x_xrSpJQlStcu5YiqbycKE8QjVWEmeng
&token_type=Bearer%253Aprofiles%252Foidc%252Fuserinfo
form_post
The form_post response type is easily the most-secure OAuth response type; that’s because the information in the response (including authorization codes, access tokens, and identity tokens) aren't exposed to the user agent. Instead, parameters and parameter values are encoded (using the application/x-www-form-urlencoded format) as members, and are transmitted to the client by using the HTTP POST method. Because these parameters aren’t part of a URI, there’s no chance they’ll show up in a browser history or server logs; in addition, they won’t be accessible from the page the client is redirected to following a successful authentication.
For example, here’s what a redirect URI looks like when the response_mode is set to form_post:
http://localhost/?state=LA6fKYw_1_7x_xrSpJQlStcu5YiqbycKE8QjVWEmeng
As you can see, no authorization code, and no tokens.
Response type and response mode interactions
If the response_type parameter is set to … | And the response_mode parameter is … | Here’s what happens |
---|---|---|
code | Not included in the authorization request | The response_mode defaults to query, and the user is redirected to the location specified by the redirect_uri. The authorization code is encoded in the URL parameters. |
code | Set to fragment | The user is redirected to the location specified by the redirect_uri. The authorization code is URL-encoded in the URL fragment. |
code | Set to query | The user is redirected to the location specified by the redirect_uri. The authorization. code is encoded in the URL parameters. |
code | Set to form_post | The authorization server POSTS a self-submitting form that redirects the user to the location specified by the redirect_uri. The authorization code is included as an application/x-www-form-urlencoded enctype attribute. |
token | Not included in the authorization request | The response_mode defaults to fragment, and the user is redirected to the location specified by the redirect_uri. The access token is URL-encoded in the URL fragment. |
token | Set to fragment | The user is redirected to the location specified by the redirect_uri. The access token is URL-encoded in the URL fragment. |
token | Set to form_post | The authorization server POSTS a self-submitting form that redirects the user to the location specified by the redirect_uri. The access token is included as an application/x-www-form-urlencoded enctype attribute. |
token | Set to query | An error occurs. The response_mode can’t be set to query if the response_type is set to token. |
id_token | Not included in the authorization request | The response_mode defaults to fragment and the user is redirected to the location specified by the redirect_uri. The identity token is URL-encoded in the URL fragment. |
id_token | Set to fragment | The user is redirected to the location specified by the redirect_uri. The identity token is URL-encoded in the URL fragment. |
id_token | Set to form_post | The authorization server POSTS a self-submitting form that redirects the user to the location specified by the redirect_uri. The identity token is included as an application/x-www-form-urlencoded enctype attribute. |
Id_token | Set to query | An error occurs. The response_mode can’t be set to query if the response_type is set to id_token. |
code token | Not included in the authorization request | The response_mode defaults to fragment and the user is redirected to the location specified by the redirect_uri. The authorization code and the access token are URL-encoded in the URL fragment. |
code token | Set to fragment | The user is redirected to the location specified by the redirect_uri. The authorization code and the access token are URL-encoded in the URL fragment. |
code token | Set to form_post | The authorization server POSTS a self-submitting form that redirects the user to the location specified by the redirect_uri. The authorization code and the access token are included as an application/x-www-form-urlencoded enctype attribute. |
code token | Set to query | An error occurs. The response_mode can’t be set to query if the response_type is set to code token. |
code id_token | Not included in the authorization request | The response_mode defaults to fragment and the user is redirected to the location specified by the redirect_uri. The authorization code and the identity token are URL-encoded in the URL fragment. |
code id_token | Set to fragment | The user is redirected to the location specified by the redirect_uri. The authorization code and identity token are URL-encoded in the URL fragment. |
code id_token | Set to form_post | The authorization server POSTS a self-submitting form that redirects the user to the location specified by the redirect_uri. The authorization code and the identity token are included as an application/x-www-form-urlencoded enctype attribute. |
code id_token | Set to query | An error occurs. The response_mode can’t be set to query if the response_type is set to code id_token. |
id_token token | Not included in the authorization request | The response_mode defaults to fragment, and the user is redirected to the location specified by the redirect_uri. The identity token and the access token are URL-encoded in the URL fragment. |
id_token token | Set to fragment | The user is redirected to the location specified by the redirect_uri. The access token and the identity token are URL-encoded in the URL fragment. |
id_token token | Set to form_post | The authorization server POSTS a self-submitting form that redirects the user to the location specified by the redirect_uri. The identity token and the access token are included as an application/x-www-form-urlencoded enctype attribute. |
id_token token | Set to query | An error occurs. The response_mode can’t be set to query if the response_type is set to id_token token. |
code id_token token | Not included in the authorization request | The response_mode defaults to fragment, and the user is redirected to the location specified by the redirect_uri. The authorization code, access token, and identity token are URL-encoded in the URL fragment. |
code id_token token | Set to fragment | The user is redirected to the location specified by the redirect_uri. The authorization code, access token, and identity token are URL-encoded in the URL fragment. |
code id_token token | Set to form_post | The authorization server POSTS a self-submitting form that redirects the user to the location specified by the redirect_uri. The authorization code, access token, and identity token are included as an application/x-www-form-urlencoded enctype attribute. |
code id_token token | Set to query | An error occurs. The response_mode can’t be set to query if the response_type is set to code id_token token. |
Anything other than the previously-specified values | Not included in the authorization request | The response_mode defaults to query, and the user is redirected to the location specified by the redirect_uri. The authorization. code is encoded in the URL parameters. |
Anything other than the previously-specified values | Set to query or Set to fragment or Set to form_post | An unsupported_response_type error occurs. |
Anything other than the previously-specified values | Anything other then query, fragment, or form_post | An invalid_request error occurs. |
Updated almost 2 years ago