Is Oauth2 authorization code bound with the client id? - security

I tried to login with two separate website, both using "login with Google". Intercepted the auth code from the 1st site, and exchange it with the auto code to the 2nd site. Neither site will let me login. I remember in RFC6749 it is not specified that the auth code to be bound with any identity, is it implemented so to increase security?

This is indeed part of OAuth2.0 security:
Exchange the Authorization Code for an Access Token
We’re about ready to wrap up the flow. Now that the application has
the authorization code, it can use that to get an access token.
The application makes a POST request to the service’s token endpoint
with the following parameters:
grant_type=authorization_code - This tells the token endpoint that the
application is using the Authorization Code grant type.
code - The
application includes the authorization code it was given in the
redirect.
redirect_uri - The same redirect URI that was used when
requesting the code. Some APIs don’t require this parameter, so you’ll
need to double check the documentation of the particular API you’re
accessing.
client_id - The application’s client ID.
client_secret -
The application’s client secret. This ensures that the request to get
the access token is made only from the application, and not from a
potential attacker that may have intercepted the authorization code.
from https://developer.okta.com/blog/2018/04/10/oauth-authorization-code-grant-type#exchange-the-authorization-code-for-an-access-token

Short answer : Authorization code is bound to the client it was issued
This is strictly enforced by the RFC6749 and stated in 4.1.3. Access Token Request section. Also, it is one of many checkes authorization server perform to validate a token request. Specification has following stated,
The authorization server MUST:
o ensure that the authorization code was issued to the authenticated
confidential client, or if the client is public, ensure that the code
was issued to "client_id" in the request
So when authorization server will cross check authorization code against client id or client credentials depending on client type.
Furthermore, authorization code is a temporary secret which must not be exposed to other parties. This is highlighted in security consideration's 10.5. Authorization Codes section.

Related

OAuth2 client credentials

So right now I'm implementing oauth2 in my server, but I just want to support the client_credentials grant. The thing is, the node-oauth2-server says that supports this type of grant, and I pretty much debugged the whole library, and there are some things that doesn't make sense to me.
As far as I understand, the client_credentials grant should work like this:
An internal request should be made to generate the client_id and client_secret for the client, this is the only time we will get the client_secret and we should give this to our client
The client_id should be stored in database with any extra data (like the account id associated or something like this) and a hash of client_secret so we can later validate it
The client sends a request to the server including the client_id and client_secret
The server should then generate an access token (in my case I will be using JWT) and return from the request. We also need to store this token in database so we can revoke the permission if needed
The client must use this access token in future requests to access resources from server, and the server will validate on each request if the token is valid (didn't expire, didn't lose permissions, etc)
I may be wrong about this, but this is what I need and this exactly what C# Identity does and it is explained here.
In my case I'm working with nodejs. Actually is a NestJS project, so I was trying to use this lib which is basically a wrapper for node-oauth2-server, and if you take a look inside node-oauth2-server, looks like they only support authorization codes, this is because the AuthorizeHandler.handle() always returns an authorization code and AuthenticateHandler.handle() always expects the authorization code and returns the access token. Basically I need to call the AuthenticateHandler.handle() but instead of checking the authorization code, I must pass and check the client_id and client_secret.
This is a recent issue which has the exact same issue than me: https://github.com/oauthjs/node-oauth2-server/issues/552
So, first, I want to confirm that I'm right and this lib have this implemented in a bad way, and second, is there any other nodejs lib that has client_credentials built in?
As you've mentioned that it doesn't support client_credentials grant at the moment, you can still utilize the authorization code flow grant type internally to get the access token.
Prepare client_credentials grant type request and submit to server.
Map this request to authorization code flow with additional
attributes require for the authorization code flow.
Submit the request to Authorization server.
Get the code from response.
Prepare the token exchange call with the oauth code.
Get the access_token.
Return the token in response to client_credentials call.

OAuth 2.0 - why consent screen doesn't require client secret?

I'm learning OAuth 2.0. When using authorization code flow, it's enough to pass client ID. Does it mean that, in theory, an attacker can generate multiple authorization codes easily?
What was the reason why the consent screen doesn't use client secret? It's secure, as authorization server should deliver HTTPS connection.
Is it only for simplicity, to allow linking on client-side, like this?
Login with Koala Auth
No, according to RFC-6749 section 1.3.1, the user is authenticated by the Authorization Server before an authorization code is given back. Therefore, the client ID is not the only piece of data the is needed to get an authorization code.
This is not because the resource owner redirects the user-agent to the authorization server that this authorization server will give back an authorization code: the user-agent must complete an authentication step with a valid user, before the authorization code is given back to the resource owner.

What does a Authorization Code contains?

