According to the spec, requests for a token using the authorization code grant are not required to be authenticated as long as the client_id
is included in the request and the client_id
is the same one used to generate the code. However, with the Spring Security OAuth 2.0 implementation, it appears that basic auth is always required on the /oauth/token
endpoint even if the client was never assigned a secret.
It looks like there is support for allowing clients without a secret due to the isSecretRequired()
method in the ClientDetails
interface. What do I need to do to enable clients without a secret to be authenticated at the /oauth/token
URL?
4.1.3. Access Token Request
The client makes a request to the token endpoint by sending the
following parameters using the "application/x-www-form-urlencoded"
format per Appendix B with a character encoding of UTF-8 in the HTTP
request entity-body:grant_type REQUIRED. Value MUST be set to "authorization_code".
code REQUIRED. The authorization code received from the authorization server.
redirect_uri REQUIRED, if the "redirect_uri" parameter was included in the authorization request as described in Section 4.1.1, and their values MUST be identical.
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.
Authenticating the client using the form parameters instead of basic auth is enabled using the
allowFormAuthenticationForClients()
method as shown in the code sample below.The
allowFormAuthenticationForClients()
method triggers the addition of theClientCredentialsTokenEndpointFilter
which allows for authentication via form parameters.Spring allows you to define OAuth2 clients with an empty secret. These can be considered "public" clients, or clients that are unable to keep a secret. Think of Javascript apps, mobile apps, ..... You typically don't want to have client secrets stored there.
As you point out, according to the OAuth2 spec, a token endpoint can opt to not require a secret for these public clients.
So in Spring, simply define an OAuth2 client with an empty secret, and configure it for a limited set of grant types (authorization_code and refresh_token)
The Spring Security implementation token url will accept a token exchange without a client secret for that particular OAuth2 client.
Initially I had a similar setup to the accepted answer, which is definitely a prerequisite to make this work. But what is missing is that you cannot simply set the password to null. You must set it to an empty password, for example like this:
If you don't do this, you will still get a 401!
like this:
It is ok.
In order to solve the issue see the method
loadUserByUsername
of class:org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService
:Probably in your case
emptyPassword
has not been initialized with empty encoded password by your password encoder. Set missing password encoder inAuthorizationServerConfigurerAdapter
: