Front-end authentication: cookie, session, token, jwt, single sign-on

Front-end authentication: cookie, session, token, jwt, single sign-on

1. Stateless HTTP protocol

Stateless means that the protocol has no memory ability for transaction processing. The lack of state means that if the previous information is needed later, it must be retransmitted, which may result in a large amount of data transmitted per connection. The stateless nature of HTTP seriously hinders the implementation of applications. After all, interaction needs to connect the past and the future. In some scenarios, we need to maintain state. The most typical example is that when a user logs in to Weibo, posting, following, and commenting should be in the logged-in user state.

So how to solve it?

At school or company, your identity and account information will be entered from the day you enroll in the company, and then a card will be issued to you. From now on, you only need to swipe this card for access control, punch-in, and consumption in the park.

This involves one issuance, one storage, and one area. Distribution is easy to handle. The login entrance is directly returned to the front end. Storage requires the front end to find a way.

The prerequisite is that you have to carry the card with you.

2. Front-end storage
  • The most embarrassing thing is to hang it on a global variable, but this is an “experience card” and it will be gone after refreshing the page.
  • The high-end ones are stored in cookies, localStorage, etc. This is a “membership card”. No matter how you refresh it, as long as the browser has not cleared it or expired, it will always be in this state.

If there is a place to save it, you can put it into the parameters and bring it to the interface when requesting.

3. Cookie

But the front-end is so troublesome. You have to save it yourself and find a way to take it out. Is there anything you don’t have to worry about?

Yes, cookies.

Cookies are also a type of front-end storage, but compared to other methods such as localStorage, cookies can be front-end unaware with the help of HTTP headers and browser capabilities.

The general process is this:

  • In the interface that provides the markup, it is directly stored in the browser through the Set-Cookie field of the HTTP response header.
  • When the browser initiates a request, it will automatically bring the cookie to the interface through the Cookie field of the HTTP request header.

Configuration:

  1. Domain/Path

    You cannot enter Peking University with a Tsinghua campus card.

    Cookies need to be restricted (spatial range) through Domain/Path two levels.

    The Domain attribute specifies which domain names should be accompanied by this cookie when the browser makes an HTTP request. If this attribute is not specified, the browser will default to the first-level domain name of the current URL. For example, www.example.com will be set to example.com, and if you access any subdomain name of example.com in the future, the HTTP request will also be Bring this cookie. If the domain name specified by the server in the Set-Cookie field does not belong to the current domain name, the browser will reject the cookie.

    The Path attribute specifies which paths should be accompanied by this cookie when the browser makes an HTTP request. As long as the browser finds that the Path attribute is the beginning part of the HTTP request path, it will bring this cookie in the header information. For example, if the PATH attribute is /, then the requested /docs path will also contain the cookie. Of course, the premise is that the domain names must be consistent.

    Cookie -Javascript Standard Reference Tutorial

  2. Expires/Max-Age

    After graduation, the card will no longer work.

    Cookies can also be limited (time range) through one of Expires and Max-Age.

    The Expires attribute specifies a specific expiration time. After the specified time, the browser will no longer retain this Cookie. Its value is in UTC format. If this attribute is not set, or is set to null, the cookie is only valid in the current session. Once the browser window is closed and the current session ends, the cookie will be deleted. In addition, the browser determines whether the cookie expires based on the local time. Since the local time is inaccurate, there is no way to guarantee that the cookie will expire at the time specified by the server.

    The Max-Age attribute specifies the number of seconds from now that the cookie will exist, such as 60 * 60 * 24 * 365 (i.e. one year). After this time, the browser will no longer retain this cookie.

    If Expires and Max-Age are specified at the same time, the value of Max-Age will take effect first.

    If the Set-Cookie field does not specify the Expires or Max-Age attributes, then this Cookie is a Session Cookie, that is, it only exists in this session. Once the user closes the browser, the browser will no longer retain this Cookie.

    Cookie -Javascript Standard Reference Tutorial

  3. Secure/HttpOnly

    Some schools do not allow stickers to be placed on cards.

    Cookies can be restricted (how they are used).

    The Secure attribute specifies that the browser can only send this cookie to the server under the encryption protocol HTTPS. On the other hand, if the current protocol is HTTP, the browser will automatically ignore the Secure attribute sent by the server. This property is just a switch and does not require a value to be specified. This switch is automatically turned on if the communication is HTTPS protocol.

    The HttpOnly attribute specifies that the cookie cannot be obtained through JavaScript scripts, mainly because the Document.cookie attribute, XMLHttpRequest object and Request API cannot obtain this attribute. This prevents the cookie from being read by scripts, and the cookie will only be brought when the browser makes an HTTP request.

    Cookie -Javascript Standard Reference Tutorial

