These are a product of the OpenID Connect work, and I think they’re going be super-useful; in fact I keep getting ideas for nifty things you could do with them. So here’s a walk-through on what they are and how they work; maybe you’ll have some ideas too.

What They Are · ID Tokens are little chunks of text which claim that some particular person wants to tell some particular party out there that they’re signed in and authenticated by the Identity Provider that issued the token.

There are some more goodies in there, but that’s the big deal. ID Tokens are easy to understand and cheap for programmers to process. And if you follow the rules for handling them, they offer first-rate security.

It seems painfully obvious to me that these things are a key weapon in our fight against passwords on the Internet. Now let’s drill down.

History · A hundred or so years ago Dave Winer said the Web needed a “You Know Me” button. I’ve liked that idea ever since. ID Tokens are the machinery behind that; and when you’re sending them from a mobile device you don’t even need the button, because of course the phone knows who you are and can tell anyone you want it to.

Standards Wonkery · ID Tokens are defined in OpenID Connect Messages 1.0, currently in Draft 17 and (in my opinion) very close to completion. They work well enough that Google is deploying them in production.

If you look there, you’ll discover that they weren’t invented from whole cloth, they’re actually JSON Web Tokens (JWT for short, pronounced “jot”, another OpenID spec) which are based on some IETF work, chiefly JSON Web Signatures.

Where Do They Come From? · OpenID Connect (OIDC for short) is a spec for doing Authentication (login or sign-in) using OAuth 2.0. It has nice clean instructions for redirecting a browser back and forth between an “RP” (relying party) and “OP” (OpenID Provider) to authenticate a user, then communicate that authentication (using an ID Token) to the RP.

OIDC is fine as far as it goes, but kind of browser-centric; we all spend more and more of our time in mobile apps, and they don’t do that redirect stuff. And furthermore, when you take your phone out of your pocket and type your PIN or whatever, you’re pretty effectively authenticated to the phone, no Web roundtrips needed.

And I’m an Internet-protocols guy not a user-interface guy. So I think this tool for communicating authentication status is way more interesting than the process of authentication, which I expect to change all the time as we get smarter and learn new lessons.

On an Android device, you can get an ID Token by calling GoogleAuthUtil.getToken() with a particular value for the “scope” argument; you can read the details in Verifying Back-End Calls from Android Apps.

Inside an ID Token · Want to look at one? Drop by the Google OAuth 2.0 Playground, ignore all the APIs, type “openid email” into the “input your own scopes” window, press the “Authorize APIs” button, tell Google it’s OK to make the token, and then press the “Exchange authorization code for tokens” button on the next screen.

I just did that, and here’s the ID Token I got (broken up to fit into the relatively narrow columns here at ongoing).

eyJhbGciOiJSUzI1NiIsImtpZCI6IjQ4OWRmMzE3YzIyYzY3NTZkOTUyMTVk
YjQ1NTA5MjY0N2RmNWIxNmEifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY
29tIiwiZW1haWwiOiJ0aW1icmF5QGdtYWlsLmNvbSIsImVtYWlsX3Zlcmlma
WVkIjoidHJ1ZSIsInN1YiI6IjEwNzYwNjcwMzU1ODE2MTUwNzk0NiIsImF1Z
CI6IjQwNzQwODcxODE5Mi5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsI
mF0X2hhc2giOiJyTC1jVml3OTJtYW5EUU1MdU1tTEt3IiwiYXpwIjoiNDA3N
DA4NzE4MTkyLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiaWF0IjoxM
zY1MDk5MTUxLCJleHAiOjEzNjUxMDMwNTF9.GeqJOTJSMaQjo33wxM-3f5k5
FIEADqxd3K4zS0pWgWjtqwDldbpGgmxwTytgvtXKjFu7dtZx6TUXPnDhLBti
MjtkTyPGZbm65RwG0arSLqH-iDelceDR5HDABhOBqXjsi19rdnC3TAWf5Dpe
QYZt9uSSgPseGW2wh6OO5izat48

That’s not supposed to be human-readable, but do take a moment to notice that the token is separated into three chunks by two dots, which I’ve colored red to make them a little easier to see.

Want a look inside that token? Google has a service for that (you have to paste in the whole token, but I’m only showing the first few characters to keep things readable):

