Skip to content

Commit 97de52b

Browse files
authored
Merge pull request #7 from chrisw-dev/copilot/add-email-to-id-token-claims
Add email claim to ID token
2 parents e1f78f5 + 70dcf13 commit 97de52b

File tree

4 files changed

+34
-9
lines changed

4 files changed

+34
-9
lines changed

internal/handlers/token.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ func (h *TokenHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
8888
return
8989
}
9090

91-
idToken, err := generateIDToken(h.issuerURL, clientID)
91+
idToken, err := h.generateIDToken(h.issuerURL, clientID)
9292
if err != nil {
9393
log.Printf("Error generating ID token: %v", err)
9494
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
@@ -139,9 +139,21 @@ func generateRefreshToken(clientID string) string {
139139
}
140140

141141
// Helper function to generate a mock ID token
142-
func generateIDToken(issuerURL, clientID string) (string, error) {
142+
func (h *TokenHandler) generateIDToken(issuerURL, clientID string) (string, error) {
143143
// Generate a subject ID based on client ID
144144
sub := "user-" + clientID
145-
146-
return jwt.GenerateIDToken(issuerURL, clientID, sub)
145+
146+
// Check if there's a configured email in the token config
147+
var email string
148+
tokenConfig := h.store.GetTokenConfig()
149+
if tokenConfig != nil {
150+
if userInfoConfig, ok := tokenConfig["user_info"].(map[string]interface{}); ok {
151+
if configuredEmail, ok := userInfoConfig["email"].(string); ok {
152+
email = configuredEmail
153+
}
154+
}
155+
}
156+
157+
// If no email is configured, pass empty string (don't default to generated email)
158+
return jwt.GenerateIDToken(issuerURL, clientID, sub, email)
147159
}

internal/jwt/jwt.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func InitKeys() error {
3737
}
3838

3939
// GenerateIDToken creates a signed JWT ID token
40-
func GenerateIDToken(issuer, clientID, sub string) (string, error) {
40+
func GenerateIDToken(issuer, clientID, sub, email string) (string, error) {
4141
if privateKey == nil {
4242
if err := InitKeys(); err != nil {
4343
return "", err
@@ -53,6 +53,11 @@ func GenerateIDToken(issuer, clientID, sub string) (string, error) {
5353
"iat": now.Unix(),
5454
"nonce": generateNonce(),
5555
}
56+
57+
// Only include email claim if an email is provided
58+
if email != "" {
59+
claims["email"] = email
60+
}
5661

5762
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
5863
token.Header["kid"] = keyID

internal/jwt/jwt_test.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ func TestGenerateIDToken(t *testing.T) {
3434
issuer := "http://localhost:8080"
3535
clientID := "test-client"
3636
sub := "user-123"
37+
email := "[email protected]"
3738

38-
tokenString, err := GenerateIDToken(issuer, clientID, sub)
39+
tokenString, err := GenerateIDToken(issuer, clientID, sub, email)
3940
if err != nil {
4041
t.Fatalf("Failed to generate ID token: %v", err)
4142
}
@@ -62,6 +63,10 @@ func TestGenerateIDToken(t *testing.T) {
6263
if claims["aud"] != clientID {
6364
t.Errorf("Expected audience %s, got %v", clientID, claims["aud"])
6465
}
66+
67+
if claims["email"] != email {
68+
t.Errorf("Expected email %s, got %v", email, claims["email"])
69+
}
6570
}
6671

6772
func TestGenerateAccessToken(t *testing.T) {
@@ -153,8 +158,9 @@ func TestVerifyToken(t *testing.T) {
153158
issuer := "http://localhost:8080"
154159
clientID := "test-client"
155160
sub := "user-123"
161+
email := "[email protected]"
156162

157-
tokenString, err := GenerateIDToken(issuer, clientID, sub)
163+
tokenString, err := GenerateIDToken(issuer, clientID, sub, email)
158164
if err != nil {
159165
t.Fatalf("Failed to generate ID token: %v", err)
160166
}
@@ -186,8 +192,9 @@ func TestTokenFormat(t *testing.T) {
186192
issuer := "http://localhost:8080"
187193
clientID := "test-client"
188194
sub := "user-123"
195+
email := "[email protected]"
189196

190-
tokenString, err := GenerateIDToken(issuer, clientID, sub)
197+
tokenString, err := GenerateIDToken(issuer, clientID, sub, email)
191198
if err != nil {
192199
t.Fatalf("Failed to generate ID token: %v", err)
193200
}

pkg/oauth/google.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,15 @@ func (p *GoogleProvider) ExchangeCodeForToken(code string) (map[string]interface
5050

5151
// Generate proper JWT tokens
5252
sub := "user-" + authRequest.ClientID
53+
email := authRequest.ClientID + "@example.com"
5354
scopes := []string{"openid", "email", "profile"}
5455

5556
accessToken, err := jwt.GenerateAccessToken(p.IssuerURL, authRequest.ClientID, sub, scopes)
5657
if err != nil {
5758
return nil, &Error{Code: "server_error", Description: "Failed to generate access token"}
5859
}
5960

60-
idToken, err := jwt.GenerateIDToken(p.IssuerURL, authRequest.ClientID, sub)
61+
idToken, err := jwt.GenerateIDToken(p.IssuerURL, authRequest.ClientID, sub, email)
6162
if err != nil {
6263
return nil, &Error{Code: "server_error", Description: "Failed to generate ID token"}
6364
}

0 commit comments

Comments
 (0)