Reading and writing HTTP headers to cookies:

Looking back, how does HTTP write and deliver cookies and their configuration?

The One Set-Cookie header of the HTTP response is used to write (one (and only one)) cookie to the browser, in the format of cookie key value + configuration key value. For example:

Set-Cookie: username=jimu; domain=jimu.com; path=/blog; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly

What should I do if I set more than one cookie at a time? Give more Set-Cookie response headers (duplication is allowed in one HTTP request)

Set-Cookie: username=jimu; domain=jimu.com
Set-Cookie: height=180; domain=me.jimu.com
Set-Cookie: weight=80; domain=me.jimu.com

The Cookie header of the HTTP request is used by the browser to send all cookies that match the current “space, time, and usage” configuration to the server. Because the browser makes the filtering judgment, there is no need to return the configuration content, just send the key value.

Cookie: username=jimu; height=180; weight=80

Front-end reading and writing of cookies

The front end can create cookies by itself. If the cookie created by the server does not add HttpOnly, the cookie given by it can be modified.

Calling document.cookie can create and modify cookies. Like HTTP, document.cookie can and can only operate one cookie at a time.

document.cookie = 'username=jimu; domain=jimu.com; path=/blog; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly';

Calling document.cookie can also read cookies. Like HTTP, all non-HttpOnly cookies can be read.

console.log(document.cookie);
// username=jimu; height=180; weight=80

Cookies are the cornerstone of maintaining HTTP request state

After understanding cookies, we know that cookies are the most convenient way to maintain HTTP request status. Most front-end authentication problems are solved by cookies. Of course, you can also choose other storage methods

4. Session

? Think about it now, what happened when you swiped your card?

In fact, there is only one ID (maybe your student number) stored on your card. When you swipe, the property management system will check your information and account, and then decide “whether you can enter this door.”

This operation is called session in the front-end and back-end authentication systems.

Typical session login/verification process:

  • The browser logs in and sends the account password, and the server checks the user database to verify the user.
  • The server saves the user login status as the Session library and generates a sessionId.
  • Return through the login interface and set the sessionId to the cookie.
  • After that, the browser requests the business interface again, and the sessionId is brought along with the cookie.
  • The server checks the sessionId to verify the session.
  • After success, perform business processing normally and return results.

Session storage method

The server only gives the cookie a sessionId, and the specific content of the session (which may include user information, session status, etc.) needs to be saved by itself. There are several ways to store:

  • Redis (recommended): In-memory database, redis Chinese official website. It is stored in the form of key-value, which is suitable for the scenario of sessionId-sessionData; and the access is fast.
  • Memory: put directly into variables. Once the service is restarted it will be gone
  • Database: ordinary database. Performance is not high.

Session expiration and destruction

It’s very simple, just destroy the stored session data.

Session Distribution Issues

Usually the server is a cluster, and user requests will go through load balancing once, not necessarily which machine. Then once the machine requested by the user’s subsequent interface is inconsistent with the machine he requested for login, or the machine requested for login is down, won’t the session become invalid?

There are currently several solutions to this problem.

  • The first is to store sessions centrally from a “storage” perspective. If we use an independent Redis or ordinary database, we can store all sessions in a library.
  • The second is from the perspective of “distribution”, so that requests with the same IP are sent to the same machine during load balancing. Taking nginx as an example, you can configure ip_hash to achieve this.

But the first method is usually adopted, because the second method is equivalent to emasculating load balancing, and still does not solve the problem of “the machine requested by the user is down.”

Session processing under node.js

The previous picture is very clear. To implement access to cookies and sessions on the server side, there is still a lot to do. In npm, there are already encapsulated middleware, such as express-session – npm.

express-session – npm mainly implements:

  • It encapsulates the read and write operations on cookies, and provides configuration item configuration fields, encryption methods, expiration time, etc.
  • It encapsulates the access operation to the session and provides configuration items to configure the session storage method (memory/redis), storage rules, etc.
  • Provides the session attribute to req, controls the set/get of the attribute and responds to cookie and session access, and provides some methods to req.session.
5. token

The maintenance of session causes a lot of trouble to the server. We must find a place to store it, consider distribution issues, and even enable a separate Redis cluster for it. Is there a better way?

