Skip to content

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

Open
@StdVectorBool

Description

@StdVectorBool
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());
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions