Open siennathesane opened 6 years ago
Sorry for this long post, but I just want to help you get this implementation right.
In addition to supporting x-www-form-urlencoded POST bodies, OAuth implementations MUST also support HTTP Basic authentication.
According to the RFC:
Clients in possession of a client password MAY use the HTTP Basic authentication scheme as defined in [RFC2617] to authenticate with the authorization server. The client identifier is encoded using the "application/x-www-form-urlencoded" encoding algorithm per Appendix B, and the encoded value is used as the username; the client password is encoded using the same algorithm and used as the password. The authorization server MUST support the HTTP Basic authentication scheme for authenticating clients that were issued a client password.
First, note that clients MAY use HTTP Basic authentication, but authorization servers MUST support it.
Second, note that the client identifier (client_id
) is encoded using the "application/x-www-form-urlencoded" encoding. This does not mean that the client_id
must be sent in the HTTP POST body. It just defines how the client_id
must be encoded when used with HTTP Basic authentication. The RFC clarifies this later.
Third, the client_id
(that was encoded using x-www-form-urlencoded) is used as the username in HTTP Basic authentication. The client password (client_secret
) is also encoded using x-www-form-urlencoded and used as the password in HTTP Basic authentication. Again, this is just referring to how the username and password are encoded, not how they are sent in the HTTP request.
The RFC goes on to say:
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). The parameters can only be transmitted in the request-body and MUST NOT be included in the request URI.
Note that the RFC recommends that client credentials are NOT sent in x-www-form-urlencoded POST bodies.
Here's an example:
client_id
is dCSQFR0i0mn3Gfd0o789OT+8
.client_secret
is AMr2mzyWCVIZF2wBkycimf/k
.The client_id
is encoded using the x-www-form-urlencoded algorithm. The result is dCSQFR0i0mn3Gfd0o789OT%2B8
.
The client_secret
is also encoded using the x-www-form-urlencoded algorith. The result is AMr2mzyWCVIZF2wBkycimf%2Fk
.
Note that the encoded client_id
and client_secret
contain %2B
and %2F
where there was a +
and /
respectively. If your implementation only generates client credentials that don't contain characters that need to be escaped by the x-www-form-urlencoded algorithm, then you can skip the step of encoding them.
Next, the encoded client_id
and client_secret
are further encoded using HTTP Basic authentication. To do this, take the client_id
, append a :
character, append the client_secret
, then Base64 encode the whole result. In this example, that would be dCSQFR0i0mn3Gfd0o789OT%2B8:AMr2mzyWCVIZF2wBkycimf%2Fk
, which is Base64 encoded to am9yZGFuYnR1Y2tlckBnbWFpbC5jb206TkZQOVkjR3VYcGR4b1NSUjhGKms=
.
Finally, the HTTP header looks like this:
Authorization: Basic am9yZGFuYnR1Y2tlckBnbWFpbC5jb206TkZQOVkjR3VYcGR4b1NSUjhGKms=
Putting all of that together looks like this:
'Authorization: Basic ' + Base64(UrlEncode(client_id) + ':' + UrlEncode(client_secret))
You may conclude that, since the x-www-form-urlencoded algorithm only refers to the encoding of the client_id
and client_secret
before they are used with HTTP Basic authentication, there is no need to support x-www-form-urlencoded POST bodies.
However, OAuth implementations must still support x-www-form-urlencoded POST bodies for other parameters like grant_type
or username
or password
. You can see an example given in section 4.4.2:
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
Note that there is no client_id
or client_secret
in the POST body. They are instead included in the HTTP Authorization header.
RFC 6749, which defines the OAuth2 framework, states OAuth endpoints must accept
application/x-www-form-urlencoded
and may returnapplication/json
. Currently, the endpoint only acceptsapplication/json
, which makes it non-compliant with the RFC and a lot of standard library clients across varying languages.Currently the Q Cloud authentication API doesn't work in Go with RFC-compliant, standard library client due to the incorrect mime type being accepted:
Returns this error:
Changing the server mime type from
application/json
toapplication/x-www-form-urlencoded
should resolve the problem.