5 Modern token-based authentication

This chapter covers

  • Supporting cross-domain web clients with CORS
  • Storing tokens using the Web Storage API
  • The standard Bearer HTTP authentication scheme for tokens
  • Hardening database token storage

With the addition of session cookie support, the Natter UI has become a slicker user experience, driving adoption of your platform. Marketing has bought a new domain name, nat.tr, in a doomed bid to appeal to younger users. They are insisting that logins should work across both the old and new domains, but your CSRF protections prevent the session cookies being used on the new domain from talking to the API on the old one. As the user base grows, you also want to expand to include mobile and desktop apps. Though cookies work great for web browser clients they are less natural for native apps because the client typically must manage them itself. You need to move beyond cookies and consider other ways to manage token-based authentication.

In this chapter, you’ll learn about alternatives to cookies using HTML 5 Web Storage and the standard Bearer authentication scheme for token-based authentication. You’ll enable cross-origin resource sharing (CORS) to allow cross-domain requests from the new site.


Cross-origin resource sharing (CORS) is a standard to allow some cross-origin requests to be permitted by web browsers. It defines a set of headers that an API can return to tell the browser which requests should be allowed.

5.1   Allowing cross-domain requests with CORS

5.1.1   Preflight requests

5.1.2   CORS headers

5.1.3   Adding CORS headers to the Natter API

5.2   Tokens without cookies

5.2.1   Storing token state in a database

5.2.2   The Bearer authentication scheme

5.2.3   Deleting expired tokens

5.2.4   Storing tokens in Web Storage

5.2.5   Updating the CORS filter

5.2.6   XSS attacks on Web Storage

5.3   Hardening database token storage

5.3.1   Hashing database tokens

5.3.2   Authenticating tokens with HMAC

5.3.3   Protecting sensitive attributes

5.4   Summary