>> curl https://www.googleapis.com/oauth2/v1/tokeninfo?id_token=eyJhb...
{
 "issuer": "accounts.google.com",
 "issued_to": "407408718192.apps.googleusercontent.com",
 "audience": "407408718192.apps.googleusercontent.com",
 "user_id": "10315112535234507946",
 "expires_in": 3089,
 "issued_at": 1365099151,
 "email": "example@gmail.com",
 "email_verified": true
}

You can try this yourself, but not with that token, which will have expired by the time you’re reading this. So go over to the playground and make your own ID Token and give it a whirl.

Let’s Unpack It Ourselves · It turns out that if you’re a programmer and you get an ID Token, you don’t have to have a conversation with Google to unpack it. Here’s how.

Earlier, I pointed out that these things have three .-separated parts. It turns out that the first two are just base64-encoded JSON. Let’s decode them (I use the command-line base64 -D on my Mac, but there are a lot of ways to do this).

First segment (with line breaks for readability):

{
 "alg":"RS256",
 "kid":"489df317c22c6756d95215db455092647df5b16a"
}

Second (somewhat anonymized):

{
 "iss":"accounts.google.com",
 "email":"example@gmail.com",
 "email_verified":"true",
 "sub":"10315112535234507946",
 "aud":"407408718192.apps.googleusercontent.com",
 "at_hash":"rL-cViw92manDQMLuMmLKw",
 "azp":"407408718192.apps.googleusercontent.com",
 "iat":1365099151,
 "exp":1365103051
}

(Alert observers will have noticed that the fields in the second don’t have the same names as reported by the “tokeninfo” endpoint above. I think that’s wrong and have filed a bug; will report back.)

Be Careful · First of all, note that the token isn’t encrypted; which means you have to be careful that the wrong people don’t see it. In practical purposes, this means whenever you send it anywhere, you have to use TLS, i.e HTTPS not HTTP. Which is just good practice anyhow.

That said, let’s look at the fields inside the ID TokBZZZZZZZZZZT! WRONG!

Oops. It turns out you must never use the info in an ID Token unless you’ve validated it, or Evil Internet People Will Come To Your House And Strangle Your Puppy. OK, I’m kidding about the puppy, but seriously, there are a lot of bad things that can happen if you don’t do this right; which, fortunately, is pretty easy.

(By the way, the tokeninfo endpoint I used above with “curl” takes care of the base64 parsing, the validation, and the unpacking all at once).

The third piece of the token (after the second dot) is the cryptographic signature. The first part (before the first, unpacked above) tells you which key and crypto algorithm was used to make it.

Fortunately, you don’t need to understand that crypto stuff. Most languages have signature verifiers and the ones I’ve been working with recently come with JWT libraries, you can just pass in the raw token and get back a nicely-validated and unpacked hash or dictionary or whatever...

... well, sort of. You also need to pass in the key, which can get a little complicated. It turns out that if you know the ID Token was signed by Google, you can tell the library to fetch our keys from www.googleapis.com/oauth2/v1/certs (go ahead, click and have a look).

This can be automated. If you know the email address you’re authenticating, you can use WebFinger to figure out which IDP to use, and then use OpenID Connect Discovery to figure out the URI pointing to the IDP’s keys, then go get them. Or you could start from the “issuer” field in the token, if you’ve whitelisted it.

All of which, of course, would be a lot of Web round-trips, but in practice you’d almost never have to; these things are all very stable and cacheable.

In most cases you’re not going to have to even fetch the keys. We at Google only rotate ours on the order of once per day. So the library code I’ve seen caches them, and if a token fails to validate, they go re-fetch the keys and try again, on the assumption that the token was issued since they rolled over. So in almost every case, validating an ID Token is a couple of calls into a crypto library.

More Carefulness · Once you’ve validated and believe that the ID Token was really signed by an issuer you’re prepared to trust, you still have to do a little more work. Most importantly, you need to look at the value of the “aud” (for audience) field. This represents who the issuer and user thought this token was intended for. It’d better be you. You’re identified by “Client ID”, a string you get from the IDP (issuer, “iss” In the ID Token) when you register with them. If the value of “aud” isn’t yours, something has gone gravely astray and you really shouldn’t use the token.

