Merged in feature/support-empty-email-jwt (pull request #209)

handle missing email in jwt

* handle missing email
This commit is contained in:
Jay Brown
2026-02-13 01:38:32 +00:00
parent d7f6c3700b
commit 58912a66d4
2 changed files with 42 additions and 14 deletions
+33 -10
View File
@@ -244,23 +244,46 @@ func TestAgreeToEula(t *testing.T) {
assert.Equal(t, http.StatusUnauthorized, rec.Code)
})
t.Run("succeeds with username fallback when email claim is missing", func(t *testing.T) {
// Simulate a Cognito access token that has 'sub' and 'cognito:username'
// but no 'email' claim. This is the default for Cognito access tokens.
t.Run("succeeds with username fallback when email is missing (access token)", func(t *testing.T) {
// Simulate a real Cognito access token: has 'sub' and 'username' (not
// 'cognito:username') and no 'email'. This is the default for access tokens.
userSubject := "no-email-user-" + uuid.New().String()[:8]
ctx, rec := setupEulaTestContext(http.MethodPost, "/eula/agree", nil)
ctx.Request().RemoteAddr = "192.168.1.100:12345"
// Set claims with sub but without email (mimics access token)
ctx.Set("user_claims", map[string]interface{}{
// Mimic what the middleware produces from a real access token:
// ExtractUserInfo sees "username" (not "cognito:username") and no "email".
claims := map[string]interface{}{
"sub": userSubject,
"cognito:username": "testuser",
})
ctx.Set("user_info", cognitoauth.UserInfo{
Username: "testuser",
Email: "", // empty - no email in access token
"username": "accessuser",
"token_use": "access",
}
ctx.Set("user_claims", claims)
ctx.Set("user_info", cognitoauth.ExtractUserInfo(claims))
err := cons.AgreeToEula(ctx)
require.NoError(t, err)
assert.Equal(t, http.StatusCreated, rec.Code)
var response queryapi.EulaAgreementResponse
err = json.Unmarshal(rec.Body.Bytes(), &response)
require.NoError(t, err)
assert.Equal(t, versionStr, response.EulaVersion)
})
t.Run("succeeds with subject ID fallback when email and username are both missing", func(t *testing.T) {
// Edge case: token has sub but neither email nor any username claim.
userSubject := "bare-token-user-" + uuid.New().String()[:8]
ctx, rec := setupEulaTestContext(http.MethodPost, "/eula/agree", nil)
ctx.Request().RemoteAddr = "192.168.1.100:12345"
claims := map[string]interface{}{
"sub": userSubject,
"token_use": "access",
}
ctx.Set("user_claims", claims)
ctx.Set("user_info", cognitoauth.ExtractUserInfo(claims))
err := cons.AgreeToEula(ctx)
require.NoError(t, err)
assert.Equal(t, http.StatusCreated, rec.Code)
+7 -2
View File
@@ -135,14 +135,19 @@ func (s *Controllers) AgreeToEula(ctx echo.Context) error {
// Resolve the user identifier for the agreement record.
// Cognito access tokens do not include the email claim by default (only ID tokens do).
// Fall back to the username (cognito:username), which is always present in access tokens.
// Fall back to username, then to subject ID (always present in any Cognito token).
userIdentifier := userInfo.Email
if userIdentifier == "" {
userIdentifier = userInfo.Username
s.cfg.GetAuthLogger().Info("AgreeToEula: email claim missing from token, using username as fallback",
s.cfg.GetAuthLogger().Info("AgreeToEula: email missing from token, using username fallback",
"user_subject", userSubject,
"username", userInfo.Username)
}
if userIdentifier == "" {
userIdentifier = userSubject
s.cfg.GetAuthLogger().Info("AgreeToEula: email and username missing from token, using subject ID fallback",
"user_subject", userSubject)
}
// Get current EULA version
currentVersion, err := s.svc.Eula.GetCurrentVersion(ctx.Request().Context())