OAuth 2.0 Authorization Code Grant without secret - azure

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.

Related

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.

Which OAuth2 authentication flow shoud I use for PWA + server side application

I am trying to choose the right authentication flow for an application:
Fontend is an Progressive Web App accessible only via HTTPS. It'is done in Angular, Single Page Application.
External Authorization Server
Backend accessible via REST calls
For now I am using Authorization Code Grant flow.
What have I tried:
I've checked official site. There is a list of possible flows (Authorization Code, Implicit, Password, Client Credentials, Device Code, ...),
but no clear indication how to choose between them.
Then I found this excellent article on Auth0.com. Unfortunately PWA + server side beckend is not present in their scheme.
Could you please tell me what OAuth2 flow is appropriate to my context and why?
Assumptions (the way I understood the question):
You own and develop both frontend (Angular app) and backend (server-side REST API).
You want to outsource authentication to a 3rd party identity provider.
You want the Angular app (Client) to hold the token and be able to authenticate on the backend (Resource Server), with the identity of your user (Resource Owner) established on the 3rd party (Authorisation Server / Identity Provider (IdP) ).
First, a sidetrack. For this use-case, OpenId Connect (OIDC) would be a better fit, because that supports the identity element. The point in OAuth2 is to authorize your app to do stuff on the 3rd party. What you want is establish the identity of your user, with the help of the 3rd party, and that's what OpenId Connect does.
Ok, so which flow (OIDC is still based on OAuth2).
The first questions are whether the Client is trusted to do anything on the Resource Server, and whether it can securely store a secret. This is clearly not the case, a client-side app is not trusted, and cannot hold a secret. In the client credentials flow, the client uses a secret to authenticate on the IdP to receive a token for the resource server. This would mean your Angular app stores a password which it uses to get a token for your backend, clearly not what you want.
Resource owner password credentials flow is used when the client is trusted to handle user credentials. In your use-case this is not good, because practically it would mean your Angular app would get the users password to forward it to the IdP in exchange for a token. Your Client should not have access to the user password, it is not trusted.
Now comes the more interesting part.
The question is whether your Client has a server-side to securely hold a secret. If it does, Authorization Code Grant is good, because it allows your user to authenticate on the IdP, get redirected back with an authorization code, and the server-side can then exchange that for an access token to be used on the resource server. However, your Client in this scenario does not have a server-side, as far as I can understand the API is the resource server. So this is not good for you, because it needs a client secret, and you can't store it in your Angular app.
And this pretty much leaves you with the Implicit Flow, for which you don't need a client secret, but on the other hand it's difficult to do things like refresh tokens. In the flowchart you linked to, the last question is whether your Client is an SPA - and in your case it is, so you should go for the implicit flow by default.
This is probably the most secure model for you, because even in case of a compromise of your Client, your user credentials are still safe (the Angular app never has access).
However, you can model this whole thing differently, and that simplifies it quite a bit.
As far as I could understand, you own both the Client and the Resource Server, and the Resource Owner is using the Client, you just want to offload authentication while you still manage users in a 3rd party service.
Looking at it this way, your Client is trusted to access user credentials, and the user using it is the Resource Owner. So you could use the Resource Owner Password Flow, where the user enters his credentials directly into the Angular app, which goes to the IdP, gets a token, and Angular simply uses that to access stuff on the API (Resource Server).
The risk compared to the Implicit Flow is that if the Angular app is compromised, user credentials will be disclosed to the attacker. Whether you want to accept this risk entirely depends on you. Note that this would obviously not work if the IdP is a well-known service (like a social website for example), because as your user I wouldn't want to give my social site password to your app. But as long as you manage users anyway, it can be acceptable to trust the Client.
While the previous anwser was perfectly accepted in 2018, it should be considerate as a security risk nowaday.
IETF source concerning implicit flow.
The correct flow to used now for a PWA and in general any public, browser based client that can not rely on client_secret is the authorization code flow + PKCE

Is Oauth2 authorization code bound with the client id?

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.

OAuth 2.0 public client impersonation

