I’m trying to get an OAuth2 access token using the grant type client credentials.
I’ve put the details into environment variables and I’m able to get the token with a humble curl request:
$ curl -X POST -u "$CLIENT_ID:$CLIENT_SECRET" -d "grant_type=client_credentials" https://$HOST$TOKEN_URI_SUFFIX
However, if I try the same with Crystal it fails.
host = ENV["HOST"]
client_id = ENV["CLIENT_ID"]
client_secret = ENV["CLIENT_SECRET"]
token_uri_suffix = ENV["TOKEN_URI_SUFFIX"]
oauth2_client = OAuth2::Client.new(
access_token = oauth2_client.get_access_token_using_client_credentials
rescue ex : OAuth2::Error
$ crystal oauth2-test.cr [14:16:54]
<meta name="viewport" content="width=device-width, initial-scale=1">
I would be interested to know if anyone is able to use the
OAuth2::Client#get_access_token_using_client_credentials method succesfully (and if so, please let me know what I’m doing wrong) or reproduce this issue?
TOKEN_URI_SUFFIX contain any query parameters? I could imagine the current implementation loosing or incorrectly encoding anything but the path component. Does passing the fully composed URI as
token_uri work for you?
TOKEN_URI_SUFFIX does not contain any query parameters.
I get the same result if I fully compose the URI (
Ah, I see the difference now.
OAuth2 posts the
client_secret as a
application/x-www-form-urlencoded body to the endpoint instead of using them for HTTP basic authentication.
The spec describes either behavior with a MAY https://tools.ietf.org/html/rfc6749#section-2.3.1 but it has a SHOULD on preferring the HTTP basic way, so we probably should default to that while still giving an option to include it in the request body for servers that don’t support HTTP basic authentication. I would say a pull request for this is welcome :)
I’m afraid for now your best bet is reimplementing
OAuth2::Client or monkey-patching https://github.com/crystal-lang/crystal/blob/master/src/oauth2/client.cr#L147-L166
OK - just to confirm that I got it working with a monkey patch.
I will create a PR for changes to
OAuth2 (hopefully in the next week or so).
@jhass having re - read the spec again, it says:
Including the client credentials in the request-body using the two parameters is NOT RECOMMENDED and SHOULD be limited to clients unable to directly utilize the HTTP Basic authentication scheme (or other password-based HTTP authentication schemes).
Since it says clients (not servers), and since a Crystal client will be capable of
HTTP Basic authentication, my reading is that the Crystal OAuth2 library should always use
Do you agree?
This would also have the advantage that there would be no need to change the API of the OAuth2::Client.
I think it would be acceptable, but given the landscape of OAuth2 I’ve seen in the wild I would prefer still having the option I think. It should be possible to make it an optional named parameter, so no real API change unless your server is buggy and requires the current implementation :)
OK, I’ll do it with an option then