mitreid-connect / OpenID-Connect-Java-Spring-Server

An OpenID Connect reference implementation in Java on the Spring platform.
Other
1.47k stars 767 forks source link

Using OAuth2 /token (in authorization_code flow) for SPA without client-secret #1455

Open Puneetsri opened 5 years ago

Puneetsri commented 5 years ago

Hello,

Apologies if this seems rather a feature request than issue.

My setup: One Angular7 based FE (on NGINX), one NodeJS based API server. FE just invokes api on this NodeJS server.

Now , i am trying to integrate mitreid openid-connect-server-webapp in my stack, and wanted to use authroization_code flow as i got enough motivation from several blogs not to use the implicit flow.

As mentioned in this blog (https://www.oauth.com/oauth2-servers/single-page-apps/), there seems to be a possibility to not to provide client_secret(means client does not posses the client_secret) but just pass client-id in http POST body while calling /token:

"Exchange the authorization code for an access token Client Identification (required): Despite the client secret not being used in this flow, the request requires sending the client ID to identify the application making the request. This means the client must include the client ID as a POST body parameter rather than using HTTP Basic Authentication like it can when including the client secret as well

POST /oauth/token HTTP/1.1  Host: authorization-endpoint.com  grant_type=authorization_code&code=Yzk5ZDczMzRlNDEwY  &redirect_uri=https://example-app.com/cb  &client_id=mRkZGFjM

"

Now, I am wondering if this is even possible with mitre implementation? I tried and simply got 'invalid credentials' due to missing client_secret.

It would be great if someone can confirm if it is supported in mitreid implementation or not. I am stuck for over a day now and could not get satisfactory outcome. I am ready to even include PKCE if that can help avoid using the client-secret somehow.

joegalley commented 5 years ago

My understanding is that if you want to use PKCE, you must be using the authorization_code flow. It's also my understanding that if you're using the authorization_code flow, you must send the client_secret in the HTTP Basic auth header (so you must therefore store client_secret on the client). I'd be interested in learning if my logic is flawed somewhere, because I am interested in doing something similar.

Puneetsri commented 5 years ago

I am well aware of the authoriztion code flow.

But specifically for Browser page (SPA) apps, I have seen several articles explaining this point:

One such (wonderful) blog (aaron from okta) is 👍 https://aaronparecki.com/oauth-2-simplified/#browser-based-apps

Excerpt from this blog

"Single-Page Apps

Single-page apps (or browser-based apps) run entirely in the browser after loading the source code from a web page. Since the entire source code is available to the browser, they cannot maintain the confidentiality of their client secret, so the secret is not used in this case. The flow is exactly the same as the authorization code flow above, but at the last step, the authorization code is exchanged for an access token without using the client secret.

Note: Previously, it was recommended that browser-based apps use the "Implicit" flow, which returns an access token immediately and does not have a token exchange step. In the time since the spec was originally written, the industry best practice has changed to recommend that the authorization code flow be used without the client secret. This provides more opportunities to create a secure flow, such as using the PKCE extension. References: OAuth 2.0 Security Best Current Practice (ietf.org), OAuth 2.0 for Browser-Based Apps (ietf.org). "

So, my conclusion is that probably today there are only few implementation which support authorization code flow without secret for SPA (okta being one of them i think).

May be i should stop exploring and just go ahead with implicit flow.

visweshwar commented 5 years ago

Based on your application you can disable authentication on the /token endpoint..

image

Puneetsri commented 5 years ago

I have not included PKCE yet, but above configuration simply does not work for /token. I just tried it, after getting code and then invoking /token, not passing the authorization header (tried multiple times, with and without client_id in request body to be sure this is not the issue) i still receive invalid-credentials. So no, I don't think MitreID connect allows it today even if in configuration screen it shows this option.

stefanocke commented 4 years ago

Related to https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server/issues/611 (it seems to have been fixed there some years ago, but maybe other things have changed meanwhile...?)

thiswastaken commented 1 year ago

Please correct me if I'm mistaken, but I think there's a difference between "No Authentication" and "No Client Secret". Per 3.2.1, In the "authorization_code" "grant_type" request to the token endpoint, an unauthenticated client MUST send its "client_id" to prevent itself from inadvertently accepting a code intended for a client with a different "client_id".

This suggests that the server should require client_id to specified even if there's no client_secret. It seems the server can chose how this should be specified (in the body, or an an Authorization header). Note that tools such as insomnia and postman do include the client_id and have the option to do so in the body or as an Authorization header.