15

Why was the decision taken that the Client doesn't need to be able to parse the access token?

It seems to me that if the token included, in addition to the current fields, a client_id and a user_id, it would make life much simpler, prevent spoofing, enable authentication, etc.

I've noted that as per section 1.4 of RFC 6749 it does not HAVE to be opaque, but it seems to me that much of OpenID Connect, if not all of it, is a way of making the Access Token into something meaningful. Yes, it adds an ID token, but the fact that it is implemented as something accompanying in stead of embedded in the access token does not change this fact. It seems every video, tutorial and blog post talks about it as if that is to be assumed to be the case (that access tokens will be opaque, because "The client is not the intended audience") ... And yet it is the API or resource provider who cannot establish authentication based on the the bearer having the token.

Actually I need to add that I don't think the token being opaque to the client is the problem. The problem is that the token is a bearer token that doesn't restrict WHO can use it.

2 Answers 2

19

In OAuth, or any other protocol where the token can be opaque or transparent, the benefits and risks swing based on what your desired result is:

  • If you want the client to be able to parse the access token, you need the token to be transparent.
  • If you don't want the client to be able to parse the access token, you need the token to be opaque.

Indeed, this is the definition of opaque and transparent tokens; the client can see into them, or not.

If your token is transparent, you must sign it, otherwise, anyone could simply edit your token contents, and claim anything they want.

So, the first obvious benefit of having an opaque token is that you can just throw away any signing mechanism; you don't need it, and conversely, if you have a proper transparent token, the client can read the token, but not edit it.

Another benefit of having an opaque token is it is more secure; No encryption method is truly random (i.e., there must be a way to decrypt it), meaning you can always tell which encryption protocol is used if you can read enough of the contents of the tokens (transparent tokens). This itself reduces the time to identify your cipher (knowing the protocol). Many people don't think this is very risky, and indeed, if you use more than 80 bits of entropy, they are right (10 truly random characters for your cipher, i.e. "secret key").

