forked from clerk/clerk-sdk-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
jwt.go
138 lines (122 loc) · 4.31 KB
/
jwt.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package clerk
import (
"context"
"encoding/json"
"time"
"github.com/go-jose/go-jose/v3/jwt"
)
type key string
const clerkActiveSessionClaims = key("clerkActiveSessionClaims")
// ContextWithSessionClaims returns a new context which includes the
// active session claims.
func ContextWithSessionClaims(ctx context.Context, value any) context.Context {
return context.WithValue(ctx, clerkActiveSessionClaims, value)
}
// SessionClaimsFromContext returns the active session claims from
// the context.
func SessionClaimsFromContext(ctx context.Context) (*SessionClaims, bool) {
claims, ok := ctx.Value(clerkActiveSessionClaims).(*SessionClaims)
return claims, ok
}
// SessionClaims represents Clerk specific JWT claims.
type SessionClaims struct {
// Standard IANA JWT claims
RegisteredClaims
// Clerk specific JWT claims
Claims
// Custom can hold any custom claims that might be found in a JWT.
Custom any `json:"-"`
}
func (s *SessionClaims) UnmarshalJSON(data []byte) error {
err := json.Unmarshal(data, &s.RegisteredClaims)
if err != nil {
return err
}
err = json.Unmarshal(data, &s.Claims)
return err
}
// HasPermission checks if the session claims contain the provided
// organization permission.
// Use this helper to check if a user has the specific permission in
// the active organization.
func (s *SessionClaims) HasPermission(permission string) bool {
for _, sessPermission := range s.ActiveOrganizationPermissions {
if sessPermission == permission {
return true
}
}
return false
}
// HasRole checks if the session claims contain the provided
// organization role.
// However, the HasPermission helper is the recommended way to
// check for permissions. Complex role checks can usually be
// translated to a single permission check.
// For example, checks for an "admin" role that can modify a resource
// can be replaced by checks for a "modify" permission.
func (s *SessionClaims) HasRole(role string) bool {
return s.ActiveOrganizationRole == role
}
// RegisteredClaims holds public claim values (as specified in RFC 7519).
type RegisteredClaims struct {
Issuer string `json:"iss,omitempty"`
Subject string `json:"sub,omitempty"`
Audience []string `json:"aud,omitempty"`
Expiry *int64 `json:"exp,omitempty"`
NotBefore *int64 `json:"nbf,omitempty"`
IssuedAt *int64 `json:"iat,omitempty"`
ID string `json:"jti,omitempty"`
raw jwt.Claims
}
func (c *RegisteredClaims) UnmarshalJSON(data []byte) error {
err := json.Unmarshal(data, &c.raw)
if err != nil {
return err
}
c.Issuer = c.raw.Issuer
c.Subject = c.raw.Subject
c.Audience = c.raw.Audience
c.ID = c.raw.ID
if c.raw.Expiry != nil {
c.Expiry = Int64(c.raw.Expiry.Time().Unix())
}
if c.raw.NotBefore != nil {
c.NotBefore = Int64(c.raw.NotBefore.Time().Unix())
}
if c.raw.IssuedAt != nil {
c.IssuedAt = Int64(c.raw.IssuedAt.Time().Unix())
}
return nil
}
// ValidateWithLeeway checks expiration and issuance claims against
// an expected time.
// You may pass a zero value to check the time values with no leeway,
// but it is not recommended.
// The leeway gives some extra time to the token from the server's
// point of view. That is, if the token is expired, ValidateWithLeeway
// will still accept the token for 'leeway' amount of time.
func (c *RegisteredClaims) ValidateWithLeeway(expected time.Time, leeway time.Duration) error {
return c.raw.ValidateWithLeeway(jwt.Expected{Time: expected}, leeway)
}
// Claims represents private JWT claims that are defined and used
// by Clerk.
type Claims struct {
SessionID string `json:"sid"`
AuthorizedParty string `json:"azp"`
ActiveOrganizationID string `json:"org_id"`
ActiveOrganizationSlug string `json:"org_slug"`
ActiveOrganizationRole string `json:"org_role"`
ActiveOrganizationPermissions []string `json:"org_permissions"`
Actor json.RawMessage `json:"act,omitempty"`
}
// UnverifiedToken holds the result of a JWT decoding without any
// verification.
// The UnverifiedToken includes registered and custom claims, as
// well as the KeyID (kid) header.
type UnverifiedToken struct {
RegisteredClaims
// Any headers not recognized get unmarshalled
// from JSON in a generic manner and placed in this map.
Extra map[string]any
KeyID string
}