Suppose that a front-end server (“A”) is sending an HTTP request to another server (“B”) to process the request and return some response, and that B needs to know on whose behalf A is making that request. This is an “identity assertion” problem. Though this problem is quite common in the HTTP/REST/API-era, the solution is still DIY. Here are some ways to support this.
- Pass whatever token that A received from its clients (such as browsers) to B.
For instance, if A is using a Cookie (which may contain an encrypted version of the user’s identifier) as an authentication token, then A could send the same token to B.
# Browser making a request to A
GET /some-page HTTP/1.1
Host: www.example.org
Cookie: xyz
# A making a request to B
GET /some-resource?some-path HTTP/1.1
Host: some-internal.example.org
Cookie: xyz
This is fairly simple to implement as long as A can entrust B with a user’s authentication token and that the transport is secure either at the network level or physically so that cookies are not leaked to others. Another downside is that this approach couples B to A’s authentication mechanism.
- Use basic authentication.
This is a bad idea since it requires A to store user credentials in plain text or in an encrypted form.
- Use OAuth 1.0 style
Authorizationheader to assert user identity.
This requires a custom HTTP authorization scheme to pass the user’s identifier along with a signature.
# A making a request to B
GET /some-resource?some-path HTTP/1.1
Host: some-internal.example.org
Authorization: MyIdentityAssertion client_id="client001",
assertion="joe001",
signature="xyz"
signature_method="HMAC-SHA1",
timestamp="...",
nonce="..."
where client_id is an identifier assigned to A by B, assertion is the user’s identifier, and signature is a signature using a secret shared between A and B. This approach is similar to the so-called two-legged OAuth. In the OAuth case, the oauth_token – equivalent to the signature above – contains a signature of the Signature Base String where as in the above, it is just the user’s identifier.
This approach is as easy to implement, and keeps B independent of A’s authentication scheme.
- Use TLS in stead of signatures as in OAuth 2.0
This is similar to the previous approach but without the signature, and using TLS.
# A making a request to B
GET /some-resource?some-path HTTP/1.1
Host: some-internal.example.org
Authorization: MyIdentityAssertion joe001
All these approaches leave it up to B whether to trust the assertion passed by A, and that’s what assertions are about.
{ 4 comments… read them below or add one }
Is there a requirement to use the Authorization header for this kind of identity assertion? I prefer to use it for Authentication of the actual client making the request, i.e. auth’ing A to B.
A while back I designed something similar to this that, instead of using the Authorization header, added another header to the request from A to B that just links to a URI identifying the original client, e.g:
X-Origin-Client: “https://example.com/users/fred”
Of course that might be better suited to the link header now, i.e:
Link: https://example.com/users/fred;rel=originClient
Thoughts?
Cheers,
Mike
@Mike – the protocol aspects are clear in RFC-2617. The Authorization header is meant for carrying credentials, and what is encoded in there depends on the scheme. Some schemes may incorporate typical authorization controls (like permissions) – and OAuth2 is a great example as the OAuth’s access token encompasses scopes.
Subbu,
How about a client-side cert for B stored on A and using SSL? Would that work?
Dan
@Dan – certainly, with the last option. Mutual auth with TLS can be used at the transport level to mutually authenticate A and B, with the Authorization header in the protocol (HTTP) used for carrying credentials/identifiers of the user.