I thought about school again. Before there was campus card technology, we all relied on “student ID cards”. The guard guy directly compared me with the face on the student ID card to confirm the validity period, grade and other information on the student ID card, and then he was released.

Looking back and thinking about it, in a login scenario, there is no need to store too many things in the session, so why not package it directly into a cookie? In this way, the server does not need to save it. It only needs to verify the validity of the “certificate” carried by the cookie every time, and it can also carry some lightweight information.

The token process is as follows:

  • User logs in, the server verifies the account password and obtains user information
  • Encode user information and token configuration into tokens and set them in cookies
  • After that, the user requests the business interface and carries the token through the cookie.
  • The interface verifies the validity of the token and performs normal business interface processing.

How client token is stored

As mentioned before, cookies are not the only way for clients to store credentials. Because token is “stateless”, the validity period and usage restrictions are all included in the token content. It relies less on cookie management capabilities, and the client can save it more freely. But the mainstream method of web applications is still to put it in cookies, after all, there is less to worry about.

Token expiration

So how do we control the validity period of the token? It’s very simple. Just put the “expiration time” and the data in it and judge it during verification.

Token encoding

base64

For example, the cookie-session – npm library on the node side, under the default configuration, when you give it a userid, it will be saved like this:

The eyJ1c2VyaWQiOiJhIn0= here is the base64 of {"userid":"abb"}.

Tamper-proof

Here comes the problem, if the user cdd takes {"userid":"abb"} and transfers it to base64, and then manually changes his token to eyJ1c2VyaWQiOiJhIn0= , is it possible to directly access abb’s data?

Yes. So depending on the situation, if the token involves sensitive permissions, you must find a way to prevent the token from being tampered with.

The solution is to add a signature to the token to identify whether the token has been tampered with. For example, in the cookie-session – npm library, add two configurations:

secret: 'iAmSecret'
signed: true

This will create one more .sig cookie, and the value inside is calculated by {"userid":"abb"} and iAmSecret through encryption algorithms. Common examples include Class HMACSHA256 (System.Security.Cryptography) | Microsoft Docs.

Now although cdd can forge eyJ1c2VyaWQiOiJhIn0=, it cannot forge the content of sig because he does not know the secret.

JWT

The above approach increased the number of cookies, and the data itself did not have a standardized format, so JSON Web Token Introduction – jwt.io was born.

JSON Web Token (JWT) is an open standard that defines a way to communicate JSON information. This information is digitally signed to ensure trustworthiness.

It is a mature token string generation scheme, including the data and signatures we mentioned earlier.

What a JWT token looks like:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyaWQiOiJhIiwiaWF0IjoxNTUxOTUxOTk4fQ.2jf3kl_uKWRkwjOP6uQRJFqMlwSABcgqqcJofFH5XCo

For type, encryption algorithm options, and JWT standard data fields, please refer to RFC 7519 – JSON Web Token (JWT)

There are also related library implementations on node: express-jwt – npm koa-jwt – npm

refresh token

Token, as the guardian of permissions, the most important thing is “security”.

The token used for authentication by the business interface is called access token. The more permission-sensitive the business is, the more we hope that the access token validity period is short enough to avoid being misappropriated. However, a too short validity period will cause the access token to expire frequently. What should I do after it expires?

One way is to ask the user to log in again to obtain a new token, which is obviously not friendly enough. You should know that some access tokens may only expire in a few minutes.

Another way is to use another token, a token that specifically generates access tokens, which we call refresh tokens.

  • The access token is used to access business interfaces. Since the validity period is short enough, the risk of theft is small, and it can also make the request method more relaxed and flexible.
  • The refresh token is used to obtain access tokens. The validity period can be longer, and security is increased through independent services and strict request methods. Since verification is infrequent, it can also be processed like the previous session.

With the refresh token, the request process in several situations becomes like this:

If the refresh token also expires, you can only log in again.

6. Session and token

Session and token are concepts with blurred boundaries. As mentioned before, refresh token may also be organized and maintained in the form of session.

In a narrow sense, we usually think that session is an authentication scheme that is “planted on a cookie, and the data is stored on the server.” Token is an authentication scheme that “the client can store it anywhere, and the data is stored in the token.” The comparison between session and token is essentially a comparison between “the client stores cookies/saves them elsewhere” and “the server stores data/does not store data”.

The client saves cookies / saves them elsewhere

