Using AzureAD as authentication for an ASP.NET application is pretty awesome. I recently had the chance to play with this combination, but found myself figuring out a lot of stuff real soon. This post is about how to set up a relationship between a 'local' user and the AzureAD authenticated identity.
I assume you already got your application working with your own AzureAD. The Startup.Auth.cs should look similar (if not exactly like) the default ASP.NET 4.5.2 template from VS2015. This of course with Authentication set up with Work and School Account -> Cloud - Single Organization.
As for the rest you're going to need something that represents a user and a way to persist it to the 'local' database. By 'local' I mean the dedicated application database, because persisting everything in the AzureAD Graph API is certainly not an option for most applications. I use EF and a User POCO:
Hooking into OpenIdConnect
To be able to connect with AzureAD an OpenIdConnectAuthenticationMiddleware component is injected into the OWIN runtime. I don't want to dive into the specifics, but for this post it's important to know processing OpenIdConnect messages can trigger various notifications. If you want to read more on Azure AD, OAuth and OpenId Connect, here's a good read on that subject.
Basically we're going to hook into one of these notifications: the AuthorizationCodeReceived event. This event is invoked after validating the security token when an authorization code is present in the protocol message. The AuthorizationCodeReceivedNotification passed along the Func contains information about the event, like the JwtSecurityToken and the AuthenticationTicket. This AuthenticationTicket contains the Identity, which we're going to use.
Registering the user
Now we're at a point we need to register the user. For matching the AzureAD user with the application user, you can use the ObjectIdentifier claim. This claim contains a unique identifier of an object in AzureAD. Also it's important to note that the value is immutable and will not be reassigned or reused. This claim, used by Microsoft clearly, doesn't have a .NET constant yet for its full name. This happens allot with claims, since anybody can think of new ones. I prefer organizing them as constants like this:
I myself needed to set some extra application claims, so I used a GetOrRegisterUser(..) method for fetching the user. You can of course skip this and use a RegisterIfNotExist(..) variant.
By using the ASP.NET's build-in dependency resolver I resolve and use one of my application's services, the IAccountService. The logic of registering or fetching users still resides in the application itself. The GetUserByIdentityClaimObjectId() and RegisterUser() methods are fairly straightforward and do exactly what you would expect ;-)
Bonus: setting claims
By setting extra claims specific to the application, I don't have to query that information every subsequent request. I prefer working with Id's rather than the Guid provided by AzureAD. Besides, not all users are required to be AzureAD users this way.