OAuth2 Auth Code with PKCE Without Whitelisting Reply/Redirect URLS Ok? - oauth-2.0

We have a home grown identity provider. It has supposedly implemented Auth Code Flow with PKCE but when you register clients it doesn't ask if the client is a public/private client and additionally it doesn't whitelist redirect/reply urls with client app registrations.
I'm trying to explain to my security team why this is a big deal and should be rectified, but I'm not seeing where the PKCE RFC explicitly states that you must whitelist redirect/reply urls for public clients.
Today the IDP's auth endpoint will send auth codes in a redirection to any url you provide it in the original auth request. Isn't this opening us up to man in the middle attacks, or am I mistaken and making a big deal of nothing, somehow PKCE patches this exploit?

Public clients have no way of proving their identity - that the application is really the client it is supposed to be. So an attacker can use their client_id and create a phishing application. If the OAuth2 server doesn't validate redirect_uri, the phishing application will easily get an auth code and exchange it for tokens.
The OAuth2 RFC says:
The authorization server
MUST require public clients and SHOULD require confidential clients
to register their redirection URIs.
You can also check the "OAuth 2.0 Threat Model and Security Considerations":
redirect URI
Validate Pre-Registered "redirect_uri"
Issue a "client_id" Only in Combination with "redirect_uri"

Related

When would I use a Hybrid flow with response_type=code id_token token in OpenID Connect?

I have been reading about OpenId Connect and their flows that are implicit flow, authorization code flow and hybrid flow.
I know that for example, the implicit flow is kind of insecure and should be used just in public clients like SPA application.
Now I´m trying to understand the Hybrid Flow that can be used for non-public applications like .Net MVC applications where you have a backchannel communication and thus you can save a secret password.
Reading about the Hybrid flow I know that it has 3 different types of response_type that can be:
code id_token
code token
code id_token token
For me, the best response_type would be code id_token where I can get the code in the front channel and then send that code to the Identity Server Provider and get the access token through the backchannel.
I've been searching for information on a real-world application of response_type=code id_token token, or code token, but other than reading that in these flows the first token/s are issued by the authorization endpoint which is the front channel and the final tokens that are issued by exchanging the authorization code are issued at the token endpoint, which is the backchannel and thus inherently accepted as being more secure, I fail to understand what you would use this for. Any information would be gladly accepted.
Why hybrid flow? The oft-documented rationale is that your app can immediately have info about the user via the id_token while the access token acquisition is still in flight. Technically this is true but it's still rarely used in the wild.
One real-world example is a Financial-grade API (FAPI) profile developed by a working group under the umbrella of OpenID Foundation. It recommends hybrid flow for security reasons. It's worth noting that the channel split "feature" of the flow is not enough on its own to provide the desired security properties, more "cooperation" from other moving parts is needed. From FAPI implementer's draft part 2:
This profile describes security provisions for the server and client
that are appropriate for Financial-grade APIs by defining the measures
to mitigate:
attacks that leverage the weak binding of endpoints in [RFC6749] (e.g. malicious endpoint attacks, IdP mix-up attacks),
attacks that modify authorization requests and responses unprotected in [RFC6749] by leveraging OpenID Connect's Hybrid Flow that returns
an ID Token in the authorization response.
and details
8.3.3 Identity provider (IdP) mix-up attack
In this attack, the client has
registered multiple IdPs and one of them is a rogue IdP that returns
the same client_id that belongs to one of the honest IdPs. When a user
clicks on a malicious link or visits a compromised site, an
authorization request is sent to the rogue IdP. The rogue IdP then
redirects the client to the honest IdP that has the same client_id. If
the user is already logged on at the honest IdP, then the
authentication may be skipped and a code is generated and returned to
the client. Since the client was interacting with the rogue IdP, the
code is sent to the rogue IdP's token endpoint. At the point, the
attacker has a valid code that can be exchanged for an access token at
the honest IdP.
This is mitigated by the use of OpenID Connect Hybrid Flow in which
the honest IdP's issuer identifier is included as the value of iss.
The client then sends the code to the token endpoint that is
associated with the issuer identifier thus it will not get to the
attacker.
8.4.3. Authorization response parameter injection attack
This attack occurs when the victim and attacker use the same relying party client.
The attacker is somehow able to capture the authorization code and
state from the victim's authorization response and uses them in his
own authorization response.
This can be mitigated by using OpenID Connect Hybrid Flow where the
c_hash, at_hash, and s_hash can be used to verify the validity of the
authorization code, access token, and state parameters. The server can
verify that the state is the same as what was stored in the browser
session at the time of the authorization request.
For a more technical description of these two attacks and countermeasures, see Single Sign-On Security – An Evaluation of OpenID Connect
For a realllly detailed description, take a look at OIDC Security Analysis paper.
The hybrid flow allows the backend to continue to act on the user’s behalf in an offline way (when the user is no longer present sending requests by browser) or independently of the frontend... doing other stuff in parallel. It can use the back channel exchanged refresh token to continue to get a new access token and work indefinitely.

