It is very easy to override the default login feature (accessible by /login/[provider] endpoints) of the Windows Azure Mobile Services and customize it according to the need of your app. In this blog post, I am going to discuss how to do that, in particular, we want to be able to do the following:
- Add custom claims to the identity (the ability to provide authorization after authentication). In this example, we will add custom claims to the facebook identity.
- Add a new oAuth identity provider (in addition to the ones supported by the Windows Azure Mobile Services). In this example, we will add Foursquare as the new identity provider.
- Add a simple classical identity provider (login by username and password).
- Add support for multiple apps using the same backend. It is necessary, if you have a public API exposed and other people are making apps using your backend.
In this post, I am going to use the oAuth flow described in my previous blog post, which is:
- the app verifies the identity of the user elsewhere, i.e., native facebook app, and acquire an access_token,
- this access_token is used to login to Windows Azure Mobile Services.
But, the examples are easily extendable to any standard oAuth flow.
Adding Custom Claims
Each endpoint in Windows Azure Mobile Services has access to the user object. A call to its asynchronous user.getIdentities(…) function will produce similar result like the following:
By default, Windows Azure Mobile Services gives you 2 claims for facebook, namely userId and accessToken.
In this example, we are going to add 2 more claims role and device, indicating the role of the user (either admin or user) and the device from which the user is trying to access the backend.
With this code, the facebook function, described above, can be called by HTTP POST /api/login/facebook (as opposed to the default HTTP POST /login/facebook). We will add another property called device in addition to the default access_token to the request body. However, when we override the client SDK, we will provide the value depending on the SDK being used.
Here is how we are going to implement the new login endpoint:
- Call facebook and get the facebook app id and user id from the access token, and check the app id with the registered facebook app id in the Windows Azure Mobile Services. If they do not match, generate a 401 unauthorized.
- If, however, they match, generate and send back a JSON Web Token (JWT) so that it can be used for subsequent API calls (similar to what the default login will give you).
Thanks to many awesome developers, there are code available in the Web to generate a JWT that the Windows Azure Mobile Services will understand. Let’s pick one of those and modify it to include claims (in /service/shared directory):
As you can see that the JWT has a claim called urn:microsoft:credentials that is used for custom claims. After that, let’s implement the previously described facebook function. In this function, we are going to use a library called async to call the facebook API parallel to get the facebook app id and user id from access_token. Once we have the info, we are going to check if the facebook app id is actually the one registered with our Windows Azure Mobile Services. If everything checks well, then we will create a JWT and send it back as a response in the standard response format of the default login. The code looks like the following:
To test if the claims are added to the identity or not, let’s write a simple API endpoint (called test with the GET permission to Only Authenticated Users). This endpoint will response the contents of the user object and the identities object.
And it should produce a response like the following:
As you can see that your custom claims are added to the identities.
(PS : You may need to install async node module to run the example code.)
Adding A New OAuth Identity Provider
With the method shown in the previous section, any identity provider can be added as long as the identity provider has endpoints to request a user_id and a app_id from the access_token. Although, any identity provider will have such endpoints for the user_id, but not all of them will have one for the app_id. In this example, we will add Foursquare as an identity provider because it has no public endpoint that returns an app_id from the access_token, so that we can generalize. The following method can also be added to the previous example to provide an additional layer of security.
The idea is simple. Since both server and client knows the client secret (you will get a client_secret once you register an app with the identity provider), before sending the access_token we are going to encrypt it using the client_secret . The server will always expect an encrypted access_token and will decrypt it before using it. We implemented the idea for foursquare and the code is following:
I have also included an endpoint for encrypting the access_token for testing purpose, but ideally you would do it in the client:
Adding A Simple Classical Identity Provider
The same process can easily be extended to provide classical identity (identity by username and password). Just check the username and password in the database and for a successful match generate a JWT. This process is described more comprehensively in here, including registration.
Adding Support For Multiple Apps (Expose Your Own API)
If you want to have your API publicly available for everyone (or a selected group) to use your backend, you need the support of multiple apps in your login. You can extend the same idea easily to have this feature. This is the oAuth flow we are going to implement today:
- The identity is still provided by an external server, i.e., facebook, and the 3rd party has an app registered with facebook, through which it gets the access_token from facebook.
- The 3rd party register the facebook app with your backend (save the app_id and app_secret).
- Similar to previous sections, the 3rd party send the facebook access_token for login and with that your backend is going to get an app_id and user_id from facebook.
- Then you check the app_id is registered with your backend or not, and depending on that either generate a JWT for login or a 401 unauthorized. (You can add another layer of security by encrypting the access_token with the app_secret. But, in that case, you have to pass the app_id when calling the login endpoint, so that the backend knows which app_secret to use for decryption.)
You may also want to add the app_id to your custom claims. The login script is following:
To recap, in this post, we learned how to add custom claims to Windows Azure Mobile Services user’s identities, and we extend the idea to implement, an authentication by an additional identity provider, the classical username/password based identity, and the support of multiple apps for a public API. The full code can be cloned from github.
(PS : As the post was getting bigger, I skipped few trivial steps. Feel free to ask questions if anything is unclear.)
(PPS : I will soon add some client SDK codes in the github repository to access these modifications. Basically, in the client SDK you need to change the login endpoint url and may need to add extra variables like device, app_id in the request body for calling the new login endpoints. Checkout this and this links for client codes for similar modifications.)
Tagged: api, authentication, authorization, azure, claim-based-auth, claims, code, expressjs, facebook, identities, identity-server, json, jwt, nodejs, oauth, public-api, restfull, security, web-api, windows, Windows Azure, Windows Azure Mobile Services, zumo