From zero to JWT certification, workflow:

1 reading rfc7519

Rfc7519 is the authentication protocol of JWT. There are two implementations of JWT (JWS and JWE), but JWS is widely used. By default, JWT refers to JWS.

  • The header (typ, cty)
  • playload
    • Registered Claims name registered Claims name Iss (publisher), SUB (subject), AUD (receiver), exp(expiration time), IAT (publisher), JTI (JWT ID), NBF (before when is not available)
    • You can define public claim names and private Claim names as required.
  • Signature, used to verify the identity of the sender, is encrypted from the first two parts.

Jwt-go: jwt-go: jwt-go: jwt-go: jwt-go:

package main

import (
   "fmt"
   "github.com/dgrijalva/jwt-go"
   "time"
)

const (
   SECRETKEY = "243223ffslsfsldfl412fdsfsdf" / / the private key
)

type CustomClaims struct {
   UserId int64
   jwt.StandardClaims
}
// Ignore error handling because it is only a demo
func main(a) {
   maxAge := 60 * 60 * 24
   customClaims := &CustomClaims{
      UserId: 11,
      StandardClaims: jwt.StandardClaims{
         ExpiresAt: time.Now().Add(time.Duration(maxAge) * time.Second).Unix(),
         Issuer:    "marry",}}// customClaims corresponds to declaring a structure and then defining claims
   // Since the declared structure contains StandardClaims, it implements the Claims interface
   // Claims1 uses the package's built-in MapClaims type (MapClaims already implements Cliams).
   claims1 := jwt.MapClaims{
      "id":11."name":"mary"."exp":time.Now().Add(time.Duration(maxAge)*time.Second).Unix(),
   }
   // new token with sha256
   token := jwt.NewWithClaims(jwt.SigningMethodHS256, customClaims)
   token1 := jwt.NewWithClaims(jwt.SigningMethodHS256, claims1)
   // signature with secret, return string
   tokenString, _ := token.SignedString([]byte(SECRETKEY))
   tokenString1, _ := token1.SignedString([]byte(SECRETKEY))
   fmt.Printf("token: %v\ntoken1: %v\n",tokenString, tokenString1)
   / / parsing tokenString
   ret, _ := ParseToken(tokenString)
   ret1, _ := ParseToken(tokenString1)
   fmt.Printf("user: %v\nuser1:%v",ret, ret1)
}

func ParseToken(tokenString string) (*CustomClaims, error) {
   token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (i interface{}, err error) {
      if_, ok := token.Method.(*jwt.SigningMethodHMAC); ! ok {return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])}return []byte(SECRETKEY), nil
   })
   if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
      return claims, nil
   } else {
      return nil, err
   }
}
Copy the code

At this point, you have a rough idea of how to use JWT.

2 read rfc6749

Rfc6749 is a specification for oauth2.0. I won’t use it in this assignment, but that’s what I’m interested in.

2.1 Protocol Flow

The interaction between the four roles in authentication is shown here:

(A) The client requests authorization from the Resource Owner. This authorization request can be sent directly to the Resource Owner or made indirectly through the Authorization Server (for example, a common jump to the authorization server).

(B) Client is authorized. The protocol specifies four authorization modes: authorization code mode, simplified mode, password mode, and client mode. Github authorizes a third party to use the authorization code mode, which is also commonly used and not described here.

(C) The client requests tokens like the Authorization Server through the authorization grant.

(D) Authorization Server verifies the grant issued by the client. If the grant is valid, the authorization server issues the token.

(E) The client requests resources from the Resource Server through a token.

Expected (F) Resource Server verifies the token and returns the resource if it is valid.

Specification CH4-CH9 describes various specifications for request and response.

2.2 Github Authorizes third-party Login to Demo

Github authorizes third-party websites to log in and obtain user information. The process is as follows:

  • Sign up for third-party apps on Github. Then use registered urls and redirect urls, Github generated clientId and Secret.

  • If a user selects Github to authorize login from a third-party application, the browser is redirected to the Github login page.

  • The user has successfully logged in to Github. The third-party application is returned according to the specified redirection URL. In this case, the URL carries the authorization code parameter code

  • A third-party application obtains an authorization code and obtains a token from Github using the authorization code.

  • Github returns a token.

  • After receiving the token, the third-party application obtains user information using the token.

In this case, the third-party application is the client, Github is the Resource server, github has its own authorization serer, and the user is the Resource owner.

