2.3 Authentication

Now that we can create users in the Issue Tracker application, we turn out attention to authentication and security. We'll learn about the difference between authentication and authorization, sometimes referred to as authn and authz, respectively. From there, we'll learn about common protocols implemented by a large number of companies that enable features like single sign-on (SSO).

Authentication vs. Authorization

These terms are so often misused and misinterpreted that it's worth dedicating a short section focused on clearing it up.

Authentication is used to verify that someone says who they say they are. In other words, if I log in to an application, I need to authenticate myself as the user that I claim to be. Traditionally, I perform this process by providing my username and password, which only I should know. Thus, when I use my private credentials and prove that I am the owner of the account, I have authenticated myself as the user that I say I am.

Authorization, on the other hand, is used to determine what actions a user is allowed to perform in an application (this is also known as access control). In other words, regardless of if the user is actually who they say they are, authorization determines what capabilities the user has.

For the Issue Tracker application, authentication is used in the login process (which you will develop in Assignment 3), whereas authorization can be used to make issues private to certain cohorts of users, and also distinguish between which users can edit issues versus read issues, similar to reading and writing documents created in Google Docs, for example).

Session management

As you've probably noticed, a variety of popular websites support persistent sessions, such that you're still logged in after days, weeks, or even months away from the platform (e.g. Amazon). Web browsers are able to support this functionality with HTTP cookies, which are small pieces of information that are exchanged between the Web browser client and the application server. In many cases, a cookie is used to personalize your experience, such that it is used to recognize which user is logged in.

The data encoded in an HTTP cookie depends on the application server that manages it. A common data format used in applications today is known as the JSON Web Token (JWT).

JWT

The JWT is a token format that is used to represent claims between two parties (i.e. the client and server). JWTs on their own are not inherently secure, but they can be signed with a secret value along with the HMAC algorithm (which is commonly paired with the SHA256 hash function). There's a lot to unpack here, so let's break it down with a visualization.

A JWT is represented as a dot-delimited string, containing exactly three components: the header, payload, and signature. This is represented as the following:

<$header>.<$payload>.<$signature>

The jwt.io website (created by Auth0) provides a great visualization tool for changing header, payload, and secret values so that you can visualize how the rest of the token changes. Give it a try, and set your own name in the payload, which is currently set to John Doe. Now try and change the secret value - do you see how the cryptographic signature changes with each of your keystokes? This demonstrates the effects of the HMAC-SHA256 hash algorithm in real-time!

JWTs in practice

But what's the point? How is this actually used in practice? The simple JWT structure can actually be used to implement both authentication and authorization flows.

JWT claims are encoded in the <$payload> portion of the token. The sub claim uniquely identifies the subject of the token, and is commonly used to associate a client request to some internal user data. For example, the sub claim can be used to associate a token to additional user data stored in the persistence layer, but not stored in the JWT.

For authentication, the application server can generate and respond with a JWT when the user logs in, and the user can use the token to make more authenticated requests. For web applications, the JWT can be stored as a HTTP cookie, which can be set in the client's browser with the Set-Cookie response header.

Then, for authorization, the JWT can encode a variable set of custom claims that can be recognized by the application server to grant additional permissions. For example, a user with admin privileges might have a JWT that contains a <$payload> with the following:

{
"sub": "1234567890",
"name": "<$YOUR_NAME>",
"admin": true
}

With this, the application server can handle client requests by first inspecting the JWT sent in the request's HTTP Cookie request header, verifying the signature contained (which prevents users from obfuscating information found in the <$header> and <$payload>), then determining what capabilities this user has based on the claims contained in the <$payload>, and finally serving the request by either permitting the operation or rejecting it based on unsatisfactory permissions.

OIDC and OAUTH2

The OpenID Connect Protocol (OIDC) is a protocol built on top of OAUTH2. In short, OIDC is used to implement single sign-on (SSO), which makes it possible for users to authenticate themselves with other popular applications. For example, you've probably signed in to an application with Google, Facebook, Apple, or some other identity provider - this is OIDC in action! When you log in with your identity provider of choice, your personal information is returned in the form of a JWT, which is then used to authenticate future requests (as described above).

Okta (another popular identity provider) created a fantastic video that explains OIDC in greater detail - please watch it by clicking on the image below before proceeding to the assignment!

OIDC Explained