{"id":2709,"date":"2014-03-03T02:31:57","date_gmt":"2014-03-03T09:31:57","guid":{"rendered":"http:\/\/www.cloudidentity.com\/blog\/?p=2709"},"modified":"2014-03-07T11:46:50","modified_gmt":"2014-03-07T18:46:50","slug":"principles-of-token-validation","status":"publish","type":"post","link":"https:\/\/www.cloudidentity.com\/blog\/2014\/03\/03\/principles-of-token-validation\/","title":{"rendered":"Principles of Token Validation"},"content":{"rendered":"<p>Sometimes it\u2019s good to take a little break from just solving the immediate problem at hand by cutting &amp; pasting code found on the \u2018net, and take a step back to contemplate the bigger picture and the general principles that make that code tick. Also, the wife DVR\u2019d the Oscars ceremony and she\u2019s about to do some binge watching \u2013 it looks like I have some unstructured time to fill and I don\u2019t feel like opening my overflowing inbox this Sunday night.<\/p>\n<p>Hence, welcome to one back-to-basics installment!\u2013If you are\u00a0 a veteran reader of this blog you probably won\u2019t have much use for this, but with the advent of Windows Azure AD I feel there\u2019s a lot of you just ramping up \u2013 hopefully this post will help shedding light on one of the most fundamental tasks we perform while handling identity, and why the initialization parameters you have to feed in our software are the way they are.<br \/>\nNote: This is <strong>by no mean <\/strong>required reading, you can successfully use Windows Azure AD\/ADFS\/etc without knowing any of the below, but I found that it helps to grok some of the basics. Up to you!<\/p>\n<h2>Why Do We Validate Tokens?<\/h2>\n<p>Why do we bother validating tokens, indeed?<\/p>\n<p>When your Web application checks credentials directly, you verify that the username &amp; password being presented corresponds to the ones you kept in your database.<br \/>\nWhen you use claims-based identity, you outsource that job (and the job of keeping track of your users\u2019 attributes) to an external authority\/identity provider. Your responsibility shifts from verifying raw credentials to verifying that your caller did indeed go through your identity provider of choice and successfully authenticated. The identity provider represents successful authentication operations by issuing a token, hence your job now becomes validating that token. More about what that entails in just a moment.<\/p>\n<h2>Tokens and Protocols<\/h2>\n<p>Let\u2019s take a second to clarify an important point: tokens != protocols.<\/p>\n<p>Tokens are the form that issued credentials take to be transported, from authority to client and from client to resource.<br \/>\nProtocols detail the ceremony that apps use to send users to authenticate to an authority and\/or clients use for sending tokens to apps for gaining authenticated access. In other words, protocols are used for <em>moving <\/em>tokens.<\/p>\n<p>Some protocols have a preference for specific token formats: the SAML protocol only works with SAML tokens, OpenId Connect calls out JWT tokens specifically. Others can work with multiple tokens, provided that there\u2019s some kind of binding: WS-Federation usually works with SAML, but can work with JWTs and pretty much anything that gets wrapped in a binary token. OAuth2 doesn\u2019t mention any token format at all, given that it is mostly concerned with teaching to apps how to be clients (and clients should not care about the format of the tokens they handle, that\u2019s a matter between the authority and the resource).<\/p>\n<h2>Mechanics of Token Validation<\/h2>\n<p>Alrighty, what that that really mean to validate a token? It boils down to three things, really:<\/p>\n<ol>\n<li>Verify that it is well-formed<\/li>\n<li>Verify that it is coming from the intended authority<\/li>\n<li>Verify that it is meant for the current application<\/li>\n<\/ol>\n<p>Let\u2019s examine all those in order.<\/p>\n<h3>Well-formed<\/h3>\n<p>If we would all be <a href=\"http:\/\/www.economistsdoitwithmodels.com\/2010\/12\/18\/just-for-fun-econs-versus-humans-in-cartoon-form\/\" target=\"_blank\">Econs<\/a>, using language with perfect property at all times, we would probably call this phase \u201cvalidation\u201d. However we usually lump in that term all checks, including the ones described later, hence I am forced to find a circumlocution like \u201cverifying that a token id well-formed\u201d.<\/p>\n<p>When can you say that a token is well-formed? If the following holds:<\/p>\n<p>A. The token is correctly formatted according to its intended format<\/p>\n<p>B. The token has been received within its validity period, as validity is defined by the token\u2019s format<\/p>\n<p>C. The token has not been tampered with<\/p>\n<p>The meaning of A. is mostly that the token implements well the format specification it is meant to use. This is not as much as a security requirement, as it is a practical one: you\u2019ll have parsing logic meant to work with SAML1.0, SAML1.1, SAML2.0, JWT or whatever other format you support \u2013 and you don\u2019t want that logic to fail or to deal with ambiguous elements.<\/p>\n<p>About B: it\u2019s a good idea for tokens to have a limited validity, as that gives the opportunity to re-assess the validity of the authority\u2019s assertions about the user often \u2013 without reasonably short validity periods, there would be no way of performing revocation.<br \/>\nEvery token format defines some mechanism for expressing validity intervals: SAML has NotBefore and NotAfter clauses, JWT has ExpiresIn, and similar. Verifying those is just a matter of parsing the values and comparing those with the local time of the authority, modulo any clock skew if known.<\/p>\n<p>Verifying that a token has not been tampered with is more complicated to explain, but it\u2019s really not that complicated in itself.<br \/>\nAll the token formats I listed establish that a token must be <em>digitally signed <\/em>by the authority that issues it. A digital signature is an operation which combines the data you want to protect and another will known piece of data, called a <em>key<\/em>. That combination generates a third piece of data, called the signature. The signature is typically sent with the token, accompanied by information about how the signing operation took place (which key was used, what specific algorithm was used).<br \/>\nAn application receiving the token can perform the same operation, <em>provided that it has access to the proper key<\/em>: it can then compare the result with the signature it received \u2013 and if it comes out different, that means that something changed the token after issuance, invalidating it.<br \/>\nGiven their importance I must make one special mention for one special class of keys, X509 certificates. Without getting in the details, let\u2019s say that certificates rely on a technology (public key cypto) that used 2 different keys, one for signing (which remains private: only the authority has it) and once for verifying the signature (which is public, known by everyone and distributed via certificates). In order to verify a signature places by a private key, an app receiving the token needs to have access to the certificate containing the corresponding public key.<\/p>\n<p>Those three tasks establish if a token \u201clooks good\u201d regardless of the context in which it has been issued and sent \u2013 if it is well formed. The next checks enter in the merit of the specific issuer and app being accessed.<\/p>\n<h3>Coming from the Intended Authority<\/h3>\n<p>You outsource authentication to a given authority because you trust it \u2013 but as you do so, it becomes critical to be able to verify that authentication did take place with your authority of choice and no else.<\/p>\n<p>Tokens are designed to advertise their origin as clearly and unambiguously as possible. There are two main mechanisms used here, often used together.<\/p>\n<ul>\n<li>Signature verification. The key used to sign the issued token is uniquely associated to the issuing authority, hence a token signed with a key you know is associated to a certain authority gives you <em>mathematical certainty <\/em>(modulo stolen keys) that the token originated from that authority.<\/li>\n<li>Issuer value. Every authority is characterized by a unique identifier, typically assigned as part of the representation of that authority within the protocol though which the token has been requested and received. That is often a URI. Different token formats will typically carry that information in a specific place, like a particular claim type, that the validation logic will parse and compare with the expected value<\/li>\n<\/ul>\n<p>In classic claims-based identity, every authority has both its own key and its own identifier. In scenarios including identity as a service, however, that might not be the case. For example: in Windows Azure Active Directory the token issuing infrastructure is shared across multiple tenants, each representing a distinct business entity. The signature of issued tokens will be performed with the Windows Azure AD key, common to all, hence the main differentiation between tenant will be reflected by the different issuer identifier found in the token. To be more concrete: a Contoso employee accessing a Contoso line of business app secured by Windows Azure AD will send a token signed by the same key used by a Fabrikam employee accessing a Fabrikam line of business app \u2013 but in the first case the token will have an Issuer value corresponding to the Contoso\u2019s tenant ID, whereas the latter will have the Fabrikam tenant ID. If the Contoso employee would attempt to access the Fabrikam app by sending his token, he\u2019d fail because the validation logic in from of Fabrikam\u2019s app would find in the incoming token the Contoso\u2019s tenant ID instead of the expected Fabrikam\u2019s tenant ID.<\/p>\n<p>Both signature verification key and issuer ID value are often available as part of some advertising mechanism supported by the authority, such as metadata &amp; discovery documents. In practice, that means that you often don\u2019t need to specify both values \u2013 as long as your validation software know how to get to the metadata of your authority, it will have access to the key and issuer ID values.<\/p>\n<h3>Intended for the Current Application<\/h3>\n<p>Tokens usually contain a claim meant to indicate the target app they have been issued for. As for the issuer, the identifier used to indicate the app is typically the representation of the app within the protocol used for obtaining the token.<\/p>\n<p>That part of the token is often referred to as the <em>audience<\/em> of the token. Its purpose is the same as the corresponding field in a bank check: ensuring that only the intended beneficiary can take advantage of it. An application receiving a token should always verify that its audience corresponds to the app\u2019s audience: any discrepancy should be considered an attack.<\/p>\n<p>Imagine that Contoso is using two different applications, A and B, from two different SaaS providers. Say that one employee obtains a token for A and sends it over. A could take that token and use it to access B, pretending to be the employee: the authority is what B expects, the token has not been tampered with, it is still within its validity period\u2026 however, as soon as B verifies the audience, it will discover that the token was originally meant for A and not B itself \u2013 making the token invalid for accessing B and averting the token forwarding attack.<\/p>\n<p>This check has an interesting property: whereas issuer value and signing keys are often discoverable from the authority via some specific mechanism (metatada documents, for example), the audience value must always be specified on a per-app basis. In other words, typically the only source of truth for what audience value should be considered valid for a particular resource is the resource itself \u2013 the developer includes that value as part of the resource configuration.<\/p>\n<h3>Other Checks<\/h3>\n<p>The checks described are the indispensible verifications one must perform to assess the validity of an incoming token. That is just the beginning, of course: knowing that the caller is actually Bob from Contoso does not mean that he has access to the resource he is requesting \u2013 rather, this gives you the information you need for performing your subsequent authorization checks if necessary for the business logic your app implements.<br \/>\nSpecific resources and app types might consider some subsequent checks so important that they should really be part of the token validation proper \u2013 examples include the value in the scope claim for OAuth2 bearer flows. Many middlewares offer extensibility points you can use for injecting your own validation logic in the pipeline; but it is also common to add the extra checks directly in the app, in constructs typical of the stack used (e.g. filters &amp; attributes in MVC) or even in the first few lines of a method call.<br \/>\nIn the end all it matters is that the logic is executed before access is granted, which in practice usually means before the interesting app code gets to execute. As long as you are satisfied that this happens, you can choose to draw the logical line that groups the \u201ctoken validation logic\u201d wherever you deem it most appropriate.<\/p>\n<h2>An Example<\/h2>\n<p>A bit abstract, but hopefully not <em>too <\/em>abstract <img decoding=\"async\" class=\"wlEmoticon wlEmoticon-smile\" alt=\"Smile\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/03\/wlEmoticon-smile.png\" \/><br \/>\nHere, let\u2019s illustrate the concepts with one example.<\/p>\n<p>Say that my resource is a Web API, protected by Windows Azure AD and specifically by the Contoso7 tenant. Say that we want to use JWT.<\/p>\n<p>In order to be considered valid, an incoming JWTs will have to comply with the following:<\/p>\n<ul>\n<li>Be signed by the certificate <strong><span style=\"text-decoration: underline;\">MIIDPjCCAiqgAwIBAgIQs[..SNIP.]WLAIarZ<\/span><\/strong><\/li>\n<li>Have\u00a0 the value <strong><span style=\"text-decoration: underline;\">https:\/\/sts.windows.net\/6133e43d-b70d-40ca-87c0-f16993f99070\/<\/span><\/strong> in the iss (issuer) claim<\/li>\n<li>Have the value <a title=\"https:\/\/contoso7.onmicrosoft.com\/RichAPI\" href=\"https:\/\/contoso7.onmicrosoft.com\/RichAPI\"><strong><span style=\"text-decoration: underline;\">https:\/\/contoso7.onmicrosoft.com\/RichAPI<\/span><\/strong><\/a> in the aud (audience) claim<\/li>\n<\/ul>\n<p>\u2026and of course it will have to be still valid, not having been tampered with, and so on.<br \/>\nThe first 2 values came straight from the Contoso7 metadata document. The audience corresponds to the ID I have chosen to assign to my API when I provisioned it in my directory.<\/p>\n<p>Let\u2019s take a look at a token satisfying the above.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/03\/image.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px; border: 0px;\" title=\"image\" alt=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/03\/image_thumb.png\" width=\"609\" height=\"305\" border=\"0\" \/><\/a><\/p>\n<p>You can see highlighted in red the issuer value, in blue the audience, and in green the relevant claims used to assess whether the token is expired. See? It\u2019s really not magic!<\/p>\n<p>That is not the token in its entirety, but only the \u201cbody\u201d. JWTs typically have<\/p>\n<ul>\n<li>a header (not shown) detailing the algorithm used for signing an a reference to the key used<\/li>\n<li>a payload carrying the claims<\/li>\n<li>The signature value (not shown)<\/li>\n<\/ul>\n<p>Each part is base64\u2019ed, hence you would not see the above in Fiddler.<\/p>\n<p>Currently we offer various ways for you to inject validation logic in front of your application. You can choose to work directly with the <a href=\"https:\/\/www.cloudidentity.com\/blog\/2013\/06\/06\/the-json-web-token-handler-for-net-4-5-reaches-ga\/\" target=\"_blank\">JWT token handler<\/a> class, as shown <a href=\"http:\/\/msdn.microsoft.com\/library\/windowsazure\/dn151790.aspx\" target=\"_blank\">here<\/a>, and configure it to use the above values as validation parameters. You can choose to use the OWIN middleware, as shown <a href=\"http:\/\/msdn.microsoft.com\/en-us\/magazine\/dn463788.aspx\" target=\"_blank\">here<\/a>, which makes your job much easier but gives less control. You might even go completely manual and re-implement the JWT parsing &amp; validating logic yourself, though that would be more work than you\u2019d likely want to do given that ready components are available. The key point is, ultimately all those techniques will perform the checks described above.<\/p>\n<h2>Wrapup<\/h2>\n<p>Well, I got to the end of the post and to my chagrin Sandra Bullock did not get an Oscar\u2026 and Her got far less recognition it would have deserved IMO.<\/p>\n<p>On the other hand, now hopefully you have a deeper understanding of why we configure our validation middleware they way we do\u2026 hence I didn\u2019t completely waste the evening! <img decoding=\"async\" class=\"wlEmoticon wlEmoticon-winkingsmile\" alt=\"Winking smile\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/03\/wlEmoticon-winkingsmile.png\" \/><\/p>\n<p>The above contains a lot of simplifications, and does not really give any details about another crucial component which requires configuration, the protocol parts \u2013 however it provides me with a base I can use to explain more complicated scenarios (like <a href=\"https:\/\/www.cloudidentity.com\/blog\/2013\/02\/08\/multitenant-sts-and-token-validation-4\/\" target=\"_blank\">this one<\/a> \u2013 which is going to be so much easier with the new Owin components).<\/p>\n<p>Let me know if you think that those \u201cback to basics\u201d posts are useful \u2013 if they are, I\u2019ll make sure to keep them coming!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Sometimes it\u2019s good to take a little break from just solving the immediate problem at hand by cutting &amp; pasting code found on the \u2018net, and take a step back to contemplate the bigger picture and the general principles that make that code tick. Also, the wife DVR\u2019d the Oscars ceremony and she\u2019s&#8230;<\/p>\n","protected":false},"author":1,"featured_media":2707,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-2709","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts\/2709","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/comments?post=2709"}],"version-history":[{"count":2,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts\/2709\/revisions"}],"predecessor-version":[{"id":2721,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts\/2709\/revisions\/2721"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/media\/2707"}],"wp:attachment":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/media?parent=2709"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/categories?post=2709"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/tags?post=2709"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}