1package jwt
2
3import (
4 "encoding/json"
5 "fmt"
6)
7
8// MapClaims is a claims type that uses the map[string]interface{} for JSON
9// decoding. This is the default claims type if you don't supply one
10type MapClaims map[string]interface{}
11
12// GetExpirationTime implements the Claims interface.
13func (m MapClaims) GetExpirationTime() (*NumericDate, error) {
14 return m.parseNumericDate("exp")
15}
16
17// GetNotBefore implements the Claims interface.
18func (m MapClaims) GetNotBefore() (*NumericDate, error) {
19 return m.parseNumericDate("nbf")
20}
21
22// GetIssuedAt implements the Claims interface.
23func (m MapClaims) GetIssuedAt() (*NumericDate, error) {
24 return m.parseNumericDate("iat")
25}
26
27// GetAudience implements the Claims interface.
28func (m MapClaims) GetAudience() (ClaimStrings, error) {
29 return m.parseClaimsString("aud")
30}
31
32// GetIssuer implements the Claims interface.
33func (m MapClaims) GetIssuer() (string, error) {
34 return m.parseString("iss")
35}
36
37// GetSubject implements the Claims interface.
38func (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.
45func (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.
69func (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 []interface{}:
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.
92func (m MapClaims) parseString(key string) (string, error) {
93 var (
94 ok bool
95 raw interface{}
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}