However, and this is much more of a risk; transparent tokens allow crackers to play with the contents (because they see them), and some protocols have serious weaknesses that allow you to create collisions or even decode the cipher in a much shorter period because the cracker will know the protocol as well as the contents of valid blocks (most encryption protocols use 16 byte-long blocks, so if your token contains 160 chars of data, you've given the cracker 10 valid combinations to your cipher. This decreases the time it will take for them to identify your cipher by an order of magnitude. Giving them more transparent tokens will further reduce this time as well. Some protocols have a reduced version of this risk, but by the nature of what encoding is, having the encoded block, and decoded block both in your hands, you're always going to make it easier to break.

This is why many choose opaque tokens. Indeed you should always opt for opaque tokens if there is no need for any external entity to be able to parse your token. An example of this is a service framework in which you only pass the token to the service as a blind claim; you have no idea what it says, but you know it works and identifies you. It is only up to the service to confirm it's you via the secret key or cipher.

Opaque tokens also don't require signing, which I mentioned above, they also don't require divulging anything about chosen protocols.

For this reason, they are much more secure, not only mathematically and logically, but get rid of human implementation errors, which is, to be honest, 99% of the reason cracks are ever made in the first place.

Should I use opaque or transparent when implementing X?

OAuth electing opaque tokens when logical was done to just raise the bar for hacking it. However, if you want to implement something custom, Opaque v. transparent isn't the question you should be asking.

Doing it yourself is actually the more lazy approach; the hackable approach.

Of course this is up to you, but a better question to ask is "should I use custom or existing?". Statistically, nearly all hacks are made in the implementation, not the underlying tech; i.e. SQL injection still works today not because this isn't solved, but because people implement their services on their own, thinking "custom is more secure". This thinking is certainly false, because in 2024, SQL injection still is one of the leading causes of information theft; and in nearly all cases, the architect thought "I'll do this custom, so hackers won't know to attack library X".

Those are literally famous last words.

When choosing opaque v. transparent, it is much better to choose an existing tech. JWT, a transparent token, is 100% secure for all intents and purposes; the flaws are in implementation; i.e. the length of your secret, and how much entropy is contained in it.

If your JWT gets hacked, it's because of something unavoidable like MITM, or your secret wasn't secure; i.e. this is all implementation; it has nothing to do with the transparency.

Electing opaque over transparent simply because it's technically more secure is like locking your inside doors for the same reason; you make your life a lot harder and limit your abilities all in the name of security. And if one day you leave your window open to air out your bedroom... HACKED, and all your internal door locking was pointless suffering.

Don't do that.

Accepted methods > human behavior

When considering custom v. existing, think in the same terms of building a door and lock yourself, vs buying one; Sure, someone can look up hacks for your brand of lock, but hopefully you stayed up to date on updates. Alternatively, if you built it yourself, chances are, they can just "try human method x", because you are human, and be done, because humans generally make the same mistakes when they do things custom. This is much, much, much worse.

9
  • 1
    Do you have a citation for further reading about the 36.7% loss of combination space?
    – benbotto
    Commented Jul 31, 2019 at 17:38
  • 1
    This is a fact that is easy to prove but not talked about often. This is referred to a lot in Wolfram material and cited in a new kind of science quite a bit but in passing as it's fact, not with proof (amazon.com/New-Kind-Science-Stephen-Wolfram-ebook/dp/B01N1I83V8). You can in fact see for yourself this is true by making an array of size n, and then randomly filling a position with a value n times. The larger the value of n, the greater the unfilled positions will converge to exactly 1 / e. Although random is "random", it still follows this pattern perfectly. Commented Jul 31, 2019 at 20:38
  • 1
    This 1 / e phenomenon is at the base of what causes most "patterns" in random behavior. There is a great youtube video by VSauce (youtube.com/watch?v=fCn8zs912OE) that explains zipf's law (simple.wikipedia.org/wiki/Zipf%27s_law) and various trivia and real-world results of the qualities of randomness, but the video never dives into the math or explains the 1 / e convergence of randomness. Luckily for you, you can see the magic convergence on your own PC with maybe 5 lines of code, and see deeper into reality than you may want to ever go :) Commented Jul 31, 2019 at 20:45
  • 1
    Thank you for the links. While I agree that the "loss of combination space" converges on 1/e, I don't follow the 1/730 number (I think you meant 1/630, by the way). Given a random number in the range [0, 999], the chance of picking that number randomly is .001. That's pretty easy to show empirically.
    – benbotto
    Commented Jul 31, 2019 at 22:13
  • 1
    I'm saying that the 1/630 is inaccurate; maybe it's just poorly worded. If you have a random lock with a combo in the range of [0, 999] the chance of correctly guessing the combination in one attempt is 1/1000. If you guess randomly 1000 times, the chance of getting every guess wrong is (1 - 1/1000)^1000=1/e. The chance of getting at least one guess right is therefore 1 - (999/1000)^1000=1-1/e. Said a different way, if you have 1000 locks with random combos in the range [0, 999] and you guess 1 combination, you have a 1-1/e chance that a lock has that random combo.
    – benbotto
    Commented Jul 31, 2019 at 22:53
0

The reason for making the access token (and the refresh token) opaque to the client is that, as the client does not have to look at the content of the token, you are free to use whichever strategy and token format better suits your need:

  • You need to connect a Resource Server which accepts a stateless JWT? Your Authorization Server can issue a JWT as access token.
  • You need to connect a Resource Server which accepts a stateless SAML tokens? Your Authorization Server can issue a SAML as access token.
  • You need to connect a Resource Server which accepts a stateless CWT tokens? Your Authorization Server can issue a CWT as access token.
  • You need to connect a Resource Server which accepts a stateless PASETO tokens? Your Authorization Server can issue a PASETO as access token.
  • You need to connect a Resource Server which accepts Biscuits? Your Authorization Server can issue a Biscuit as access token.
  • You need to connect a Resource Server which accepts a Kerberos ticket? Your Authorization Server can issue a Kerberos ticket as access token.
  • You need to connect a Resource Server which expects an opaque "session-ID" token? Your authorization server can use an API of the Resource Server to request a new token and pass it to the client.
  • Your Resource Server is your Auhorization Server? Maybe you can just create a stateful token ID directly in database and pass that as an access token.
  • Your want to provide an access token for Resource Server which is controlled by a third party resource server? Your Authorization Server can request an access token from the third party Access Server using the Client Credentials Grant or the Token Exchange flow in order to get an access token from the third party Authorization Server. It does not need to know the format of this access token and the client does not need to know it either.
  • You need to connect a Resource Server which accepts an TOTP code as an access token (probably not a good idea but who am I to judge you?). Your Authorization Server can generate the TOTP code and send that as an access token

The access token is opaque to the client because the client does not need to know the content of this token. The content of the token is a contract between the (issuing) authorization server and the resource server.

  • You need to connect a Resource Server and you would like to use an encrypted (JWE) JWT? You can because the client does not have to look at the content.
  • You need to connect a Resource Server and you would like to use a MAC-ed (ex. HS256) JWT? You can because as the client does not need to look at the content of the access token, it does not need to have the shared secret.
  • You have chosen one of these options and now you have changed your mind. You only need to make changes in the Authorization Server and the Resource Server and your clients do not need to be notified because they don't care about what's in the access token.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .