- The identity token needs to clearly identify the identity provider that issued the token, some value that identifies the user, and I believe the party the token was initially issued to (the Consumer in OAuth speak).
- The value that identifies the user must support opaque values to prevent this token becoming a global correlation handle (if desired by the involved parties). Of course, the user identifier could be the user’s OpenID.
- The identity token must be signed in some way and protected from replay attacks.
If we go back to the use case from yesterday’s post, using a Open Identity Token would enable the flow to work like this.
- Alice logs into hikingtrails.example.com with her OpenID
- When hikingtrails.example.com invokes the OpenID flow, it asks Alice’s OpenID provider to return an Open Identity Token
- hikingtrails.example.com receives the OpenID assertion and Open Identity Token
- Alice uploads a GPS track and some photos of a new trail she hiked over the Labor Day weekend.
- At the conclusion of her upload, hikingtrails.example.com asks Alice if it should notify her friends about her activity.
- Alice thinks that’s a great idea and agrees.
- So hikingtrails.example.com queries portablecontacts.example.com, using pre-established OAuth credentials, and retrieves Alice’s list of contacts with a tag of “hiking buddy”.
- Now for each of these friends, hikingtrails.example.com has to discover the “notification” service and send it the new activity message.
- One of Alice’s friends, Bob, only exposes the endpoint and metadata of his “notification” service to a restricted list of people
- hikingtrails.example.com queries Bob’s discovery service presenting the Alice’s Open Identity Token
- Bob’s discovery service validates Alice’s Open Identity Token and then returns the non-public service endpoint and metadata
In this flow, Alice does not have to interact via some user interface with Bob’s discovery service. Of course the identity represented in the Open Identity Token needs to be resolvable in to an identifier that Bob’s discovery service can use.
Finally, here are some initial technical implementation ideas...
I was thinking that the identity provider could construct the token and “sign” it with a HMAC_SHA? hash. The signature-base-string would be IdentityProvider:Consumer:UserIdentifier and the identity provider would construct a random value to use as the secret in the HMAC_SHA? hash. This value would need to be remembered based on the IdentityProvider:Consumer pair. What would be returned (probably base64’d) as the Open Identity Token would be “IdentityProvider:Consumer:UserIdentifier,hash”.
When the Consumer that receives the token wants to use it in an API call, it constructs a unique Open Identity Token (to protect against replay of the token) for the API call. This token uses the hash received from the Identity Provider as the secret in a new HMAC_SHA? hash. The signature base string for this hash would be “IdentityProvider:Consumer:UserIdentifier:Nonce”. What would go on the wire as the token would be base64(“IdentityProvider:Consumer:UserIdentifier:Nonce,hash”).
When a Service Provider receives the Open Identity Token, it can verify the token by sending it to the IdentityProvider specified in the token. For OpenID this would require a new extension and “API” method. Note that in the verification step, if the user identifier was opaque in the token it can be resolved into something the Service Provider can use. This allows for generating tokens that are unique to a specific context (no global correlation) while still providing the Service Provider with the data they need.
In this model, only the identity provider can validate the Open Identity Token because it is the only entity (besides the Consumer) that has the secret used by the Consumer in signing the token. All the identity provider needs to do is look up the hash it gave to that Consumer and then use it in a HMAC_SHA? hash of the “IdentityProvider:Consumer:UserIdentifier:Nonce” string and finally compare hashes.
I realize that going back to the Identity Provider to verify the token does have some drawbacks: privacy (leaking where this identity token is used), complexity and performance (an extra lookup/validation is required). But since I’m not a security expert, I’m hoping that others will be able to modify these ideas to allow for direct Service Provider validation. It’s just critical to me that the mechanism used to generate the Open Identity Token allow for both un-defined “circles of trust” (e.g. OpenID) as well as more closed or dynamic “circles of trust” (e.g. SAML). This might be as simple as leveraging the OAuth signature method and then support RSA signing.