...

Source file src/github.com/golang-jwt/jwt/claims.go

Documentation: github.com/golang-jwt/jwt

     1  package jwt
     2  
     3  import (
     4  	"crypto/subtle"
     5  	"fmt"
     6  	"time"
     7  )
     8  
     9  // For a type to be a Claims object, it must just have a Valid method that determines
    10  // if the token is invalid for any supported reason
    11  type Claims interface {
    12  	Valid() error
    13  }
    14  
    15  // Structured version of Claims Section, as referenced at
    16  // https://tools.ietf.org/html/rfc7519#section-4.1
    17  // See examples for how to use this with your own claim types
    18  type StandardClaims struct {
    19  	Audience  string `json:"aud,omitempty"`
    20  	ExpiresAt int64  `json:"exp,omitempty"`
    21  	Id        string `json:"jti,omitempty"`
    22  	IssuedAt  int64  `json:"iat,omitempty"`
    23  	Issuer    string `json:"iss,omitempty"`
    24  	NotBefore int64  `json:"nbf,omitempty"`
    25  	Subject   string `json:"sub,omitempty"`
    26  }
    27  
    28  // Validates time based claims "exp, iat, nbf".
    29  // There is no accounting for clock skew.
    30  // As well, if any of the above claims are not in the token, it will still
    31  // be considered a valid claim.
    32  func (c StandardClaims) Valid() error {
    33  	vErr := new(ValidationError)
    34  	now := TimeFunc().Unix()
    35  
    36  	// The claims below are optional, by default, so if they are set to the
    37  	// default value in Go, let's not fail the verification for them.
    38  	if !c.VerifyExpiresAt(now, false) {
    39  		delta := time.Unix(now, 0).Sub(time.Unix(c.ExpiresAt, 0))
    40  		vErr.Inner = fmt.Errorf("token is expired by %v", delta)
    41  		vErr.Errors |= ValidationErrorExpired
    42  	}
    43  
    44  	if !c.VerifyIssuedAt(now, false) {
    45  		vErr.Inner = fmt.Errorf("Token used before issued")
    46  		vErr.Errors |= ValidationErrorIssuedAt
    47  	}
    48  
    49  	if !c.VerifyNotBefore(now, false) {
    50  		vErr.Inner = fmt.Errorf("token is not valid yet")
    51  		vErr.Errors |= ValidationErrorNotValidYet
    52  	}
    53  
    54  	if vErr.valid() {
    55  		return nil
    56  	}
    57  
    58  	return vErr
    59  }
    60  
    61  // Compares the aud claim against cmp.
    62  // If required is false, this method will return true if the value matches or is unset
    63  func (c *StandardClaims) VerifyAudience(cmp string, req bool) bool {
    64  	return verifyAud([]string{c.Audience}, cmp, req)
    65  }
    66  
    67  // Compares the exp claim against cmp.
    68  // If required is false, this method will return true if the value matches or is unset
    69  func (c *StandardClaims) VerifyExpiresAt(cmp int64, req bool) bool {
    70  	return verifyExp(c.ExpiresAt, cmp, req)
    71  }
    72  
    73  // Compares the iat claim against cmp.
    74  // If required is false, this method will return true if the value matches or is unset
    75  func (c *StandardClaims) VerifyIssuedAt(cmp int64, req bool) bool {
    76  	return verifyIat(c.IssuedAt, cmp, req)
    77  }
    78  
    79  // Compares the iss claim against cmp.
    80  // If required is false, this method will return true if the value matches or is unset
    81  func (c *StandardClaims) VerifyIssuer(cmp string, req bool) bool {
    82  	return verifyIss(c.Issuer, cmp, req)
    83  }
    84  
    85  // Compares the nbf claim against cmp.
    86  // If required is false, this method will return true if the value matches or is unset
    87  func (c *StandardClaims) VerifyNotBefore(cmp int64, req bool) bool {
    88  	return verifyNbf(c.NotBefore, cmp, req)
    89  }
    90  
    91  // ----- helpers
    92  
    93  func verifyAud(aud []string, cmp string, required bool) bool {
    94  	if len(aud) == 0 {
    95  		return !required
    96  	}
    97  	// use a var here to keep constant time compare when looping over a number of claims
    98  	result := false
    99  
   100  	var stringClaims string
   101  	for _, a := range aud {
   102  		if subtle.ConstantTimeCompare([]byte(a), []byte(cmp)) != 0 {
   103  			result = true
   104  		}
   105  		stringClaims = stringClaims + a
   106  	}
   107  
   108  	// case where "" is sent in one or many aud claims
   109  	if len(stringClaims) == 0 {
   110  		return !required
   111  	}
   112  
   113  	return result
   114  }
   115  
   116  func verifyExp(exp int64, now int64, required bool) bool {
   117  	if exp == 0 {
   118  		return !required
   119  	}
   120  	return now <= exp
   121  }
   122  
   123  func verifyIat(iat int64, now int64, required bool) bool {
   124  	if iat == 0 {
   125  		return !required
   126  	}
   127  	return now >= iat
   128  }
   129  
   130  func verifyIss(iss string, cmp string, required bool) bool {
   131  	if iss == "" {
   132  		return !required
   133  	}
   134  	if subtle.ConstantTimeCompare([]byte(iss), []byte(cmp)) != 0 {
   135  		return true
   136  	} else {
   137  		return false
   138  	}
   139  }
   140  
   141  func verifyNbf(nbf int64, now int64, required bool) bool {
   142  	if nbf == 0 {
   143  		return !required
   144  	}
   145  	return now >= nbf
   146  }
   147  

View as plain text