Skip to content

Commit

Permalink
tests: verify expected claims are present
Browse files Browse the repository at this point in the history
  • Loading branch information
staaldraad committed Jan 20, 2025
1 parent e067caa commit 1126963
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 7 deletions.
6 changes: 3 additions & 3 deletions internal/api/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ type AccessTokenClaims struct {
AuthenticatorAssuranceLevel string `json:"aal,omitempty"`
AuthenticationMethodReference []models.AMREntry `json:"amr,omitempty"`
SessionId string `json:"session_id,omitempty"`
IsAnonymous bool `json:"is_anonymous"`
IsAnonymous bool `json:"is_anonymous,omitempty"`
}

// AccessTokenResponse represents an OAuth2 success response
Expand Down Expand Up @@ -339,8 +339,8 @@ func (a *API) generateAccessToken(r *http.Request, tx *storage.Connection, user
}

// add additional claims that are optional
for _, rc := range config.JWT.AdditionalClaims {
switch rc {
for _, ac := range config.JWT.AdditionalClaims {
switch ac {
case "email":
claims.Email = user.GetEmail()
case "phone":
Expand Down
64 changes: 64 additions & 0 deletions internal/api/token_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -855,3 +855,67 @@ $$;`
})
}
}

func (ts *TokenTestSuite) TestConfigureAccessToken() {
type customAccessTokenTestcase struct {
desc string
additionalClaimsConfig []string
expectedClaims []string
}
requiredClaims := []string{"aud", "exp", "iat", "sub", "role", "aal", "session_id", "user_metadata"}
cases := []customAccessTokenTestcase{

{
desc: "Default claims all present",
additionalClaimsConfig: []string{"empty"},
expectedClaims: requiredClaims,
}, {
desc: "Minimal set of claims is returned",
additionalClaimsConfig: []string{},
expectedClaims: requiredClaims,
},
{
desc: "Selected additional claims are returned",
additionalClaimsConfig: []string{"email"},
expectedClaims: append(requiredClaims, []string{"email"}...),
},
}
for _, c := range cases {
ts.T().Run(c.desc, func(t *testing.T) {
ts.Config.JWT.AdditionalClaims = c.additionalClaimsConfig

var buffer bytes.Buffer
require.NoError(t, json.NewEncoder(&buffer).Encode(map[string]interface{}{
"refresh_token": ts.RefreshToken.Token,
}))

req := httptest.NewRequest(http.MethodPost, "http://localhost/token?grant_type=refresh_token", &buffer)
req.Header.Set("Content-Type", "application/json")

w := httptest.NewRecorder()
ts.API.handler.ServeHTTP(w, req)

var tokenResponse struct {
AccessToken string `json:"access_token"`
}
require.NoError(t, json.NewDecoder(w.Result().Body).Decode(&tokenResponse))
parts := strings.Split(tokenResponse.AccessToken, ".")
require.Equal(t, 3, len(parts), "Token should have 3 parts")

payload, err := base64.RawURLEncoding.DecodeString(parts[1])
require.NoError(t, err)

var responseClaims map[string]interface{}
require.NoError(t, json.Unmarshal(payload, &responseClaims))

assert.Len(t, responseClaims, len(c.expectedClaims), "More or less claims in the response than expected")
for _, expectedClaim := range c.expectedClaims {
_, exists := responseClaims[expectedClaim]
assert.True(t, exists, "Claim should exist {%s}", expectedClaim)
}

// reset
ts.Config.JWT.AdditionalClaims = []string{"email", "phone", "app_metadata", "user_metadata", "amr", "is_anonymous"}
})
}
}
8 changes: 4 additions & 4 deletions internal/hooks/auth_hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,15 @@ const MinimumViableTokenSchema = `{
// AccessTokenClaims is a struct thats used for JWT claims
type AccessTokenClaims struct {
jwt.RegisteredClaims
Email string `json:"email"`
Phone string `json:"phone"`
AppMetaData map[string]interface{} `json:"app_metadata"`
Email string `json:"email,omitempty"`
Phone string `json:"phone,omitempty"`
AppMetaData map[string]interface{} `json:"app_metadata,omitempty"`
UserMetaData map[string]interface{} `json:"user_metadata"`
Role string `json:"role"`
AuthenticatorAssuranceLevel string `json:"aal,omitempty"`
AuthenticationMethodReference []models.AMREntry `json:"amr,omitempty"`
SessionId string `json:"session_id,omitempty"`
IsAnonymous bool `json:"is_anonymous"`
IsAnonymous bool `json:"is_anonymous,omitempty"`
}

type MFAVerificationAttemptInput struct {
Expand Down

0 comments on commit 1126963

Please sign in to comment.