So I've been looking at setting up OAuth 2.0 for a Cordova mobile app using Microsofts cordova-plugin-ms-adal plugin (which uses the native libs) against a custom API using Azure AD. This all works well but I'm a bit confused with the use of the secret (or more specifically its absence).
In many articles on the web they state that when using the Authorization Code Grant and requesting a token, you include the secret. And that this grant type is ideal for use when you can securely store the secret e.g. on a server.
However the plugin does not require that a secret is specified in the app (and rightly so) but it still uses the Authorization Code Grant to authenticate. Also I can manually call
https://login.windows.net/common/oauth2/authorize?resource=http://***.onmicrosoft.com/***API&client_id=***&response_type=code&redirect_uri=http://***.onmicrosoft.com/***App
in my browser, login, get the code and then POST to https://login.windows.net/common/oauth2/token with
grant_type: authorization_code
client_id: ***
code: ***
redirect_uri: http://***.onmicrosoft.com/***App
resource: http://***.onmicrosoft.com/***API
and it works, so I get back a valid JWT, without having to send a secret.
Why!? Is this less secure? (I also noticed that the OAuth 2.0 spec section 4.1.3 does not state that the secret is required for grant type Authorization Code!?)
What are the implications of using a grant type of authorization_code without a secret / basic auth header?
To get a new access token, use the refresh token as you would an authorization code, but with a grant_type value of refresh_token and a refresh_token parameter that holds the contents of the refresh token. The type of grant being used. To exchange a refresh token for an access token, use refresh_token .
Authorization code is return when the user clicks accept to your application accessing their data. This code is used to exchange for an access token and a refresh token. This code can only be used once and is extremely short lived 10 minutes I believe. Access tokens are used to access private user data.
“Do I still need a client secret when using PKCE?” Yes, assuming you can keep a secret. PKCE helps protect you against various code injection attacks, but PKCE does not replace client authentication.
Using the Authorization Code grant with a so-called confidential client (a client that has a client secret) is more secure than using a public Client indeed.
That is because the exchange of the authorization code itself happens as URL parameter in the front-channel i.e. through the browser and as such is relatively vulnerable to attacks like cross-scripting, click-jacking, network/DNS manipulation etc. That means that it is possible for a dedicated attacker to steal the authorization code from a user in certain circumstances (sloppy user, attacker network control, sloppy redirect URI matching in the server implementation, etc.).
To exchange the authorization code for an Access Token, a confidential Client would have to present the client secret on an HTTPs protected call alongside of the authorization code, whereas a public Client doesn't have any means of making sure that it is really the designated Client.
This means that it is relatively easy for an attacker to mimic a public Client since that requires only non-secret information (he can grab the client_id
and the redirect_uri
from his own browser) and the authorization code
that he can grab through an attack as described above.
Though grabbing the authorization code for a confidential Client works in the same way, the attacker cannot use it and exchange it for an Access Token because in order to do so he needs a client secret which is typically much harder to obtain for the attacker. The secret is usually stored on the server in backend storage and communicated only over a secure HTTPs channel so it doesn't leak.
The implication of using grant_type=authorization_code
(or any other flow) with a public client (one that does not have a secret or authenticate in any other way) is that the access token granted does not represent an authorization of the client to directly access the resource, it represents an authorization for the client to access the resource on behalf of the user.
This is why you'll notice in Azure AD that when you register a native client app (a public client) you can only configure it to have delegated permissions to a resource, and not app-only permissions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With