Trying to find information about this. I'm wondering what format the OAuth2 Access Token is, or should be. Is it ok to use JWT format for the Access Token?
OAuth does not specify the access token itself, the format is opaque to the protocol flow. It can be any thing you want, e.g. a JWT if you want it to be self-contained.
Related
I'm using OpenID Connect to control access to my REST API. One of the things I need to do when servicing a request is get the OIDC UserInfo based on the access token in request's Authorization: Bearer ... header.
To this point I've been working with JWTs and this works fine. I'm looking at expanding this to work with opaque tokens as well.
My strategy has been based on my understanding of the OpenID Connect Discovery spec, section 4:
Extract the iss from the access token.
Discover the userinfo endpoint by getting ${iss}/.well-known/openid-configuration and querying the JSON for userinfo_endpoint.
HTTP GET the userinfo_endpoint, passing the access token as an Authorization: Bearer ... header.
This works fine for opaque tokens... except for step 1. Currently, I have to know who the issuer is via an out-of-band mechanism because I don't know how to get the issuer from the opaque token (which, to be honest, makes sense given that it's opaque). I see a few possibilities:
Maybe I'm just supposed to know who issued it and my question is misguided.
Maybe the best thing to do is try a list of known issuers and see if one of them works.
Maybe there's a mechanism for discovering the issuer of the opaque token. (The spec refers to WebFinger, but that doesn't seem like it fits my use case.)
Maybe there's something I haven't considered...
Thanks all for any help.
The standard mechanism for dealing with opaque tokens is via introspection. Also the preferred option is for there to only be a single type of access token - issued by your Authorization Server (AS), which sits alongside your APIs.
The introspection result can be a claims payload or a JWT. It is common to plug in an API gateway, as in this article, so that the gateway makes the actual introspection call. The gateway should then cache results for subsequent calls made with the same access token.
An opaque token is typically a GUID or something similar, and the issuer value is not stored in the token - it is instead stored in the issuing Authorization Server's back end state. The only way to determine the issuer is to try to introspect the token.
FOREIGN ACCESS TOKENS
Aim to avoid using foreign access tokens in your APIs as in the following examples. This can make it difficult to control data added to tokens and token lifetimes:
User signs in with Google - then API uses Google access tokens
User signs in with Microsoft - then API uses Microsoft access tokens
It is preferred instead to use 'federated login capabilities' of your Authorization Server, leading to the following cleaner result, and fewer issues:
User signs in with Google - then API uses your AS access tokens
User signs in with Microsoft - then API uses your AS access tokens
Answering my own question:
You cannot discover anything from an opaque token alone.
An opaque token could be anything, even just a UUID that serves as a key to a database table in the Authorization Server. The only way anything can be obtained with such a token is by calling the introspection endpoint.
(Even if there is anything encoded in the opaque token, the only way it should be decoded is by calling the introspection endpoint.)
To that extent, my original question was somewhat misguided in that I was attempting to decode something that doesn't intrinsically express its encoding. It's rather like trying to use a pointer without knowing what it points to. Indeed, I've found a number of places where the term "reference token" is used to mean "opaque token."
Thanks to Gary Archer for some helpful feedback.
I have 2 internal Rails services, which need to speak to each other.
I need an advice how to make it secure enough and with minimum effort.
Currently service A sends Authorization HTTP header to service B, which contains secret token. Simple HTTP Token-based method, nothing special. But I also need somehow to communicate a user token, so service B will know, which user is talking to it.
My current solution is following:
send Authorization Token token=blabla user_token=blabla2
use existing in Rails methods to parse it
identify user by provided user_token
inspired by this StackOverflow post
Alternatives:
Amazon way with something like: Authorization: MY-APP-V1 Token=blabla Credential=user_token, but I need custom parser for it.
Custom HTTP header like X-USER-TOKEN, but seems like RFC is not in favor of this idea.
Your proposal or suggestion
Thank you very much for any help.
I'm curious as to why the user token is not enough, can you elaborate on this?
But assuming you want to continue with the double-token approach, something like JWT could be used to encode the user token with the secret token. That way you will just have 1 token and can send it simply as Authorization: Bearer xxxxxx.
I am adding JWT Auth for a completely new frontend to a legacy Rails backend.
Upon HTTP request, it seems most sources suggest I send the token back to the server via Bearer Header.
Why? What is the additional value of sending via header (bearer or basic). What can't I simply pass the JWT back to the server via .json and authenticate the token from there.
What benefit does an Authorization header give me, and moreso, what does a Bearer Authorization header give me?
I can of course simply follow everyone's example, but want to understand why. The bearer docs are verbose and hard to understand what I'm gaining over simple sending the JWT as part of the data in the request.
Thank you.
You can technically send a json body on each request with the JTW but that would be non standard behaviour (for instance, GET requests should not have a body via the spec).
A more standard way would be to provide an Authorization HTTP header.
The Authorization header is not specific to JWTs and its role is to specify an auth scheme between the client and the server.
Another way would be to include the JWT inside a cookie but that would make the behaviour browser specific while the HTTP header can be sent by virtually any HTTP client.
P.S
Bear in mind that contrary to Auth cookies which are sent by the browser automatically the Authorization header needs to be set by the client explicitly.
I'm trying to use OAuth. In this example the provider was Windows Live. The redirect returned this fragment. I have added line breaks before the ampersands to make it a bit easier to read.
access_token=EwAwA61DBAAUGCCXc8wU/zFu9QnLdZXy%2bYnElFkAAQcQQB3c7oVYQmQhyeTOiw1Tp5iA7cjrLJbEnvXVoDlu48mjv7WX35RRIK3L3miAQEUrn5ZVNRSUV8dqiZi4kIko93k2bODqpIY7r/nBRmnTTbInajZm0iF1FLjXaFJGzM/XJN4jZiZUtipwaNu66cSwbEhNVUWwZufHjE7SNDUQze3/ciGP9c%2bTampSUS23u%2bcuKrCbj8jPhFIj2Tbritf83YcVaXLJHpEYVz2a1GKHm8/TPot2MgcjD3yBOBd5b/QBImASEcdOpouiYIshi1Ddy20iYL1Jv6JRpPExeWd8q9sEfk4a%2btMHIPFJ%2bdy0e6X9nRMjlx%2bHP0FhUrOp4rADZgAACD41pKeivbukAAIVEy964MrcJsT6MwfHHf54bi9Nfhek/vARUG32qt1HId/3GgYDKcXblAk6I7qW%2boywDMa%2bck59pJms7/pEGqSkLtY%2b5M86%2bWvSG9bNAJWfQnKT1re5L4AxpbJ2J7JOw9md%2byBnt9I3hk%2bQGoY4ZoSMTtZ2QOxIH0rfgxVqrebUjAcCf1AIl7yBusgF1zJITPTBX1fLaEw48VjXjNygQq/N82%2baKZhU2ZMBTtUzgnod4SMrb/IOaQsDF6prVTihGHae6rbRL/Ul4C/au59NAijEBB9evjM6PxSMMpMmag6VTXdVeLeCBFitFwcjtRUH38yIuhPGalBnRTVHyLpm8cS06mrQM2n5j9XnMFBtQzEQEtdvtOsUkIgpVYmqZE38CEh9YAjJBxG1Xo9Pdz/DnHflfc3PWtO1xMZsP/krBMQFxQRTPBOiNv%2bH2DPF1TED35iW%2bS5VDbxjSur1dCVAPqv3Vbduia1moJ1AUYPm9P7%2bcY%2bIV3skuz4Dzk0zQPgU3h7N6zPwr0oi%2bNe548sk6Cqq/wbF7oV6ytuAc0fbedf49I7QA8x8BEruePwNWj2N6v2vJQqQm6fOC%2by7ZQSsJ9830hD6E5yp4YVht%2bux%2b8wu%2bDQ9x/VB6BXLNC%2b4Q2aIhDQmui/JMrgHXgo2okv9FywwVQdaSLXVasfrCVmqzDwGFhIC
&token_type=bearer
&expires_in=3600
&scope=wl.signin%20wl.emails
&user_id=AAAAAAAAAAAAAAAAAAAAAB1EauoOQMnYy_bu42gkx90
&state=STATE
and I parsed that into name value pairs applying decodeURIcomponent to each.
That gave me an access_token value of
EwAwA61DBAAUGCCXc8wU/zFu9QnLdZXy+YnElFkAAQcQQB3c7oVYQmQhyeTOiw1Tp5iA7cjrLJbEnvXVoDlu48mjv7WX35RRIK3L3miAQEUrn5ZVNRSUV8dqiZi4kIko93k2bODqpIY7r/nBRmnTTbInajZm0iF1FLjXaFJGzM/XJN4jZiZUtipwaNu66cSwbEhNVUWwZufHjE7SNDUQze3/ciGP9c+TampSUS23u+cuKrCbj8jPhFIj2Tbritf83YcVaXLJHpEYVz2a1GKHm8/TPot2MgcjD3yBOBd5b/QBImASEcdOpouiYIshi1Ddy20iYL1Jv6JRpPExeWd8q9sEfk4a+tMHIPFJ+dy0e6X9nRMjlx+HP0FhUrOp4rADZgAACD41pKeivbukAAIVEy964MrcJsT6MwfHHf54bi9Nfhek/vARUG32qt1HId/3GgYDKcXblAk6I7qW+oywDMa+ck59pJms7/pEGqSkLtY+5M86+WvSG9bNAJWfQnKT1re5L4AxpbJ2J7JOw9md+yBnt9I3hk+QGoY4ZoSMTtZ2QOxIH0rfgxVqrebUjAcCf1AIl7yBusgF1zJITPTBX1fLaEw48VjXjNygQq/N82+aKZhU2ZMBTtUzgnod4SMrb/IOaQsDF6prVTihGHae6rbRL/Ul4C/au59NAijEBB9evjM6PxSMMpMmag6VTXdVeLeCBFitFwcjtRUH38yIuhPGalBnRTVHyLpm8cS06mrQM2n5j9XnMFBtQzEQEtdvtOsUkIgpVYmqZE38CEh9YAjJBxG1Xo9Pdz/DnHflfc3PWtO1xMZsP/krBMQFxQRTPBOiNv+H2DPF1TED35iW+S5VDbxjSur1dCVAPqv3Vbduia1moJ1AUYPm9P7+cY+IV3skuz4Dzk0zQPgU3h7N6zPwr0oi+Ne548sk6Cqq/wbF7oV6ytuAc0fbedf49I7QA8x8BEruePwNWj2N6v2vJQqQm6fOC+y7ZQSsJ9830hD6E5yp4YVht+ux+8wu+DQ9x/VB6BXLNC+4Q2aIhDQmui/JMrgHXgo2okv9FywwVQdaSLXVasfrCVmqzDwGFhIC
As I understood it, at this point all I have to do is add a header Authorization: Bearertoken value but doing so for a route protected by `[Authorization] produces 401 Unauth with a type of Basic. This leaves me at a bit of a loss as to how to proceed.
Looking at the browser debug info I see
WWW-Authenticate: Bearer error=invalid_token
Does the token being invalid mean this is an inappropriate token or that it can't be parsed as a token?
Is my methodology so far correct?
Is there some kind of server configuration I need to make?
Suggested next steps?
The Access token looks a bit like Base64 but it's not valid base64, I checked. Just thinking about the nature of a token, it's probably just the claims encrypted with the token issuer's private key. If that were so you could check the integrity of a token by decrypting the token using the issuer's public key, but I can't see how to use this observation to figure out why I have a 401.
Update
This is the startup.cs code that introduces token checking
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
SaveToken = true,
TokenValidationParameters = tokenValidationParameters
});
and this auth0 web page cannot decode my token as a JWT token. Further reading suggests that a JWT token has three dot-separated sections each base64 encoded, and this is simply not present in the tokens I'm receiving from both Windows Live and Google (I've tested with both now).
So perhaps I need to restructure the token request if I want JWT tokens. More on this next episode. Feel free to write the next episode as an answer, if you know what I ought to be doing, endpoint and parameters etc. This other question What is the difference between id_token and access_token in Auth0 appears to be salient.
An access_token is what is says on the box - a token for access to a particular resource.
A JWT is an identity token. To get one of those, what I need to do is
use this endpoint: https://login.microsoftonline.com/common/oauth2/v2.0/authorize
specify a response_type of id_token
Include a nonce
Specify a scope of openid.
But returning to the question of how to use an access token, you use it as a bearer token in the authorization header in a requestion to the provider's endpoint for the scope in question, eg wl.email
When an OAuth signed request is made to a Rails 3 app, I can see the OAuth consumer key in amongst the other values in request.headers["HTTP_AUTHORIZATION"]. What is a better way to access it? I'm using the OAuth gem.
According to this section in the OAuth specification, the Authorization header is the preferred way of sending OAuth protocol parameters. The specification does make allowances for sending protocol parameters in a form encoded body or in the request URI, if the request meets certain requirements.
To answer your question: parsing the Authorization header is a must for any OAuth provider. But you may also look for it (and other protocol parameters) amongst "normal" parameters, you will never find them in more than one place,