Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Handler to check azp claim #247

Merged
merged 1 commit into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
27 changes: 23 additions & 4 deletions http/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,15 +160,34 @@ type AuthorizationParams struct {
// authorization options.
type AuthorizationOption func(*AuthorizationParams) error

// AuthorizedParty sets the authorized parties that will be checked
// against the azp JWT claim.
func AuthorizedParty(parties ...string) AuthorizationOption {
// AuthorizedParty allows to provide a handler that accepts the
// 'azp' claim.
// The handler can be used to perform validations on the azp claim
// and should return false to indicate that something is wrong.
func AuthorizedParty(handler func(string) bool) AuthorizationOption {
return func(params *AuthorizationParams) error {
params.SetAuthorizedParties(parties...)
params.AuthorizedPartyHandler = handler
return nil
}
}

// AuthorizedPartyMatches registers a handler that checks that the
// 'azp' claim's value is included in the provided parties.
func AuthorizedPartyMatches(parties ...string) func(string) bool {
authorizedParties := make(map[string]struct{})
for _, p := range parties {
authorizedParties[p] = struct{}{}
}

return func(azp string) bool {
if azp == "" || len(authorizedParties) == 0 {
return true
}
_, ok := authorizedParties[azp]
return ok
}
}

// CustomClaims allows to pass a type (e.g. struct), which will be populated with the token claims based on json tags.
// You must pass a pointer for this option to work.
func CustomClaims(claims any) AuthorizationOption {
Expand Down
33 changes: 33 additions & 0 deletions http/middleware_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,36 @@ func TestRequireHeaderAuthorization_InvalidAuthorization(t *testing.T) {
require.NoError(t, err)
require.Equal(t, http.StatusForbidden, res.StatusCode)
}

func TestAuthorizedPartyFunc(t *testing.T) {
t.Parallel()
for _, tc := range []struct {
azp string
parties []string
want bool
}{
{
azp: "clerk.com",
parties: []string{"clerk.com", "clerk.dev"},
want: true,
},
{
azp: "clerk.com",
parties: []string{"clerk.dev"},
want: false,
},
{
azp: "",
parties: []string{"clerk.com"},
want: true,
},
{
azp: "clerk.com",
parties: []string{},
want: true,
},
} {
fn := AuthorizedPartyMatches(tc.parties...)
require.Equal(t, tc.want, fn(tc.azp))
}
}
24 changes: 7 additions & 17 deletions jwt/jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"github.com/go-jose/go-jose/v3/jwt"
)

type AuthorizedPartyHandler func(string) bool

type VerifyParams struct {
// Token is the JWT that will be verified. Required.
Token string
Expand All @@ -26,19 +28,9 @@ type VerifyParams struct {
IsSatellite bool
// ProxyURL is the URL of the server that proxies the Clerk Frontend API.
ProxyURL *string
// List of values that should match the azp claim.
// Use SetAuthorizedParties to set the value.
authorizedParties map[string]struct{}
}

// SetAuthorizedParties accepts a list of authorized parties to be
// set on the params.
func (params *VerifyParams) SetAuthorizedParties(parties ...string) {
azp := make(map[string]struct{})
for _, p := range parties {
azp[p] = struct{}{}
}
params.authorizedParties = azp
// AuthorizedPartyHandler can be used to perform validations on the
// 'azp' claim.
AuthorizedPartyHandler AuthorizedPartyHandler
}

// Verify verifies a Clerk session JWT and returns the parsed
Expand Down Expand Up @@ -81,10 +73,8 @@ func Verify(ctx context.Context, params *VerifyParams) (*clerk.SessionClaims, er
return nil, fmt.Errorf("invalid issuer %s", iss)
}

if claims.AuthorizedParty != "" && len(params.authorizedParties) > 0 {
if _, ok := params.authorizedParties[claims.AuthorizedParty]; !ok {
return nil, fmt.Errorf("invalid authorized party %s", claims.AuthorizedParty)
}
if params.AuthorizedPartyHandler != nil && !params.AuthorizedPartyHandler(claims.AuthorizedParty) {
return nil, fmt.Errorf("invalid authorized party %s", claims.AuthorizedParty)
}

return claims, nil
Expand Down
Loading