I thought I'd write this all down before I forget it. Really hard to remember it after stepping away for a second.
I'm using the Microsoft Azure Mobile App platform and I want to support a number of different identity providers and platforms.
This is basically how it works:
- My program calls
MobileServiceClient(provided by MS and unique to each platform). As soon as I do this, control of the process is turned over to the MS libraries.
On the device, a web browser is launched.
The Mobile App service refers my request to the identity provider I chose (Google, Facebook, etc.)
The user logs into that service with their username and password specific to that service.
At this point, the identity provider returns an
access_tokenwhich is fed to my backend server (running on the app service platform). Again, this is all automatic.
The service then returns a
MobileServiceUserwhich contains a
UserId. This information is then attached to each web request made by the app, so it's always available. This is the first time my device code begins to execute again (steps 2 through 5 happen transparently and out of our control).
MobileServiceAuthenticationTokencontains the identity provider name and what's called a "stable id" or
sid. It has a few other bits that are important, but not in this discussion. The
sidis Microsoft's hashed value of the identity provider's real id for the user. The
sidshould be consistent no matter what the user changes on their identity provider account. We can count on that to never change.
On the client, the
UserIdis simply the
sidprefixed with the literal "sid:"
At this point, we are authenticated as far as the Azure Mobile App Service is concerned. But we don't have all the information we want.
Back under our control, the device then calls
LoginAsyncagain, only this time we are calling a Custom Authentication controller that we designed on our backend. This controller requires an authenticated user - which we now are - so random anonymous requests will fail (which is what we want to keep nosy beggars at bay).
This backend controller accesses the user information (coming back from the device in the form of the
MobileServiceAuthenticationToken). Now the backend has access to the
The backend controller then makes a call to:
`this.User.GetAppServiceIdentityAsync<GoogleCredentials>( this.Request )`
which allows it to retrieve all of the information from the identity provider that the user has agreed to allow us to access. This would include email, name, URL to their photo, etc. (Google is just an example.) This call decodes the information in an authentication header that gets added on behalf of their identity provider, e.g.
At this point, our controller creates a new
MobileServiceAuthenticationTokenthat contains lots more information (claims) about the user and so on.
Now our authentication process is complete. We just have to remember that every time we authenticate, re-authenticate or refresh our tokens, we have to call our custom authentication controller to add those claims needed by our app.
A couple of additional considerations here:
- Azure Mobile App service automatically provides a refresh token of 72 hours, even if the identity provider you select has a shorter expiration time.
- Since we are actually using a hybrid of the social identity provider and a custom identity provider, it can be quite confusing when it comes to refresh tokens, especially when they're expiring at different intervals. To deal with this, I set the re
- In the Settings of the App Service, we've also set the
trueso that we are only getting the permanent id of the user.