# Can't get OAuth2 access token with grant type client credentials

**URL:** <https://forum.crystal-lang.org/t/cant-get-oauth2-access-token-with-grant-type-client-credentials/1958>\
**Category:** Help & Support\
**Created:** [April 14, 2020, 1:37pm UTC](https://forum.crystal-lang.org/t/cant-get-oauth2-access-token-with-grant-type-client-credentials/1958 "2020-04-14T13:37:39Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![crush-157](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/crush-157/32/796_2.png) [@crush-157](https://forum.crystal-lang.org/u/crush-157)\
**Post date:** [April 14, 2020, 1:37pm UTC](https://forum.crystal-lang.org/t/cant-get-oauth2-access-token-with-grant-type-client-credentials/1958/1 "2020-04-14T13:37:39Z")

</div>

Hi,

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:

```auto
$ curl -X POST -u "$CLIENT_ID:$CLIENT_SECRET" -d "grant_type=client_credentials" https://$HOST$TOKEN_URI_SUFFIX     
{"access_token":"S-OW6C7WwIR0Kl_d9PMIjg","token_type":"bearer","expires_in":3600}

```

However, if I try the same with Crystal it fails.

Code:

```auto
require "oauth2"

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(
  host: host,
  client_id: client_id,
  client_secret: client_secret,
  token_uri: token_uri_suffix
)

begin
  access_token = oauth2_client.get_access_token_using_client_credentials
rescue ex : OAuth2::Error
  puts ex.class
  puts ex.message
end

```

Result:

```auto
$ crystal oauth2-test.cr [14:16:54]
OAuth2::Error
<!DOCTYPE html>
...
<head>
	<title>Unauthorized</title>
	
	<meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
...

```

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?

---

<div class="post-metadata">

**Author:** ![jhass](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jhass/32/1779_2.png) [@jhass](https://forum.crystal-lang.org/u/jhass)\
**Post date:** [April 14, 2020, 1:59pm UTC](https://forum.crystal-lang.org/t/cant-get-oauth2-access-token-with-grant-type-client-credentials/1958/2 "2020-04-14T13:59:12Z")

</div>

Does `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?

---

<div class="post-metadata">

**Author:** ![crush-157](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/crush-157/32/796_2.png) [@crush-157](https://forum.crystal-lang.org/u/crush-157)\
**Post date:** [April 14, 2020, 2:40pm UTC](https://forum.crystal-lang.org/t/cant-get-oauth2-access-token-with-grant-type-client-credentials/1958/3 "2020-04-14T14:40:47Z")

</div>

No the `TOKEN_URI_SUFFIX` does not contain any query parameters.

I get the same result if I fully compose the URI (`token_uri: "https://#{host}#{token_uri_suffix}"`)

---

<div class="post-metadata">

**Author:** ![jhass](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jhass/32/1779_2.png) [@jhass](https://forum.crystal-lang.org/u/jhass)\
**Post date:** [April 14, 2020, 3:12pm UTC](https://forum.crystal-lang.org/t/cant-get-oauth2-access-token-with-grant-type-client-credentials/1958/4 "2020-04-14T15:12:10Z")

</div>

Ah, I see the difference now. `OAuth2` posts the `client_id`and `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](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](https://github.com/crystal-lang/crystal/blob/master/src/oauth2/client.cr#L147-L166)

---

<div class="post-metadata">

**Author:** ![crush-157](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/crush-157/32/796_2.png) [@crush-157](https://forum.crystal-lang.org/u/crush-157)\
**Post date:** [April 14, 2020, 10:43pm UTC](https://forum.crystal-lang.org/t/cant-get-oauth2-access-token-with-grant-type-client-credentials/1958/5 "2020-04-14T22:43:05Z")

</div>

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).

---

<div class="post-metadata">

**Author:** ![crush-157](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/crush-157/32/796_2.png) [@crush-157](https://forum.crystal-lang.org/u/crush-157)\
**Post date:** [April 15, 2020, 8:30pm UTC](https://forum.crystal-lang.org/t/cant-get-oauth2-access-token-with-grant-type-client-credentials/1958/6 "2020-04-15T20:30:00Z")

</div>

@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).

(my italics)

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 `HTTP Basic`.

Do you agree?

This would also have the advantage that there would be no need to change the API of the OAuth2::Client.

---

<div class="post-metadata">

**Author:** ![jhass](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jhass/32/1779_2.png) [@jhass](https://forum.crystal-lang.org/u/jhass)\
**Post date:** [April 16, 2020, 8:48am UTC](https://forum.crystal-lang.org/t/cant-get-oauth2-access-token-with-grant-type-client-credentials/1958/7 "2020-04-16T08:48:05Z")

</div>

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 :)

---

<div class="post-metadata">

**Author:** ![crush-157](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/crush-157/32/796_2.png) [@crush-157](https://forum.crystal-lang.org/u/crush-157)\
**Post date:** [April 16, 2020, 10:03am UTC](https://forum.crystal-lang.org/t/cant-get-oauth2-access-token-with-grant-type-client-credentials/1958/8 "2020-04-16T10:03:42Z")

</div>

OK, I’ll do it with an option then 🙂

---

<div class="post-metadata">

**Author:** ![crush-157](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/crush-157/32/796_2.png) [@crush-157](https://forum.crystal-lang.org/u/crush-157)\
**Post date:** [April 18, 2020, 8:49pm UTC](https://forum.crystal-lang.org/t/cant-get-oauth2-access-token-with-grant-type-client-credentials/1958/9 "2020-04-18T20:49:52Z")

</div>

@jhass [https://github.com/crystal-lang/crystal/pull/9127](https://github.com/crystal-lang/crystal/pull/9127)