The Payload · Having practiced good hygiene, we can now talk about what was inside that ID Token. It turns out that it’s flexible enough to allow for all sorts of different fields, but here are the standard ones that deliver the real value.

iss is the Issuer. Many apps will want to whitelist the issuers they’ll accept ID Tokens from, but I can imagine some apps where you’d be less sensitive.

email is self-explanatory, the person the ID Token claims to have authenticated.

email_verified means that the token issuer really took pains to check that this is that person.

sub (for subject) is interesting. It’s the real unique identifier for the person whose “email” was provided. The combination of “issuer” and “sub” is globally unique. For example, you can change the email address on a Google account, but the “sub” won’t change. So if you’re building a user database, the right key for “example@gmail.com” would be the combination of ”accounts.google.com” and 10315112535234507946.

aud is the app which is expected to receive this ID Token. For example, on an Android device, when the app asks for an ID Token, the user would be prompted if it were OK to share her identity with the app (identified by name and graphic) which had registered with Google and been given this Client ID.

at_hash is used in the case where you get both an ID Token and an Access Token, to verify the linkage. It’s an interesting use-case, but not what I’m discussing today.

azp identifies the party authorized to send the ID Token, in the same way that “aud” identifies the one expected to receive it. In the case where the ID Token was generated on Android, it’ll identify the Android app that requested it.

iat and exp are timestamps for when the token was issued and when it expires. If we apply that advanced algorithm known as “subtraction”, we can deduce that this particular token was good for 65 minutes.

There You Have It · Lightweight, suitable for including in a URL or sending in an HTTP header, easily verified, easily unpacked, and (assuming you validate properly) just as trustworthy as you think its issuer is.

A very damn useful little piece of technology.



Contributions

Comment feed for ongoing:Comments feed

From: Bryant Cutler (Apr 04 2013, at 18:10)

Hmmm, could have sworn that it's actually the issuer/aud/sub combo that's globally unique so that apps still only see pairwise identifiers for users...

[link]

From: Dick Hardt (Apr 04 2013, at 18:35)

I hope we get rid of the term "ID". What the heck is that? Token is also an overused word. You've done a good job explaining this aspect of OpenID Connect -> but how does it fit into everything else, or does it?

[link]

From: Dirkjan Ochtman (Apr 05 2013, at 01:03)

I don't know, it seems like most of the stuff you are excited about is actually from JWT, and doesn't apply just in an OpenID Connect/ID Token context.

[link]

From: Anonymous Cowherd (Apr 08 2013, at 17:53)

> If the value of “aud” isn’t yours,

> something has gone gravely astray

> and you really shouldn’t use the token.

I think you mean

> If the value of “aud” isn’t yours,

> something has gone gravely astray

> and you can go to the intended

> audience and pretend to be the named

> user, at least until the token expires.

For example, if the user accidentally sends you their ID token intended for the Bank of Zork, then you have all you need to clean out their checking account.

(And of course the *issuer* can clean out *everyone's* checking accounts. We just have to trust them not to do that.)

In practice, I expect that services won't blindly accept tokens as proof of identity; they'll have some sort of actual authentication going on ("hey stranger, sign this nonce with your private key", that sort of thing). Tokens seem like a non-solution in search of a problem...

[link]

From: Justin Richer (Apr 10 2013, at 04:25)

I've been trying to push for standardization of the token introspection endpoint, what google calls "tokeninfo", and one of the things I've been asked to change is to align the response values with the field names in JWT. I think it would be fantastic if Google could adopt this and help push it forward so that developers can depend on a standard way of unpacking a token. Note that this would work with any token, whether it's structured like a JWT or just a random blob of characters, because the server can store and return the metadata for the token.

Current draft is here: http://tools.ietf.org/html/draft-richer-oauth-introspection

Issue tracker for it is here: https://github.com/jricher/oauth-spec/issues

[link]

From: James Manger (Apr 16 2013, at 07:09)

I hope that "somewhat anonymized" email address was only to defeat web page crawlers, as the actual address is still in the base64 blob. ;-)

[link]

author · Dad
colophon · rights
picture of the day
April 04, 2013
· Technology (90 fragments)
· · Identity (44 more)

By .

The opinions expressed here
are my own, and no other party
necessarily agrees with them.

A full disclosure of my
professional interests is
on the author page.

I’m on Mastodon!