3 Understand the storage policies of various tokens

With that said, HOWEVER, I still have a problem with a standard, applicable SSO mechanism, especially the storage of tokens. Although JWT has encryption and signatures, there is no difference between a signature and plaintext if it is leaked. Obviously, sensitive information should not be placed in JWT. However, JWT does have a wide application in microservices. Therefore, I need to learn the storage mechanism of various tokens.

3.1 Authentication Mode of Postman

Postman mentioned common authentication methods, so I tried to understand the meanings of various Authorization types:

  • Inherit auth from parent: inherit, default authentication mode

  • No auth: no authentication

  • Bearer of tokens: Commonly known as JWT tokens that have been sent in JSON format, servers have roughly read RFC6750 for token validation.

  • Basic Token: a common authentication mode that provides user name and password authentication and automatic postman authorization.

  • Digest Auth: indicates digest authentication. Expanded the security, on the basic authentication server for each connection to generate a unique random number, the client with the random Numbers to MD5 encryption password, and then back to the server, the server with the random Numbers to encrypt the password, and then sent the client and the encryption of data comparison, if you agree, return the result. It is a secondary authentication process with two authentication exchange messages. When the client requests resources, the server returns the authentication identifier. When the client sends authentication information, the server checks authentication.

  • Hawk authentication: Another authentication scheme that uses the message code authentication algorithm. Similar to Digest authentication, hawk authentication requires a second interaction

  • Aws Signature: Aws signature authentication is used to authenticate the aws public cloud user signatures of Amazon

  • NTLM Authentication [beta]: Microsoft LAN management authentication protocol.

However, after reading these, my problem is still not solved. So I went to understand github, Baidu Translation, b station’s practice, here just talk about Github.

3.2 making

Direct Postman to github for some urls, result:

Eg1: sends requests using Postman without setting cookies

Eg2:

Eg3:

Related cookie Meaning:

  • Logged_in: indicates whether to log in

  • _octo: This cookie is used by our internal analytics service to distinguish unique users and clients.

  • _gh_sess: This cookie is used for temporary application and framework state between pages like what step the user is on in a multiple step form.

  • _ga: This cookie is used by Google Analytics

  • _device_id: used to trace and identify devices

  • Tz: The browser informs github users of their time zone

  • User_session: This field is used for login and should be the sessionID

  • _host-user_session_same_site: This cookie is set to ensure that browsers that support the SameSite cookie can check whether the request is coming from GitHub. (Samesite-cookies is a mechanism for defining how cookies are sent across domains.)

  • Logged_in: indicates whether to log in

  • Dotcom_user: indicates that the user has logged in

  • has_recent_activity: This cookie is used to prevent showing the security interstitial to users that have visited the app recently

4. My solution

Github uses the session-cookie mechanism to directly store authentication related content in the cookie. The core field is user-session(as long as there is this field, normal access can be achieved. The process is to log in to the account and return the cookie to the client). Therefore, I think there is no problem to put the token in the cookie.

So how to design a simple and workable SSO mechanism?

1 Set the JWT field in the cookie to httpOnly, which is operated by the backend only

Reason: It is currently a common practice not to let the front end manipulate sensitive cookies to prevent XSS attacks. In github’s cookie, only insensitive fields such as time zone are not set to httpOnly, while SITE B only sets one field related to session to httpOnly. Baidu Translate is a compromise between the two. So I think whether you need to set cookies to httpOnly depends on what kind of risk the designer thinks the application is facing and how secure it needs to be. I think a few of our cookie fields are a little sensitive, but really, it’s the token that’s really sensitive, so you can just set the token to httpOnly(the code involved here is just a few details).

2 Use the whitelist mechanism to store tokens

That is, every time a user logs in, he/she issues a token and stores the token in redis in the form of key value. Every time the token verification is performed, he/she also needs to check whether the token is available. When the user logs out, the token is removed from Redis.

Why not consider blacklists? Because the blacklist will swell, and the whitelist will always store the currently valid tokens, the overall volume will not be large.

3 Use RPC and middleware to implement authentication

Set up a simple GRPC authentication service. If the token is unexpired, unmodified, or whitelisted, it is valid.

While I didn’t do the GRPC part, I did write…. for middleware

Reason: computer into half a bottle of Oriental leaves…. Become stupid on the spot, after standing still, just open the computer thought good, in fact, is more serious… For the hair and mood of programmers, drink water with a lid on it…