HTTP Authentication: a client-server story
You’re a client talking to an http server, and you get a 401: unauthorized.
How are you supposed to know how to authenticate?
RFC 7235 has you covered. Let’s review.
1. 401 and Authorization header
Along with the 401: unauthorized http response, the server must be setting the following header telling you how to authenticate:
-
www-authenticate: <challenge>,<challenge>
Where challenge
tells you which kind of authentication is expected.
More than one challenge can be received, meaning that the client may chose one of them.
1.1. Challenge and Schemes
Challenges are linked to authorization schemes, which are standardized by IANA.org.
Each challenge has the following format:
scheme <options>
where the accepted options
depend on the scheme itself.
1.2. Basic Scheme
With Basic Authentication, the only required option is realm
, and the scheme
name is Basic
:
GET /resources HTTP/2
Host: website.org
HTTP/2 401 Unauthorized
WWW-Authenticate: Basic realm="whatever"
This indicates that you need to send an Authorization
header:
GET /resources HTTP/2
Host: website.org
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQK
HTTP/2 200 Ok
Note: What is the realm
option? Really depends on the scheme, but for Basic
it’s a way to let specific the scope/partition onto which this authentication
will work for. Imagine something like some servers needing one kind of username
and password (for example, a github account), and some servers needing a different
kind of username and password (for example, a windows account): the server can
use the realm
to indicate to the client that this is the case.
1.3. OAuth2 and Bearer scheme
In the wild, you’re more likely to encounter the OAuth 2 nowadays, with its Bearer
scheme:
GET /resources HTTP/2
Host: website.org
HTTP/2 401 Unauthorized
WWW-Authenticate: Bearer realm="whatever", scope="openid profile email"
2. 407 and Proxy-Authorization header
If the client is talking to a proxy, the same is true, but with a code 407
,
and header Proxy-Authenticate
header:
GET /resources HTTP/2
Host: website.org
HTTP/2 407 Proxy Authentication Required
Proxy-Authenticate: Basic realm="Access to internal site"
This time, you the client needs to fill-in the Proxy-Authorization
header:
GET /resources HTTP/2
Host: website.org
Proxy-Authorization: Basic cHJveHktdXNlcm5hbWU6cHJveHktcGFzc3dvcmQK
HTTP/2 200 Ok
Note: the client may have to proxy both the Authorization
header and the
Proxy-Authorization
header in some scenarios.
3. Reality and shortcomings
In reality, not all servers will actually return a WWW-Authenticate
header,
leaving the client in the dark about how to go forward with the authentication.
Even if the server does return such a header, the specification is quite open, and doesn’t require telling the client how or where to get the authorization data.
For example, the realm
part of the Basic
scheme could tell the client which
type of account is required, but the client and server must understand each other
about its meaning.
In the OAuth 2, the scope
option of the Bearer
scheme is often used to indicate
which kind of rights is required in the token expected by the server, but the
server doesn’t tell you what is the endpoint to target to generate such a token.
Yet, if you work on a server, make sure your server does return a WWW-Authenticate
.