Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Java][Retrofit2] OAuth does not support Client ID and Secret as HTTP Basic Auth #7648

Open
StdVectorBool opened this issue Feb 13, 2018 · 2 comments

Comments

@StdVectorBool
Copy link

StdVectorBool commented Feb 13, 2018

Description

The Java clients using Oltu (Feign, Retrofit, Retrofit2) always send the Client ID and Secret in the url-encoded body during the Client Credential flow. This fails for strict OAuth2 server implementations that require it in the HTTP Basic Auth header and reject its appearance in the body.

The OAuth2 RFC 6749 - Section 2.3.1 states:

The authorization server MUST support the HTTP Basic
authentication scheme for authenticating clients that were issued a
client password.

...

Alternatively, the authorization server MAY support including the
client credentials in the request-body using the following
parameters:

Swagger-codegen version

2.2.1

Suggest a fix/enhancement

The problem lies partially in Oltu, but this line in OAuth.updateAccessToken is where the issue starts:

  OAuthJSONAccessTokenResponse accessTokenResponse = oauthClient.accessToken(this.tokenRequestBuilder.buildBodyMessage());

A workaround is to override TokenRequestBuilder:

public OAuthClientRequest buildBodyMessage() throws OAuthSystemException {
  // constructor is not not visible here, so let the parent create it
  OAuthClientRequest message = super.buildBodyMessage();

  // now undo what the parent did...
  Map<String, Object> paramsNoAuth = new HashMap<String, Object>(this.parameters);
  paramsNoAuth.remove(OAuth.OAUTH_CLIENT_ID);
  paramsNoAuth.remove(OAuth.OAUTH_CLIENT_SECRET);
		
  String body = OAuthUtils.format(paramsNoAuth.entrySet(), "UTF-8");
  message.setBody(body);
  
  // add basic-auth client_id:client_seret
  String id = (String) parameters.get(OAuth.OAUTH_CLIENT_ID);
  String secret = (String) parameters.get(OAuth.OAUTH_CLIENT_SECRET);
  String credentials = id + ":" + secret;
  String base64Credentials = Base64.getEncoder().encodeToString(credentials.getBytes());
  message.addHeader("Authorization", "Basic " + base64Credentials);
  return message;
}

Then change the generated OAuthOkHttpClient to read those headers (as the Oltu URLConnectionClient does )

// existing code
if(headers != null) {
    for (Entry<String, String> entry : headers.entrySet()) {
        if (entry.getKey().equalsIgnoreCase("Content-Type")) {
            mediaType = MediaType.parse(entry.getValue());
        } else {
            requestBuilder.addHeader(entry.getKey(), entry.getValue());
        }
    }
}

// added code
if (request.getHeaders() != null) {
    for (Entry<String, String> entry : request.getHeaders().entrySet()) {
        if (entry.getKey().equalsIgnoreCase("Content-Type")) {
            mediaType = MediaType.parse(entry.getValue());
        } else {
            requestBuilder.addHeader(entry.getKey(), entry.getValue());
        }
    }
}
@StdVectorBool
Copy link
Author

Slightly less ugly patch to the generated sources: gist

@cbornet @wing328 is it likely this change would be accepted for the generator templates?

@cbornet
Copy link
Contributor

cbornet commented Feb 16, 2018

Agreed. The default should be to use basic auth with an apiclient option to switch to query params (I know some incorrect oauth2 servers that only support the latter)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants