Getting Acquainted with AuthenticationResult

Now that the cat’s out of the bag, we can finally play with it Smile time & energy permitting, in the next days (weeks?) I’ll be covering some aspects of using ADAL .NET to help you to get the most from AD in your applications.

In the announcement post I introduced AcquireToken, the key primitive exposed by ADAL for obtaining access tokens to be used with the protected resources you want to access. Today I’ll go a bit deeper on how to use the results of that operation.

Let’s consider a common case, in which you have a desktop app accessing a Web API protected by Windows Azure AD, associated to the domain CloudIdentity.net (could have been just as well whatever.onmicrosoft.com, I just like to use the other one because it’s shorter). The client is regularly registered in the tenant, hence we have its ID; same for the Web API, for which we have the resource ID.

Here there’s the code you’d write for acquiring the token:

AuthenticationContext ac = 
    new AuthenticationContext("https://login.windows.net/cloudidentity.net");
AuthenticationResult ar = 
    ac.AcquireToken("https://cloudidentity.net/WindowsAzureADWebAPITest",
                    "a4836f83-0f69-48ed-aa2b-88d0aed69652",
                    new Uri("https://cloudidentity.net/myWebAPItestclient"));

The first couple of lines initialize the instance of AuthenticationContext which we can use for interacting with the associated AD instance.

The next line asks to the Windows Azure AD tenant for a token scoped for the resource https://cloudidentity.net/WindowsAzureADWebAPITest, advertises that the request is coming from the client a4836f83-0f69-48ed-aa2b-88d0aed69652, and indicates https://cloudidentity.net/myWebAPItestclient as reply url (technicalities of the OAuth2 code grant; let’s just say that ehre you have to pass the same value that is stored in the client registration in Windows Azure AD).

If that’s the first time that you call AcquireToken with those parameters, ADAL will take care of popping out a dialog containing a browser, which will in turn present the user with whatever authentication experience Windows Azure AD decides to use in this case.

If the user successfully authenticates, AcquireToken returns to you a nice AuthenticationResult instance. There you will find the access token (in the AccessToken property) you need to call the web API, and let me be clear: if performing the call as is is all you want to do, you don’t need to know anything else.
That said, you’ll discover that there’s way more stuff in AuthenticationResult: if you know what it’s for, you can use the extra info for interesting tweaks. Let’s take a look!

image

Here there’s a view courtesy of the VS2013 debugger. Let me give you a brief description for all of those properties:

AccessToken – Those are the bits of the access token themselves. In most cases it will be a JWT, but you’re not supposed to know that! Smile Or, to clarify: the token is meant for the resource, and for the client the token itself is supposed to be an opaque blob to be used but not inspected. Should you peek in it and take a dependency on any of its aspects in the client code, you’d end up with extremely brittle software: the characteristics of the token are the result of a negotiation between the resource and its issuer, which can change things at any time without having to inform the client. You’ve been warned Winking smile

AccessTokenType – givens indications on the intended usage. More details are beyond the scope of this post, but not not leaving completely dry: in this case “bearer” indicates that this token should be simply attached to requests.

ExpiresOn – this is the expiration of the access token. If you repeat the AccessToken call with the exact same parameters before the expiration occurs, you are going to get the exact same token as cached by ADAL. If you repeat the call after the expiration, if there is an associated refresh token (see below) and it is not expired itself ADAL is going to automatically (and silently, no UI) use it to get a new access token and return it to you. Bottom line; in general always use AcquireToken instead of storing the access token in your own code!
Note: ADAL does not offer any clock skew functionality. That expiration value is final. If there is clock skew between the issuer and the resource, you might need to do something to get things renewed sooner. More detials in a future post.

IsMultipleResourceRefreshToken – this flag indicates whether the refresh token (if present in the AuthenticationResult, it won’t always be the case) is one of those magic refresh tokens that can be used for silently obtaining an access token even for resources that are different from the one for which the refresh token/access token couple was obtained in the first place. Of all the flavors of AD ADAL can talk to, this can only happen with Windows Azure AD. This is another candidate for its own blog post.

RefreshToken – This contains the bits of the refresh token. It won’t always be present: ACS never issues it, ADFS will do so only in special cases and even Windows Azure AD will do so only when the underlying OAuth flow is right (e.g. code grant).
Important: in the general case, you don’t need to use this field at all. ADAL caches the refresh token and uses it transparently, taking full advantage of all of its capabilities, every single time you call AcquireToken. We return the refresh token because there are some cases where you might want to have full control about some other aspects, but those are only advanced scenarios that should be fairly rare.

TenantId – this is the identifier of the tenant that was used for authenticating the user. You might not have known that information in advance, given that you can create a generic AuthenticationContext tied to the Common endpoint: in that case, the true tenant is established only when the end user enters his/her credentials which by necessity must belong to a specific tenant. This value makes a lot of sense for Windows Azure AD, but less for other AD flavors.

UserInfo – This is a bit of a “contamination” from OpenId Connect. I won’t go in any details, I’ll just say that when ADAL triggers a user authentication with Windows Azure AD, as in the case described here, besides the expected bits (access token, refresh token…) you also get back an Id_token describing the user. Some info might be useful to you as generic properties (FirstName, LastName). Other properties can instead play an important role in the mechanics of how you handle authentication and manage state. More details below.

One property of UserInfo, UserId, deserves to be explored in more details. In the Windows Azure AD case, UserId will contain the UPN of the user who authenticated to obtain the tokens back. There are variations I don’t want to talk about yet, but they’ll work like in the UPN case hence for our explanation that makes no difference. Now, although this is a less-than-perfect identifier (it can be reassigned) it is still a pretty good moniker for tying the obtained tokens to the user they are associated to. As such, it is used as one of the component of the cache key under which ADAL stores the current result. And as such, this can play a role to gain more control in subsequent calls to AcquireToken. Let’s make an example.

Suppose that your client application is designed to allow the user to use multiple accounts at once. A classic example would be the People app in Windows 8, where you can connect multiple accounts from different providers. Say that you want to make sure that you will perform a certain API call using a specific user, for example the same one that was used in the earlier call. You have a reference to that user, the string you found in UserInfo.UserId from the AuthenticationResult of the first call: all you need to do is specifying it as a parameter in AcquireToken.

AuthenticationResult ar =
     ac.AcquireToken("https://cloudidentity.net/AnotherResource", 
                                 "a4836f83-0f69-48ed-aa2b-88d0aed69652", 
                                 new Uri("https://cloudidentity.net/whatevs"),
                                 "vibro@cloudidentity.net");

Adding the UserId as parameter will have the following effect:

  • ADAL will search the cache for an entry that not only satisfies the resource and clientid constraint, but also  that it was obtained with the same userid
  • If the cache does not contain a suitable entry, ADAL will pop out the browser dialog with the user textbox pre-populated with the indicated userid

That’s pretty neat, as it gives you the necessary control for handling tokens in multi-users scenarios that can notoriously get very complicated. I’ll get back to this in the post where I’ll discuss the cache model. So much to write!

Now, technically there’s nothing preventing your application from gathering the UPN of the intended user and feeding it directly in AcquireToken: that can work, but there are limitations:

  • the username textbox will be pre-populated with the right values, but the end user can always delete its content and type another username. ADAL will always use what’s returned in the UserInfo.UserId as cache key, hence you can catch this situation with a simple check on the AuthenticationResult
  • different flavors of AD work differently

Neither ADFS or ACS will return id_tokens, hence the UserInfo properties will not carry values when you work with those authority types. Well, mostly. We did do some extra steps for giving you at least some info.

For results from those authorities ADAL itself generates an identifier and stores it in the UserId field. That won’t tell you an absolute identifier for the user, but it does offer you a mechanism for enforcing that subsequent calls to AcquireToken can search the cache for the same user that came into play here. I know, it’s complicated: let me make you an example. Say that you call AcquireToken against ADFS, and you get back the usual tokens and a UserId value of 1234567. Now, from that userid value you cannot know that the user is in fact mario@contoso.com; but by using that userid value later on you can enforce that the token you are getting from the cache is associated to the same user that authenticated earlier, even if you are not certain about the actual identity of the user. It’s a bit like when you leave your jacket a the coat check. They give you a ticket with a number, and as long as you show up later with the same number you get your jacket back: at no point in that transaction your name need to come up.
If that’s not crystal clear don’t worry too much, I’ll be getting back on this multiple times in the next posts.

That’s pretty much it! However, before closing I just want to make sure I stress that for the basic case you don’t need to know anything, and I mean anything at all, about the structure of AuthenticationResult. There is a little utility method which crafts a header for your web API flow, and that’s all you need to know to be able to call your OAuth-protected API. Just make sure you always call AcquireToken so that ADAL has the chance of handling token lifecycle & refreshing for you, and that’s all you need! Code below:

 string authHeader = ar.CreateAuthorizationHeader();
 HttpClient client = new HttpClient();
 HttpRequestMessage request = 
     new HttpRequestMessage(HttpMethod.Get, "https://localhost:44353/api/Values");
 request.Headers.TryAddWithoutValidation("Authorization", authHeader);
 HttpResponseMessage response = await client.SendAsync(request);
 string responseString = await response.Content.ReadAsStringAsync();
 MessageBox.Show(responseString);

 

All so standard that I’ll deem it self-explanatory and call it a post.

Next, I’ll be talking about cache. Stay tuned! Winking smile

Leave a Reply

Your email address will not be published. Required fields are marked *