Authorization code flow - User logs in from client app, authorization server returns an authorization code to the app. The app then exchanges the authorization code for access token.So, I want to know what is the content that authorization server sends as authorization code?I mean what code or signature does a authorization code contains?
Authorization Code in oAuth is explained in the RFC for oAuth, in section 1.3.1 called Authorization Code. See:
https://www.rfc-editor.org/rfc/rfc6749#section-1.3.1
The authorization code is obtained by using an authorization server as
an intermediary between the client and resource owner. Instead of
requesting authorization directly from the resource owner, the client
directs the resource owner to an authorization server (via its
user-agent as defined in [RFC2616]), which in turn directs the
resource owner back to the client with the authorization code.
Before directing the resource owner back to the client with the
authorization code, the authorization server authenticates the
resource owner and obtains authorization. Because the resource owner
only authenticates with the authorization server, the resource owner's
credentials are never shared with the client.
The authorization code provides a few important security benefits,
such as the ability to authenticate the client, as well as the
transmission of the access token directly to the client without
passing it through the resource owner's user-agent and potentially
exposing it to others, including the resource owner.
It is explained in more details with block diagrams in section 4.1 Authorization Code Grant, and in section 10.5 Authorization Codes. See:
https://www.rfc-editor.org/rfc/rfc6749#section-4.1
https://www.rfc-editor.org/rfc/rfc6749#section-10.5
Some relevant quotes from the documentation referenced above:
The transmission of authorization codes SHOULD be made over a secure
channel, and the client SHOULD require the use of TLS with its
redirection URI if the URI identifies a network resource. Since
authorization codes are transmitted via user-agent redirections, they
could potentially be disclosed through user-agent history and HTTP
referrer headers.
Authorization codes operate as plaintext bearer credentials, used to
verify that the resource owner who granted authorization at the
authorization server is the same resource owner returning to the
client to complete the process. Therefore, if the client relies on
the authorization code for its own resource owner authentication, the
client redirection endpoint MUST require the use of TLS.
Authorization codes MUST be short lived and single-use. If the
authorization server observes multiple attempts to exchange an
authorization code for an access token, the authorization server
SHOULD attempt to revoke all access tokens already granted based on
the compromised authorization code.
If the client can be authenticated, the authorization servers MUST
authenticate the client and ensure that the authorization code was
issued to the same client.
See the rest of RFC 6749 for more details:
https://www.rfc-editor.org/rfc/rfc6749

Security Issue Related to OAuth Flow

This question is related to the OAuth based login in a native mobile application. As per the Authorization Grant Type flow, the user enters the userid, password in the login page and in response, the Authorization Code is obtained in the URL (since its URL, https based encryption wont work either).
This means that the Authorization code is available in the proxies and anyone can use it, provided they have the client secret as well. The client secret cannot be stored in the mobile application as the mobile app is not considered secured as well.The approach that I had in mind to circumvent the security of client secret was to provide a server side endpoint, where the mobile client can call with Client Id, Authorization code and redirect url. The endpoint will enrich the client secret and then call the actual token endpoint to get the accesstoken. The accesstoken is secured as the entire communication is over HTTPS.
Now the issue is - the authorization code in the URL parameter is insecure and vulnerable. Or am I overthinking about the security. This is the primary question and if this is indeed a security issue, what is the mitigation adopted?
One option that I could think and from one of the older stackoverflow threads was to Secure the token endpoint which will give the access token from the server side. Any suggestion as to how to do that? - If its certificates , then the certificate will be packaged in the mobile app, making it insecure again)
Shameless plug ... but since I read through the complete specs and did some offline discussions, I want to provide my view on the same.
a. TLS between client and the authroization server - When the complete authentication is done after few redirects within the authorization provider, the Authorization provider will set the location header as the redirect uri along with the authorization code in the query parameter within he location header. Since the authorization code is within the location header and the response headers are still protected by the TLS, eavesdropping will not expose the authorization code.
b. If the client is a mobile application - the redirect uri should point to a custom URI scheme that will point to the mobile app itself. So when the browser executes the redirection based on the location header, the browser will call the mobile app. The call doesnt go out of the device and hence the authorization code is not exposed to the outside world.
c. If the client is a web application - the redirect uri will be executed over the browser and the authorization code will be exposed in the proxy logs (after https offloading) and in the browser cache or if there is an redirection , it will be susceptible for the leak of the codes. The protection of the authorization code is done in 2 ways - a. The authorization code can be set with a lifetime, which can be small. b. The authorization code can be used only once. So if the actual client already used it, no one can reuse the auth code to get the access token again.
d. Based on the point mentioned by Kris in the comments below, the spec defines an approach to protect the misuse of the authorization code. If the code is used more than once, the Authorization server can revoke all of the access tokens created with the authorization code.

OAuth 2.0 Authorization Code Grant without secret

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?
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.
without having to send a secret.
Not true. In the link you posted the request includes also:
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Maybe you didn't notice it. This shows the client_secret being transmitted in an encoded form, using HTTP Basic Authentication.
It's up to the server to decide how the client authenticates (if necessary). From the specification :
If the client type is confidential or the client was issued client
credentials (or assigned other authentication requirements), the
client MUST authenticate with the authorization server as described
in Section 3.2.1.
Sec 3.2.1 directs to section 2.3 (seriously), which says:
Clients in possession of a client password MAY use the HTTP Basic
authentication scheme as defined in [RFC2617] to authenticate with
the authorization server.
client password is aka client secret.
So the secret is being transmitted.

Resources