...

Source file src/github.com/golang-jwt/jwt/v4/parser.go

Documentation: github.com/golang-jwt/jwt/v4

     1  package jwt
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"strings"
     8  )
     9  
    10  type Parser struct {
    11  	// If populated, only these methods will be considered valid.
    12  	//
    13  	// Deprecated: In future releases, this field will not be exported anymore and should be set with an option to NewParser instead.
    14  	ValidMethods []string
    15  
    16  	// Use JSON Number format in JSON decoder.
    17  	//
    18  	// Deprecated: In future releases, this field will not be exported anymore and should be set with an option to NewParser instead.
    19  	UseJSONNumber bool
    20  
    21  	// Skip claims validation during token parsing.
    22  	//
    23  	// Deprecated: In future releases, this field will not be exported anymore and should be set with an option to NewParser instead.
    24  	SkipClaimsValidation bool
    25  }
    26  
    27  // NewParser creates a new Parser with the specified options
    28  func NewParser(options ...ParserOption) *Parser {
    29  	p := &Parser{}
    30  
    31  	// loop through our parsing options and apply them
    32  	for _, option := range options {
    33  		option(p)
    34  	}
    35  
    36  	return p
    37  }
    38  
    39  // Parse parses, validates, verifies the signature and returns the parsed token.
    40  // keyFunc will receive the parsed token and should return the key for validating.
    41  func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
    42  	return p.ParseWithClaims(tokenString, MapClaims{}, keyFunc)
    43  }
    44  
    45  // ParseWithClaims parses, validates, and verifies like Parse, but supplies a default object implementing the Claims
    46  // interface. This provides default values which can be overridden and allows a caller to use their own type, rather
    47  // than the default MapClaims implementation of Claims.
    48  //
    49  // Note: If you provide a custom claim implementation that embeds one of the standard claims (such as RegisteredClaims),
    50  // make sure that a) you either embed a non-pointer version of the claims or b) if you are using a pointer, allocate the
    51  // proper memory for it before passing in the overall claims, otherwise you might run into a panic.
    52  func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) {
    53  	token, parts, err := p.ParseUnverified(tokenString, claims)
    54  	if err != nil {
    55  		return token, err
    56  	}
    57  
    58  	// Verify signing method is in the required set
    59  	if p.ValidMethods != nil {
    60  		var signingMethodValid = false
    61  		var alg = token.Method.Alg()
    62  		for _, m := range p.ValidMethods {
    63  			if m == alg {
    64  				signingMethodValid = true
    65  				break
    66  			}
    67  		}
    68  		if !signingMethodValid {
    69  			// signing method is not in the listed set
    70  			return token, NewValidationError(fmt.Sprintf("signing method %v is invalid", alg), ValidationErrorSignatureInvalid)
    71  		}
    72  	}
    73  
    74  	// Lookup key
    75  	var key interface{}
    76  	if keyFunc == nil {
    77  		// keyFunc was not provided.  short circuiting validation
    78  		return token, NewValidationError("no Keyfunc was provided.", ValidationErrorUnverifiable)
    79  	}
    80  	if key, err = keyFunc(token); err != nil {
    81  		// keyFunc returned an error
    82  		if ve, ok := err.(*ValidationError); ok {
    83  			return token, ve
    84  		}
    85  		return token, &ValidationError{Inner: err, Errors: ValidationErrorUnverifiable}
    86  	}
    87  
    88  	vErr := &ValidationError{}
    89  
    90  	// Validate Claims
    91  	if !p.SkipClaimsValidation {
    92  		if err := token.Claims.Valid(); err != nil {
    93  
    94  			// If the Claims Valid returned an error, check if it is a validation error,
    95  			// If it was another error type, create a ValidationError with a generic ClaimsInvalid flag set
    96  			if e, ok := err.(*ValidationError); !ok {
    97  				vErr = &ValidationError{Inner: err, Errors: ValidationErrorClaimsInvalid}
    98  			} else {
    99  				vErr = e
   100  			}
   101  		}
   102  	}
   103  
   104  	// Perform validation
   105  	token.Signature = parts[2]
   106  	if err = token.Method.Verify(strings.Join(parts[0:2], "."), token.Signature, key); err != nil {
   107  		vErr.Inner = err
   108  		vErr.Errors |= ValidationErrorSignatureInvalid
   109  	}
   110  
   111  	if vErr.valid() {
   112  		token.Valid = true
   113  		return token, nil
   114  	}
   115  
   116  	return token, vErr
   117  }
   118  
   119  // ParseUnverified parses the token but doesn't validate the signature.
   120  //
   121  // WARNING: Don't use this method unless you know what you're doing.
   122  //
   123  // It's only ever useful in cases where you know the signature is valid (because it has
   124  // been checked previously in the stack) and you want to extract values from it.
   125  func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Token, parts []string, err error) {
   126  	parts = strings.Split(tokenString, ".")
   127  	if len(parts) != 3 {
   128  		return nil, parts, NewValidationError("token contains an invalid number of segments", ValidationErrorMalformed)
   129  	}
   130  
   131  	token = &Token{Raw: tokenString}
   132  
   133  	// parse Header
   134  	var headerBytes []byte
   135  	if headerBytes, err = DecodeSegment(parts[0]); err != nil {
   136  		if strings.HasPrefix(strings.ToLower(tokenString), "bearer ") {
   137  			return token, parts, NewValidationError("tokenstring should not contain 'bearer '", ValidationErrorMalformed)
   138  		}
   139  		return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
   140  	}
   141  	if err = json.Unmarshal(headerBytes, &token.Header); err != nil {
   142  		return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
   143  	}
   144  
   145  	// parse Claims
   146  	var claimBytes []byte
   147  	token.Claims = claims
   148  
   149  	if claimBytes, err = DecodeSegment(parts[1]); err != nil {
   150  		return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
   151  	}
   152  	dec := json.NewDecoder(bytes.NewBuffer(claimBytes))
   153  	if p.UseJSONNumber {
   154  		dec.UseNumber()
   155  	}
   156  	// JSON Decode.  Special case for map type to avoid weird pointer behavior
   157  	if c, ok := token.Claims.(MapClaims); ok {
   158  		err = dec.Decode(&c)
   159  	} else {
   160  		err = dec.Decode(&claims)
   161  	}
   162  	// Handle decode error
   163  	if err != nil {
   164  		return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
   165  	}
   166  
   167  	// Lookup signature method
   168  	if method, ok := token.Header["alg"].(string); ok {
   169  		if token.Method = GetSigningMethod(method); token.Method == nil {
   170  			return token, parts, NewValidationError("signing method (alg) is unavailable.", ValidationErrorUnverifiable)
   171  		}
   172  	} else {
   173  		return token, parts, NewValidationError("signing method (alg) is unspecified.", ValidationErrorUnverifiable)
   174  	}
   175  
   176  	return token, parts, nil
   177  }
   178  

View as plain text