I'd like to develop a native application (for a mobile phone) that uses OAuth 2.0 Authorization to access protected resources from a resource API. As defined in section 2.1 the type of my client is public.
Upon registration, the Authorization Server provides a client_id for public identification and a redirect_uri.
The client will make use of Authorization Code to receive it's Authorization Grant from the Authorization Server. This all seems secure (if implemented correctly) against any attacker in the middle.
In section 10.2 client impersonation is discussed. In my case, the resource owner grants the client authorization by providing it's credentials via the user agent to the Authorization Server. This section discusses that the Authorization Server:
SHOULD utilize other means to protect resource owners from such
potentially malicious clients. For example, the authorization server
can engage the resource owner to assist in identifying the client and
its origin.
My main concern is that it's easy to impersonate my client once the client_id and redirect_uri is retrieved.
Due to the nature of a public client, this can either be easily reverse engineered. Or in my case, the project will be open source, so this information can be retrieved from the web.
As far as I've understood from section 10.2, it's the resource owner's responsibility to check that the client is legitimate by comparing with what the Authorization Server SHOULD assist with.
In my experience with third party applications requesting an Authorization Grant from me, all I get is a page with some information about the client that actually should be requesting that grant. Based on pure logical sense, I can only judge if the client that's requesting the grant is actually the client that the Authorization Server is telling me who it should be.
So whenever we are dealing with PEBKAC (which I think occurs frequently), isn't it true that impersonators can easily access protected resources if the resource owner just grants them (which might identically look like my legitimate client) authorization?
TLDR - You want oauth access tokens to be issued only to valid clients - in this case devices that installed your app, yes?
First - Oauth2 has multiple workflows for issuing tokens. When YOU are running the Oauth2 service and its issuing tokens to devices running YOUR app, authorization code / redirect URL is not the relevant workflow. I suggest you read my answer here - https://stackoverflow.com/a/17670574/116524 .
Second - No luck here. Just run your services entirely on HTTPS. There is no real way to know whether the client registration request is coming from an app installed from the official app store. You can store bake some secret into the app, but it can be found via reverse engineering. The only possible way this could possibly happen can be some sort of authentication information being provided by the app store itself, which does not exist yet.

What's "Code substitution (OAuth Login)" threat?

From the OAuth 2.0 Threat Model and Security Considerations draft:
4.4.1.13. Threat: Code substitution (OAuth Login)
An attacker could attempt to login to an application or web site
using a victim's identity. Applications relying on identity data
provided by an OAuth protected service API to login users are
vulnerable to this threat. This pattern can be found in so-called
"social login" scenarios.
As a pre-requisite, a resource server offers an API to obtain
personal information about a user which could be interpreted as
having obtained a user identity. In this sense the client is
treating the resource server API as an "identity" API. A client
utilizes OAuth to obtain an access token for the identity API. It
then queries the identity API for an identifier and uses it to look
up its internal user account data (login). The client asssumes that
because it was able to obtain information about the user, that the
user has been authenticated.
If the client uses the grant type "code", the attacker needs to
gather a valid authorization code of the respective victim from the
same identity provider used by the target client application. The
attacker tricks the victim into login into a malicious app (which may
appear to be legitimate to the Identity Provider) using the same
identity provider as the target application. This results in the
Identity Provider's authorization server issuing an authorization
code for the respective identity API. The malicious app then sends
this code to the attacker, which in turn triggers a login process
within the target application. The attacker now manipulates the
authorization response and substitutes their code (bound to their
identity) for the victim's code. This code is then exchanged by the
client for an access token, which in turn is accepted by the identity
API since the audience, with respect to the resource server, is
correct. But since the identifier returned by the identity API is
determined by the identity in the access token (issued based on the
victim's code), the attacker is logged into the target application
under the victim's identity.
Impact: the attacker gains access to an application and user-specific
data within the application.
Countermeasures:
All clients must indicate their client id with every request to
exchange an authorization code for an access token. The
authorization server must validate whether the particular
authorization code has been issued to the particular client. If
possible, the client shall be authenticated beforehand.
Clients should use appropriate protocol, such as OpenID (cf.
[openid]) or SAML (cf. [OASIS.sstc-saml-bindings-1.1]) to
implement user login. Both support audience restrictions on
clients.
This is rather confusing to me: «the attacker needs to gather a valid authorization code of the respective victim from the same identity provider used by the target client application». What's "the respective victim" and what does "identity provider" mean in this and subsequent uses?
The whole attack description is obscure. I came to understand it as "one shouldn't use OAuth 2.0 to implement user login", but wouldn't that mean that major platforms such as Facebook are vulnerable? And vulnerable to what, exactly?
I probably only need a clarification of some of the terms used in this paragraph.
I found the answer by myself. The wording in this section is a bit confusing, but the attack is quite simple. "Identity provider" is the name for the resource server used to verify the identity of an user.
Basically it's a case of using an authentication code issued for a client application to obtain an access token by a different application. I try to outline the steps in a clearer way.
Attacker registers a malicious client (e.g. an app registered to Facebook).
Victim user is tricked into logging into the malicious client using a "Login with third party" button (e.g. "Login into Facebook") triggering OAuth 2.0 authorization_code flow.
The malicious client gets the authorization_code.
The attacker uses the just obtained authorization_code with another app and obtains access to that app as the victim user.
Step 4 is only possible if authorization_codes aren't bound to a specific client. Auth codes issued to a client can only be used by that same client to obtain an access token.
Of course Facebook is not vulnerable, as this requires only a basic check from the authorization server to defeat.

Resources