OAuth2 authorization code PKCE without client_secret (wso2 5.3.0 IAM)

I'm currently trying to implement the OAuth 2.0 authorization code grant on a public client/native client (Android App).
Since it is impossible to store the client_secret on the device, I wanted to use this grant type with rfc7636 / Proof Key for Code Exchange by OAuth Public Clients (PKCE).
I'm using wso2 5.3.0 IAM in the backend.
The Authorization step works perfectly fine, but I'm not able to get the Access Token without a client_secret: invalid_request, Missing parameters: client_secret
Did I misunderstand the authorization code grant with PKCE wrong or did I miss some configuration in the IAM?
In comparison: It is possible with auth0.
Best Regards,
Robert
Even if you use the authorization code flow, client_secret is required at the token endpoint if the client type of your application is confidential. "4.1.3. Access Token Request" in RFC 6749 says as follows:
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.
So, change the client type of your application to public. I don't know WSO2, but I guess that it provides settings menu to switch the client type like below.
(screenshot of Authlete's web console)
The definitions of confidential clients and public clients are described in "2.1. Client Types" in RFC 6749.
Yes, the client_secret is mandatory in WSO2 IS implementation due to the Apache OLTU library that has been used internally to implement the OAuth2 feature.
Currently there is no way to register an application as a public client as explained.
However that doesn't mean there are necessarily any security pitfalls. Basically what the recommendation says is, not to embed the client_secret in a mobile app, because it makes it vulnerable. It doesn't provide any additional security for protected backend resources, because the client request is anyway not authenticated using client_secret. If you just treat the "Base64(client_id:client_secret)" as one single string it doesn't make any difference in the protocol or security of the protocol.
So when using WSO2 IS with mobile applications, following recommendations need to be followed.
Use authorization code grant type, which requires the client_secret.
Use PKCE (after WSO2 IS 5.2.0)
If you have other type of clients or channels for the same applications, e.g. like web, then register them as a separate service provider in IS and generate a separate pair of client_id, client_secret for them.
Disable "client_credentials" grant type for the particular OAuth2 mobile client you register in WSO2 IS, so that those apps can't get an access token without user authentication.
Going one step further, if you need to have unique client credentials for each instance of the mobile applications then use OAuth2 Dynamic Client Registration (DCR) to generate client credentials on the fly.
By following above 5 recommendations, it gives you the same level of security as recommended in the specification.
For Authorization grant flow you can send the request with empty client_secret. Try putting empty string like this client_secret='' and it should work as expected. You cannot request TOKEN_URI without client_secret parameter.
PKCE is used to protect theft of authorization code, Authorization code is valid for 10 minutes, when auth code is redeemed for access_token we also send code_verifier to make sure the auth code is not stoled by someone. code_verifier and code_challenge are generated together and code_challenge is used while requesting for auth code & code_verifier is used while requesting for access_token

In OAuth2 why is it authorization code and not authentication code?

From section 1.3.1:
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.
Since authorization code allows for authenticating the client (as an additional security measure), why isn't it called authentication code?
It is primarily called authorization code because OAuth 2.0 is about authorization and not about (user) authentication.
It doesn't actually authenticate the client in the traditional "static" or "pre-established" sense. It just makes sure that the client requesting the token is the same as the that the authorization response was sent to.
In fact there's a separate set of client authentication options that can be applied to actually authenticate the client to the token endpoint in the classic sense.

What are the limits of public clients in OAuth 2.0

OAuth 2.0 specifies two client types:
public (client_id)
confidential (client_id:client_secret)
and section 2.2 says:
The client identifier is not a
secret; it is exposed to the resource owner and MUST NOT be used
alone for client authentication.
While it is clear to me that public clients are primarily used for the implicit flow, there is more to this than it seems. When performing the auth code flow, we first request the authorization endpoint with our client_id, no secret required. Then, after getting the user's consent and the authorize code, we request the token endpoint. According to spec, we are able to request this endpoint without a client_secret:
client_id
REQUIRED, if the client is not authenticating with the
authorization server as described in Section 3.2.1.
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.
...
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 basically this section says that we are able to request this endpoint without a client secret. Now, it doesn't say anything about refresh tokens other than that those may be included in the request.
Refreshing an access token mentions:
Because refresh tokens are typically long-lasting credentials used to
request additional access tokens, the refresh token is bound to the
client to which it was issued. 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.
So basically we're allowed to refresh the access token without client authentication.
Now, what confuses me is that the implicit flow does not allow issuing of refresh tokens:
The authorization server MUST NOT issue a refresh token.
It doesn't say explicitly why we can't do that, only that we're not allowed to. My reasoning is that this isn't allowed because the client can't be trusted. But since the authorize code flow is allowed for public clients, why do we actually need the implicit flow, if the same thing can be achieved with a public client, plus getting a refresh token?
I'd be very glad if someone could clarify this.
You are allowed to request/refresh access token without client secret at your own risk. Or we can say it depends on your security requirements. The spec only clarifies client authentication for confidential clients, basically if the client is confidential. it MUST be authenticated by the server.
For public clients, the spec says:
The authorization server MUST NOT issue client passwords or other
client credentials to native application or user-agent-based
application clients for the purpose of client authentication.
So public clients can't even have a secret to be authenticated with. And then the spec also says:
When client authentication is not possible, the authorization server
SHOULD employ other means to validate the client's identity -- for
example, by requiring the registration of the client redirection URI
or enlisting the resource owner to confirm identity. A valid
redirection URI is not sufficient to verify the client's identity
when asking for resource owner authorization but can be used to
prevent delivering credentials to a counterfeit client after
obtaining resource owner authorization.
Also you may look at PKCE.
Get back to your question, I think you are misunderstanding:
According to spec, we are able to request this endpoint without a client_secret.
Not quite right, you must authenticate confidential client and you can't authenticate public client using a client secret (it does not have one).
The authorization server MUST NOT issue a refresh token.
I think it is all matter of security. In implicit grant, we are operating under a presumably unsafe environment. Exposing refresh token could harm your system, since we already expose access token in this grant type (Please read security consideration for access token).
But since the authorize code flow is allowed for public clients, why do we actually need the implicit flow, if the same thing can be achieved with a public client, plus getting a refresh token?
They are meant for completely different use cases. From https://oauth.net/2/grant-types/implicit/
The Implicit grant type is a simplified flow that can be used by public clients, where the access token is returned immediately without an extra authorization code exchange step.
It is generally not recommended to use the implicit flow (and some servers prohibit this flow entirely). In the time since the spec was originally written, the industry best practice has changed to recommend that public clients should use the authorization code flow with the PKCE extension instead.
Lastly, I suggest you to play with this site to get a better understanding of different grant types.

Why is OAuth a viable technique to prevent CSRF for RESTful APIs?

I have an exact situation with this question: What are some viable techniques for combining csrf protection with RESTful APIs?
One answer given talks about using
basic authentication with SSL
1 API key per application
OAuth
I am already convinced about implementing OAuth2.0 where you will have access_token, client_id, client_secret for each app.
However, I was not aware that this would actually help prevent CSRF.
My opinion is that at the end of the day, you still need ssl.
Because in OAuth2.0, when the client app sends requests on behalf of the Resource Owner, they need to send alongside the data parameters such as client_id, client_secret and access token.
Without HTTPS, if the client_id, client_secret and access token are known either through leaks or man-in-the-middle, then there is still a chance of CSRF, albeit a small one because of the expiry period of the access token.
Is my understanding correct?
If a resource is protected by OAuth 2 alone and an attacker gets client_id, client_secret and an access token, then no CSRF is needed at all. The attacker directly can send a request to use the protected resource and will be served because OAuth 2 does not filter the source of the request, it requires an access token only.
In general, you should definitely use HTTPS both for the authentication server and the protected resource to avoid man-in-the-middle attacks. However, if you're using the "authorization code grant" scenario (i.e. use it from your own web application), then the access token is not known even to the resource owner, he can intercept the authorization code only. Thus, if your web application has a trusted (e.g. intranet) connection to both the authorization server and the protected resource, it is safe to use an unencrypted connection to the protected resource.

Resources