Skip to content

Commit b3a0ca9

Browse files
committed
fix(cli): prefer user/api audience for mixed-aud JWTs
1 parent c968cba commit b3a0ca9

2 files changed

Lines changed: 36 additions & 6 deletions

File tree

app/cli/internal/token/token.go

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,20 @@ const (
3838
federatedTokenAudience = "chainloop"
3939
)
4040

41+
func chooseAudience(audiences []string) string {
42+
// Priority matters for mixed-audience tokens: user/api token identity
43+
// should win over generic federated audience.
44+
for _, candidate := range []string{apiTokenAudience, userAudience, federatedTokenAudience} {
45+
for _, aud := range audiences {
46+
if aud == candidate {
47+
return candidate
48+
}
49+
}
50+
}
51+
52+
return ""
53+
}
54+
4155
// Parse the token and return the type of token. At the moment in Chainloop we have 3 types of tokens:
4256
// 1. User account token
4357
// 2. API token
@@ -65,20 +79,28 @@ func Parse(token string) (*ParsedToken, error) {
6579
return nil, nil
6680
}
6781

68-
// Supports both string and array formats per JWT RFC 7519
69-
// Takes first array element when multiple audiences exist
70-
var audience string
82+
// Supports both string and array formats per JWT RFC 7519.
83+
// For multi-audience tokens, prefer the most specific Chainloop auth audience
84+
// instead of taking the first element (order can vary by issuer/runtime).
85+
var audiences []string
7186
switch aud := claims["aud"].(type) {
7287
case string:
73-
audience = aud
88+
audiences = []string{aud}
7489
case []interface{}:
75-
if len(aud) > 0 {
76-
audience, _ = aud[0].(string)
90+
for _, a := range aud {
91+
if s, ok := a.(string); ok && s != "" {
92+
audiences = append(audiences, s)
93+
}
7794
}
7895
default:
7996
return nil, nil
8097
}
8198

99+
if len(audiences) == 0 {
100+
return nil, nil
101+
}
102+
103+
audience := chooseAudience(audiences)
82104
if audience == "" {
83105
return nil, nil
84106
}

app/cli/internal/token/token_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,14 @@ func TestParse(t *testing.T) {
5353
TokenType: v1.Attestation_Auth_AUTH_TYPE_FEDERATED,
5454
},
5555
},
56+
{
57+
name: "user token with mixed audiences prefers user audience",
58+
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiYmMwYjIxOTktY2E4NS00MmFiLWE4NTctMDQyZTljMTA5ZDQzIiwiaXNzIjoiY3AuY2hhaW5sb29wIiwiYXVkIjpbImNoYWlubG9vcCIsInVzZXItYXV0aC5jaGFpbmxvb3AiXSwiZXhwIjoxNzE1OTM1MjUwfQ.signature",
59+
want: &ParsedToken{
60+
ID: "bc0b2199-ca85-42ab-a857-042e9c109d43",
61+
TokenType: v1.Attestation_Auth_AUTH_TYPE_USER,
62+
},
63+
},
5664
{
5765
name: "federated github token",
5866
token: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3Rva2VuLmFjdGlvbnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tIiwiYXVkIjoiY2hhaW5sb29wIiwicmVwb3NpdG9yeSI6Im1hdGlhc2luc2F1cnJhbGRlL3Byb2plY3QiLCJzdWIiOiJyZXBvOm1hdGlhc2luc2F1cnJhbGRlL3Byb2plY3Q6cmVmOnJlZnMvaGVhZHMvbWFpbiJ9.signature",

0 commit comments

Comments
 (0)