Saving cookies is convenient and worry-free, but the problem is also obvious:

  • On the browser side, you can use cookies (in fact, tokens commonly use cookies), but outside the browser side, what should I do if there are no cookies?
  • Cookies are automatically carried by the browser under the domain, which can easily trigger CSRF attacks (Front-end Security Series (2): How to prevent CSRF attacks? – Meituan Technical Team)

Saving it elsewhere can solve the scenario without cookies; manually bringing it through parameters and other methods can avoid CSRF attacks.

Storing data on the server / not saving data

  • Storing data: The request only needs to carry the id, which can greatly shorten the length of the authentication string and reduce the size of the request.
  • No data stored: No need for a complete set of server-side solutions and distributed processing, reducing hardware costs; avoiding verification delays caused by database searches
7. Single sign-on

We have already known before that in the client/server authentication system under the same domain, the client carries credentials to maintain the login status for a period of time.

But as we have more and more business lines, more business systems will be scattered under different domain names, and we will need the ability of “one login, universal use”, which is called “single sign-on”.

“False” single sign-on (same primary domain name)

Simply, if the business systems are all under the same main domain name, such as wenku.baidu.com tieba.baidu.com, it will be easier to handle. You can directly set the cookie domain as the main domain name baidu.com, which is what Baidu does.

“Real” single sign-on (different primary domain name)

For example, Didi also owns didihuxing.com xiaaojukeji.com didiglobal.com and other domain names, so cookies cannot be avoided at all.

This must be able to achieve “one login, universal use”, which is the true single sign-on.

In this scenario, we need an independent authentication service, usually called SSO.

A complete process of “logging in from system A to system B without logging in”

  • The user enters system A without login credentials (ticket), and system A jumps to SSO for him.

  • If you have not logged in to SSO, there is no credential under the SSO system (note that this is different from the previous A ticket). Enter your account and password to log in.

  • If the SSO account password is successfully verified, two things will be done through the interface return: one is to plant the credentials under the SSO system (record the user’s SSO login status); the other is to issue a ticket

  • The client gets the ticket, saves it, and requests system A interface

  • System A verifies the ticket and processes the business request normally after success.

  • At this time, the user enters system B for the first time and does not have login credentials (ticket). System B jumps to SSO for him.

  • If you have logged in with SSO and have credentials in the system, you do not need to log in again. You only need to issue a ticket.

  • The client gets the ticket, saves it, and requests the system B interface

Full version: Consider the browser scenario

The above process seems fine. In fact, this is enough for many apps. But it may not work well in the browser.

For browsers, how should the data returned in the SSO domain be stored so that it can be brought with it when accessing A? Browsers have strict restrictions on cross-domain, and methods such as cookies and localStorage are subject to domain restrictions.

This requires and can only be provided by A with the ability to store credentials under domain A. Generally we do this:

In the picture, we mark the domain name where the browser is currently located by color. Pay attention to the changes in the gray background text description in the picture.

  • In the SSO domain, SSO does not return the ticket directly through the interface, but redirects it to the interface of system A through a URL with code. This interface is usually agreed upon when A registers with SSO.
  • The browser is redirected to domain A and accesses A’s callback interface with code. The callback interface exchanges code for tickets.
  • This code is different from the ticket. The code is one-time and is exposed in the URL. It is only used to change the ticket and it will become invalid after the change.
  • After the callback interface gets the ticket, it successfully sets cookies in its own domain.
  • In subsequent requests, you only need to parse the ticket in the cookie and go to SSO for verification.
  • The same goes for accessing system B
8. Summary
  • HTTP is stateless. In order to maintain previous and subsequent requests, front-end storage tags are required.
  • Cookie is a complete marking method that operates through HTTP headers or js and has corresponding security policies. It is the cornerstone of most state management solutions.
  • Session is a state management solution. The front end stores IDs through cookies, and the back end stores data, but the back end has to deal with distributed issues.
  • Token is another state management solution. Compared to session, which does not require back-end storage, all data is stored in the front-end, liberating the back-end and releasing flexibility.
  • Token encoding technology is usually based on base64, or adds an encryption algorithm to prevent tampering. JWT is a mature encoding scheme.
  • In complex systems, tokens can be decentralized through service tokens and refresh tokens to meet both security and user experience.
  • The comparison between session and token is the comparison between “whether to use cookies” and “whether to store in the backend”
  • Single sign-on requires “one login, universal use” for systems in different domains. Usually, an independent SSO system records login status and issues tickets, and each business system cooperates to store and authenticate tickets.