Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/jwt/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ func signToken() error {
// add command line claims
if len(flagClaims) > 0 {
for k, v := range flagClaims {
claims[k] = v
claims[jwt.ClaimsType(k)] = v
}
}

Expand Down
47 changes: 35 additions & 12 deletions map_claims.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,44 +5,67 @@ import (
"fmt"
)

// MapClaims is a claims type that uses the map[string]any for JSON
// decoding. This is the default claims type if you don't supply one
type MapClaims map[string]any
// ClaimsType is a type alias for claim keys in the [MapClaims] type.
type ClaimsType string

var (
// Exp is the "exp" claim key according to RFC 7519 section 4.1.4.
Exp ClaimsType = "exp"

// Nbf is the "nbf" claim key according to RFC 7519 section 4.1.5.
Nbf ClaimsType = "nbf"

// Iat is the "iat" claim key according to RFC 7519 section 4.1.6.
Iat ClaimsType = "iat"

// Aud is the "aud" claim key according to RFC 7519 section 4.1.3.
Aud ClaimsType = "aud"

// Iss is the "iss" claim key according to RFC 7519 section 4.1.1.
Iss ClaimsType = "iss"

// Sub is the "sub" claim key according to RFC 7519 section 4.1.2.
Sub ClaimsType = "sub"
)

// MapClaims is a claims type that uses of map of [ClaimsType] with value [any]
// for JSON decoding. This is the default claims type if you do not supply one.
type MapClaims map[ClaimsType]any

// GetExpirationTime implements the Claims interface.
func (m MapClaims) GetExpirationTime() (*NumericDate, error) {
return m.parseNumericDate("exp")
return m.parseNumericDate(Exp)
}

// GetNotBefore implements the Claims interface.
func (m MapClaims) GetNotBefore() (*NumericDate, error) {
return m.parseNumericDate("nbf")
return m.parseNumericDate(Nbf)
}

// GetIssuedAt implements the Claims interface.
func (m MapClaims) GetIssuedAt() (*NumericDate, error) {
return m.parseNumericDate("iat")
return m.parseNumericDate(Iat)
}

// GetAudience implements the Claims interface.
func (m MapClaims) GetAudience() (ClaimStrings, error) {
return m.parseClaimsString("aud")
return m.parseClaimsString(Aud)
}

// GetIssuer implements the Claims interface.
func (m MapClaims) GetIssuer() (string, error) {
return m.parseString("iss")
return m.parseString(Iss)
}

// GetSubject implements the Claims interface.
func (m MapClaims) GetSubject() (string, error) {
return m.parseString("sub")
return m.parseString(Sub)
}

// parseNumericDate tries to parse a key in the map claims type as a number
// date. This will succeed, if the underlying type is either a [float64] or a
// [json.Number]. Otherwise, nil will be returned.
func (m MapClaims) parseNumericDate(key string) (*NumericDate, error) {
func (m MapClaims) parseNumericDate(key ClaimsType) (*NumericDate, error) {
v, ok := m[key]
if !ok {
return nil, nil
Expand All @@ -66,7 +89,7 @@ func (m MapClaims) parseNumericDate(key string) (*NumericDate, error) {

// parseClaimsString tries to parse a key in the map claims type as a
// [ClaimsStrings] type, which can either be a string or an array of string.
func (m MapClaims) parseClaimsString(key string) (ClaimStrings, error) {
func (m MapClaims) parseClaimsString(key ClaimsType) (ClaimStrings, error) {
var cs []string
switch v := m[key].(type) {
case string:
Expand All @@ -89,7 +112,7 @@ func (m MapClaims) parseClaimsString(key string) (ClaimStrings, error) {
// parseString tries to parse a key in the map claims type as a [string] type.
// If the key does not exist, an empty string is returned. If the key has the
// wrong type, an error is returned.
func (m MapClaims) parseString(key string) (string, error) {
func (m MapClaims) parseString(key ClaimsType) (string, error) {
var (
ok bool
raw any
Expand Down
36 changes: 36 additions & 0 deletions map_claims_example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package jwt_test

import (
"fmt"

"github.com/golang-jwt/jwt/v5"
)

var (
// OpenIdConnectEMail represents the "email" claim as defined in
// OpenID Connect Core 1.0, section 5.1.
//
// Reference: https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
OpenIdConnectEMail jwt.ClaimsType = "email"
)

// ExampleMapClaims shows how to create a token with custom claims using
// [jwt.MapClaims] and the custom [jwt.ClaimsType].
func ExampleMapClaims() {
claims := jwt.MapClaims{
"custom_claim": "custom_value",
OpenIdConnectEMail: "me@example.com",
jwt.Sub: "me",
}

t := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
s, err := t.SignedString([]byte("secret"))
if err != nil {
panic(err)
}

fmt.Println(s)

// Output:
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b21fY2xhaW0iOiJjdXN0b21fdmFsdWUiLCJlbWFpbCI6Im1lQGV4YW1wbGUuY29tIiwic3ViIjoibWUifQ.ylWqOBiOzsJpcJQarXmPtvgGMP9d72Zc2GtEdriqXko
}
2 changes: 1 addition & 1 deletion map_claims_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ func TestMapClaimsVerifyExpiresAtExpire(t *testing.T) {

func TestMapClaims_parseString(t *testing.T) {
type args struct {
key string
key ClaimsType
}
tests := []struct {
name string
Expand Down