Skip to content

Commit 1365aaa

Browse files
authored
feat: Add custom claims from Keycloak user token (#1917)
## What kind of change does this PR introduce? This change will populate the `CustomClaims` field from the `Claims` struct with 'other' claims from the Keycloak user token. ## What is the current behavior? Currently only `Name`, `Sub`, `Email`, and `EmailVerified` are taken from the Keycloak user token. ## What is the new behavior? The "custom_claims" field in the retrieved JWT is populated. ## Additional context * https://github.com/orgs/supabase/discussions/18909
1 parent 11d76aa commit 1365aaa

File tree

1 file changed

+40
-4
lines changed

1 file changed

+40
-4
lines changed

internal/api/provider/keycloak.go

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package provider
22

33
import (
44
"context"
5+
"encoding/json"
56
"errors"
67
"strings"
78

@@ -16,10 +17,33 @@ type keycloakProvider struct {
1617
}
1718

1819
type keycloakUser struct {
19-
Name string `json:"name"`
20-
Sub string `json:"sub"`
21-
Email string `json:"email"`
22-
EmailVerified bool `json:"email_verified"`
20+
Name string `json:"name"`
21+
Sub string `json:"sub"`
22+
Email string `json:"email"`
23+
EmailVerified bool `json:"email_verified"`
24+
RawClaims map[string]interface{} `json:"-"`
25+
}
26+
27+
func (u *keycloakUser) UnmarshalJSON(data []byte) error {
28+
if err := json.Unmarshal(data, &u.RawClaims); err != nil {
29+
return err
30+
}
31+
32+
// Extract known fields
33+
if v, ok := u.RawClaims["name"].(string); ok {
34+
u.Name = v
35+
}
36+
if v, ok := u.RawClaims["sub"].(string); ok {
37+
u.Sub = v
38+
}
39+
if v, ok := u.RawClaims["email"].(string); ok {
40+
u.Email = v
41+
}
42+
if v, ok := u.RawClaims["email_verified"].(bool); ok {
43+
u.EmailVerified = v
44+
}
45+
46+
return nil
2347
}
2448

2549
// NewKeycloakProvider creates a Keycloak account provider.
@@ -72,6 +96,17 @@ func (g keycloakProvider) GetUserData(ctx context.Context, tok *oauth2.Token) (*
7296
return nil, err
7397
}
7498

99+
customClaims := make(map[string]interface{})
100+
standardClaims := map[string]bool{
101+
"name": true, "sub": true, "email": true, "email_verified": true,
102+
}
103+
104+
for k, v := range u.RawClaims {
105+
if !standardClaims[k] {
106+
customClaims[k] = v
107+
}
108+
}
109+
75110
data := &UserProvidedData{}
76111
if u.Email != "" {
77112
data.Emails = []Email{{
@@ -87,6 +122,7 @@ func (g keycloakProvider) GetUserData(ctx context.Context, tok *oauth2.Token) (*
87122
Name: u.Name,
88123
Email: u.Email,
89124
EmailVerified: u.EmailVerified,
125+
CustomClaims: customClaims,
90126

91127
// To be deprecated
92128
FullName: u.Name,

0 commit comments

Comments
 (0)