Skip to content
This repository has been archived by the owner on May 21, 2022. It is now read-only.

Commit

Permalink
Add support for array value of aud
Browse files Browse the repository at this point in the history
  • Loading branch information
dklesev committed Aug 27, 2019
1 parent 5e25c22 commit f6eb27a
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 14 deletions.
62 changes: 49 additions & 13 deletions claims.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package jwt

import (
"crypto/subtle"
"encoding/json"
"fmt"
"time"
)
Expand All @@ -12,17 +13,34 @@ type Claims interface {
Valid() error
}

// https://tools.ietf.org/html/rfc7519#section-4.1.3
type Audience []string

// Structured version of Claims Section, as referenced at
// https://tools.ietf.org/html/rfc7519#section-4.1
// See examples for how to use this with your own claim types
type StandardClaims struct {
Audience string `json:"aud,omitempty"`
ExpiresAt int64 `json:"exp,omitempty"`
Id string `json:"jti,omitempty"`
IssuedAt int64 `json:"iat,omitempty"`
Issuer string `json:"iss,omitempty"`
NotBefore int64 `json:"nbf,omitempty"`
Subject string `json:"sub,omitempty"`
Audience Audience `json:"aud,omitempty"`
ExpiresAt int64 `json:"exp,omitempty"`
Id string `json:"jti,omitempty"`
IssuedAt int64 `json:"iat,omitempty"`
Issuer string `json:"iss,omitempty"`
NotBefore int64 `json:"nbf,omitempty"`
Subject string `json:"sub,omitempty"`
}

// To support string and []string
func (aud *Audience) UnmarshalJSON(b []byte) error {
if b[0] != '"' {
var a []string
if err := json.Unmarshal(b, &a); err != nil {
return err
}
*aud = a
} else {
*aud = Audience{string(b)}
}
return nil
}

// Validates time based claims "exp, iat, nbf".
Expand Down Expand Up @@ -61,6 +79,10 @@ func (c StandardClaims) Valid() error {
// Compares the aud claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func (c *StandardClaims) VerifyAudience(cmp string, req bool) bool {
return verifyAud(c.Audience, []string{cmp}, req)
}

func (c *StandardClaims) VerifyMultipleAudiences(cmp []string, req bool) bool {
return verifyAud(c.Audience, cmp, req)
}

Expand Down Expand Up @@ -90,15 +112,29 @@ func (c *StandardClaims) VerifyNotBefore(cmp int64, req bool) bool {

// ----- helpers

func verifyAud(aud string, cmp string, required bool) bool {
if aud == "" {
func contains(aud Audience, cmp string) bool {
for _, a := range aud {
if subtle.ConstantTimeCompare([]byte(a), []byte(cmp)) != 0 {
return true
} else {
return false
}
}
return false
}

func verifyAud(aud Audience, cmp []string, required bool) bool {
if len(aud) < 1 {
return !required
}
if subtle.ConstantTimeCompare([]byte(aud), []byte(cmp)) != 0 {
return true
} else {
return false

for _, c := range cmp {
if !contains(aud, c) {
return false
}
}

return true
}

func verifyExp(exp int64, now int64, required bool) bool {
Expand Down
8 changes: 7 additions & 1 deletion map_claims.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@ type MapClaims map[string]interface{}
// Compares the aud claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func (m MapClaims) VerifyAudience(cmp string, req bool) bool {
aud, _ := m["aud"].(string)
aud, _ := m["aud"].(Audience)
return verifyAud(aud, []string{cmp}, req)
}

// Compares the aud claim against cmp which is an array of strings
func (m MapClaims) VerifyMultipleAudiences(cmp []string, req bool) bool {
aud, _ := m["aud"].(Audience)
return verifyAud(aud, cmp, req)
}

Expand Down

0 comments on commit f6eb27a

Please sign in to comment.