This article will demonstrate a technique using the Passport.js library to implement social logins using a variety of providers, and leading from that to token-based authentication for the later API calls.
All of the source code for this article is available for download from our GitHub repository.
Why Use Social Sign-in for Your SPA?
When implementing a login mechanism on your web application, there are a number of concerns to take into account.
- How should your UI handle authentication itself?
- How should you store user information?
- How should you best secure the user credentials?
These, and many more questions, need to be taken into consideration before you embark on writing a login portal. But, there is a better way.
Many sites, social networks chiefly among them, allow you to use their platforms for authentication of your own applications. This is achieved using a number of different APIs – OAuth 1.0, OAuth 2.0, OpenID, OpenID Connect, etc.
Implementing your login flow by using these social login technologies offers a number of advantages.
- You are no longer responsible for rendering the UI for the user to authenticate with.
- You are no longer responsible for storing and securing sensitive user details.
- The user is able to use a single login for accessing multiple sites.
- If the user feels their password has been compromised, they can reset it once and benefit across many sites.
- Often, the service that provides the authentication functionality will make other details available. This can be used, for example, to automatically register users that have never used your site before, or to allow you to post updates to their profile on their behalf.
Why Use Token-based Authentication for Your API?
Any time a client requires access to your API, you will need some way to determine who they are and whether the access is permitted or not. There are several ways of achieving this, but the principal options are:
- Session-based authentication
- Cookie-based authentication
- Token-based authentication
Session-based authentication requires some way for your API service to associate a session with the client. This is often very straightforward to set up, but can suffer if you are deploying your API across multiple servers. You are also at the mercy of the mechanism that your server uses for session management and expiry, which might be out of your control.
Cookie-based is where you simply have some identifier stored in a cookie, and this is used to automatically identify the API request. This means that you need some mechanism of setting the cookie in the first place, and you risk leaking it on subsequent requests, since cookies are automatically included in all (suitable) requests to the same host.
Token-based is a variation on the cookie-based authentication, but putting more control in your hands. Essentially you generate a token in the same way as in a cookie-based authentication system, but you will include it with requests yourself — normally in the “Authorization” header or else directly in the URL. This means that you are completely in control of storing the token, which requests will include it, and so on.
Note: even though the HTTP Header is called “Authorization”, we are actually doing authentication with it. This is because we are using it to ascertain “who” the client is, not “what” the client is allowed to do.
The strategy that is used for generating the token is important as well. These tokens can either be reference tokens, which means that they are nothing more than an identifier that the server uses to look up the real details. Or complete tokens, which means that the token contains all of the information needed already.
Reference tokens have a significant security advantage in that there is absolutely no leakage to the client of the users credentials. There is a performance penalty though, in that you need to resolve the token into the actual credentials on every single request made.
Complete tokens are the opposite. They expose the user credentials to anyone who can understand the token, but because the token is complete there is no performance penalty on looking it up.
Often, Complete Tokens will be implemented using the JSON Web Tokens standard, since this has allowances in it for improving the security of the tokens. Specifically, JWTs allow for the token to be cryptographically signed, meaning that you can guarantee that the token has not been tampered with. There is also provision for them to be encrypted, meaning that without the encryption key the token can not even be decoded.
If you’d like a refresher on using JWTs in Node, check out our tutorial: Using JSON Web Tokens with Node.js.
The other downside to using a complete token is one of size. A reference token could be implemented, for example, using a UUID which would have a length of 36 characters. Conversely, a JWT can easily be hundreds of characters long.
For this article we are going to use JWT tokens to demonstrate how they can work. However, when you implement this for yourself you will need to decide on whether you wish to use reference or complete tokens, and what mechanism you will use for these.