1 package jwt
2
3 import (
4 "crypto/subtle"
5 "fmt"
6 "time"
7 )
8
9
10
11 type Claims interface {
12 Valid() error
13 }
14
15
16
17
18
19
20
21
22
23
24 type RegisteredClaims struct {
25
26 Issuer string `json:"iss,omitempty"`
27
28
29 Subject string `json:"sub,omitempty"`
30
31
32 Audience ClaimStrings `json:"aud,omitempty"`
33
34
35 ExpiresAt *NumericDate `json:"exp,omitempty"`
36
37
38 NotBefore *NumericDate `json:"nbf,omitempty"`
39
40
41 IssuedAt *NumericDate `json:"iat,omitempty"`
42
43
44 ID string `json:"jti,omitempty"`
45 }
46
47
48
49
50
51 func (c RegisteredClaims) Valid() error {
52 vErr := new(ValidationError)
53 now := TimeFunc()
54
55
56
57 if !c.VerifyExpiresAt(now, false) {
58 delta := now.Sub(c.ExpiresAt.Time)
59 vErr.Inner = fmt.Errorf("%s by %s", ErrTokenExpired, delta)
60 vErr.Errors |= ValidationErrorExpired
61 }
62
63 if !c.VerifyIssuedAt(now, false) {
64 vErr.Inner = ErrTokenUsedBeforeIssued
65 vErr.Errors |= ValidationErrorIssuedAt
66 }
67
68 if !c.VerifyNotBefore(now, false) {
69 vErr.Inner = ErrTokenNotValidYet
70 vErr.Errors |= ValidationErrorNotValidYet
71 }
72
73 if vErr.valid() {
74 return nil
75 }
76
77 return vErr
78 }
79
80
81
82 func (c *RegisteredClaims) VerifyAudience(cmp string, req bool) bool {
83 return verifyAud(c.Audience, cmp, req)
84 }
85
86
87
88 func (c *RegisteredClaims) VerifyExpiresAt(cmp time.Time, req bool) bool {
89 if c.ExpiresAt == nil {
90 return verifyExp(nil, cmp, req)
91 }
92
93 return verifyExp(&c.ExpiresAt.Time, cmp, req)
94 }
95
96
97
98 func (c *RegisteredClaims) VerifyIssuedAt(cmp time.Time, req bool) bool {
99 if c.IssuedAt == nil {
100 return verifyIat(nil, cmp, req)
101 }
102
103 return verifyIat(&c.IssuedAt.Time, cmp, req)
104 }
105
106
107
108 func (c *RegisteredClaims) VerifyNotBefore(cmp time.Time, req bool) bool {
109 if c.NotBefore == nil {
110 return verifyNbf(nil, cmp, req)
111 }
112
113 return verifyNbf(&c.NotBefore.Time, cmp, req)
114 }
115
116
117
118 func (c *RegisteredClaims) VerifyIssuer(cmp string, req bool) bool {
119 return verifyIss(c.Issuer, cmp, req)
120 }
121
122
123
124
125
126
127
128
129
130
131 type StandardClaims struct {
132 Audience string `json:"aud,omitempty"`
133 ExpiresAt int64 `json:"exp,omitempty"`
134 Id string `json:"jti,omitempty"`
135 IssuedAt int64 `json:"iat,omitempty"`
136 Issuer string `json:"iss,omitempty"`
137 NotBefore int64 `json:"nbf,omitempty"`
138 Subject string `json:"sub,omitempty"`
139 }
140
141
142
143
144 func (c StandardClaims) Valid() error {
145 vErr := new(ValidationError)
146 now := TimeFunc().Unix()
147
148
149
150 if !c.VerifyExpiresAt(now, false) {
151 delta := time.Unix(now, 0).Sub(time.Unix(c.ExpiresAt, 0))
152 vErr.Inner = fmt.Errorf("%s by %s", ErrTokenExpired, delta)
153 vErr.Errors |= ValidationErrorExpired
154 }
155
156 if !c.VerifyIssuedAt(now, false) {
157 vErr.Inner = ErrTokenUsedBeforeIssued
158 vErr.Errors |= ValidationErrorIssuedAt
159 }
160
161 if !c.VerifyNotBefore(now, false) {
162 vErr.Inner = ErrTokenNotValidYet
163 vErr.Errors |= ValidationErrorNotValidYet
164 }
165
166 if vErr.valid() {
167 return nil
168 }
169
170 return vErr
171 }
172
173
174
175 func (c *StandardClaims) VerifyAudience(cmp string, req bool) bool {
176 return verifyAud([]string{c.Audience}, cmp, req)
177 }
178
179
180
181 func (c *StandardClaims) VerifyExpiresAt(cmp int64, req bool) bool {
182 if c.ExpiresAt == 0 {
183 return verifyExp(nil, time.Unix(cmp, 0), req)
184 }
185
186 t := time.Unix(c.ExpiresAt, 0)
187 return verifyExp(&t, time.Unix(cmp, 0), req)
188 }
189
190
191
192 func (c *StandardClaims) VerifyIssuedAt(cmp int64, req bool) bool {
193 if c.IssuedAt == 0 {
194 return verifyIat(nil, time.Unix(cmp, 0), req)
195 }
196
197 t := time.Unix(c.IssuedAt, 0)
198 return verifyIat(&t, time.Unix(cmp, 0), req)
199 }
200
201
202
203 func (c *StandardClaims) VerifyNotBefore(cmp int64, req bool) bool {
204 if c.NotBefore == 0 {
205 return verifyNbf(nil, time.Unix(cmp, 0), req)
206 }
207
208 t := time.Unix(c.NotBefore, 0)
209 return verifyNbf(&t, time.Unix(cmp, 0), req)
210 }
211
212
213
214 func (c *StandardClaims) VerifyIssuer(cmp string, req bool) bool {
215 return verifyIss(c.Issuer, cmp, req)
216 }
217
218
219
220 func verifyAud(aud []string, cmp string, required bool) bool {
221 if len(aud) == 0 {
222 return !required
223 }
224
225 result := false
226
227 var stringClaims string
228 for _, a := range aud {
229 if subtle.ConstantTimeCompare([]byte(a), []byte(cmp)) != 0 {
230 result = true
231 }
232 stringClaims = stringClaims + a
233 }
234
235
236 if len(stringClaims) == 0 {
237 return !required
238 }
239
240 return result
241 }
242
243 func verifyExp(exp *time.Time, now time.Time, required bool) bool {
244 if exp == nil {
245 return !required
246 }
247 return now.Before(*exp)
248 }
249
250 func verifyIat(iat *time.Time, now time.Time, required bool) bool {
251 if iat == nil {
252 return !required
253 }
254 return now.After(*iat) || now.Equal(*iat)
255 }
256
257 func verifyNbf(nbf *time.Time, now time.Time, required bool) bool {
258 if nbf == nil {
259 return !required
260 }
261 return now.After(*nbf) || now.Equal(*nbf)
262 }
263
264 func verifyIss(iss string, cmp string, required bool) bool {
265 if iss == "" {
266 return !required
267 }
268 return subtle.ConstantTimeCompare([]byte(iss), []byte(cmp)) != 0
269 }
270
View as plain text