map_claims.go raw

   1  package jwt
   2  
   3  import (
   4  	"encoding/json"
   5  	"fmt"
   6  )
   7  
   8  // MapClaims is a claims type that uses the map[string]any for JSON
   9  // decoding. This is the default claims type if you don't supply one
  10  type MapClaims map[string]any
  11  
  12  // GetExpirationTime implements the Claims interface.
  13  func (m MapClaims) GetExpirationTime() (*NumericDate, error) {
  14  	return m.parseNumericDate("exp")
  15  }
  16  
  17  // GetNotBefore implements the Claims interface.
  18  func (m MapClaims) GetNotBefore() (*NumericDate, error) {
  19  	return m.parseNumericDate("nbf")
  20  }
  21  
  22  // GetIssuedAt implements the Claims interface.
  23  func (m MapClaims) GetIssuedAt() (*NumericDate, error) {
  24  	return m.parseNumericDate("iat")
  25  }
  26  
  27  // GetAudience implements the Claims interface.
  28  func (m MapClaims) GetAudience() (ClaimStrings, error) {
  29  	return m.parseClaimsString("aud")
  30  }
  31  
  32  // GetIssuer implements the Claims interface.
  33  func (m MapClaims) GetIssuer() (string, error) {
  34  	return m.parseString("iss")
  35  }
  36  
  37  // GetSubject implements the Claims interface.
  38  func (m MapClaims) GetSubject() (string, error) {
  39  	return m.parseString("sub")
  40  }
  41  
  42  // parseNumericDate tries to parse a key in the map claims type as a number
  43  // date. This will succeed, if the underlying type is either a [float64] or a
  44  // [json.Number]. Otherwise, nil will be returned.
  45  func (m MapClaims) parseNumericDate(key string) (*NumericDate, error) {
  46  	v, ok := m[key]
  47  	if !ok {
  48  		return nil, nil
  49  	}
  50  
  51  	switch exp := v.(type) {
  52  	case float64:
  53  		if exp == 0 {
  54  			return nil, nil
  55  		}
  56  
  57  		return newNumericDateFromSeconds(exp), nil
  58  	case json.Number:
  59  		v, _ := exp.Float64()
  60  
  61  		return newNumericDateFromSeconds(v), nil
  62  	}
  63  
  64  	return nil, newError(fmt.Sprintf("%s is invalid", key), ErrInvalidType)
  65  }
  66  
  67  // parseClaimsString tries to parse a key in the map claims type as a
  68  // [ClaimsStrings] type, which can either be a string or an array of string.
  69  func (m MapClaims) parseClaimsString(key string) (ClaimStrings, error) {
  70  	var cs []string
  71  	switch v := m[key].(type) {
  72  	case string:
  73  		cs = append(cs, v)
  74  	case []string:
  75  		cs = v
  76  	case []any:
  77  		for _, a := range v {
  78  			vs, ok := a.(string)
  79  			if !ok {
  80  				return nil, newError(fmt.Sprintf("%s is invalid", key), ErrInvalidType)
  81  			}
  82  			cs = append(cs, vs)
  83  		}
  84  	}
  85  
  86  	return cs, nil
  87  }
  88  
  89  // parseString tries to parse a key in the map claims type as a [string] type.
  90  // If the key does not exist, an empty string is returned. If the key has the
  91  // wrong type, an error is returned.
  92  func (m MapClaims) parseString(key string) (string, error) {
  93  	var (
  94  		ok  bool
  95  		raw any
  96  		iss string
  97  	)
  98  	raw, ok = m[key]
  99  	if !ok {
 100  		return "", nil
 101  	}
 102  
 103  	iss, ok = raw.(string)
 104  	if !ok {
 105  		return "", newError(fmt.Sprintf("%s is invalid", key), ErrInvalidType)
 106  	}
 107  
 108  	return iss, nil
 109  }
 110