Skip to content

Commit 71c84a8

Browse files
fix: jfrog oauth username extraction from oauth jwt token (#539)
## Description Add username extraction from jfrog JWT OAuth token with fallback to coder username. <!-- Briefly describe what this PR does and why --> ## Type of Change - [ ] New module - [ ] New template - [X] Bug fix - [ ] Feature/enhancement - [ ] Documentation - [ ] Other ## Module Information <!-- Delete this section if not applicable --> **Path:** `registry/coder/modules/jfrog-oauth` **New version:** `v1.2.2` **Breaking change:** [ ] Yes [X] No ## Template Information <!-- Delete this section if not applicable --> **Path:** `registry/[namespace]/templates/[template-name]` ## Testing & Validation - [X] Tests pass (`bun test`) - [X] Code formatted (`bun fmt`) - [X] Changes tested locally ## Related Issues <!-- Link related issues or write "None" if not applicable -->
1 parent e11ed2d commit 71c84a8

File tree

2 files changed

+33
-5
lines changed

2 files changed

+33
-5
lines changed

registry/coder/modules/jfrog-oauth/README.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Install the JF CLI and authenticate package managers with Artifactory using OAut
1616
module "jfrog" {
1717
count = data.coder_workspace.me.start_count
1818
source = "registry.coder.com/coder/jfrog-oauth/coder"
19-
version = "1.2.1"
19+
version = "1.2.2"
2020
agent_id = coder_agent.example.id
2121
jfrog_url = "https://example.jfrog.io"
2222
username_field = "username" # If you are using GitHub to login to both Coder and Artifactory, use username_field = "username"
@@ -39,6 +39,15 @@ module "jfrog" {
3939

4040
This module is usable by JFrog self-hosted (on-premises) Artifactory as it requires configuring a custom integration. This integration benefits from Coder's [external-auth](https://coder.com/docs/v2/latest/admin/external-auth) feature and allows each user to authenticate with Artifactory using an OAuth flow and issues user-scoped tokens to each user. For configuration instructions, see this [guide](https://coder.com/docs/v2/latest/guides/artifactory-integration#jfrog-oauth) on the Coder documentation.
4141

42+
## Username Handling
43+
44+
The module automatically extracts your JFrog username directly from the OAuth token's JWT payload. This preserves special characters like dots (`.`), hyphens (`-`), and accented characters that Coder normalizes in usernames.
45+
46+
**Priority order:**
47+
48+
1. **JWT extraction** (default) - Extracts username from OAuth token, preserving special characters
49+
2. **Fallback to `username_field`** - If JWT extraction fails, uses Coder username or email
50+
4251
## Examples
4352

4453
Configure the Python pip package manager to fetch packages from Artifactory while mapping the Coder email to the Artifactory username.
@@ -47,7 +56,7 @@ Configure the Python pip package manager to fetch packages from Artifactory whil
4756
module "jfrog" {
4857
count = data.coder_workspace.me.start_count
4958
source = "registry.coder.com/coder/jfrog-oauth/coder"
50-
version = "1.2.1"
59+
version = "1.2.2"
5160
agent_id = coder_agent.example.id
5261
jfrog_url = "https://example.jfrog.io"
5362
username_field = "email"
@@ -76,7 +85,7 @@ The [JFrog extension](https://open-vsx.org/extension/JFrog/jfrog-vscode-extensio
7685
module "jfrog" {
7786
count = data.coder_workspace.me.start_count
7887
source = "registry.coder.com/coder/jfrog-oauth/coder"
79-
version = "1.2.1"
88+
version = "1.2.2"
8089
agent_id = coder_agent.example.id
8190
jfrog_url = "https://example.jfrog.io"
8291
username_field = "username" # If you are using GitHub to login to both Coder and Artifactory, use username_field = "username"

registry/coder/modules/jfrog-oauth/main.tf

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,27 @@ variable "package_managers" {
7676
}
7777

7878
locals {
79-
# The username field to use for artifactory
80-
username = var.username_field == "email" ? data.coder_workspace_owner.me.email : data.coder_workspace_owner.me.name
79+
jwt_parts = try(split(".", data.coder_external_auth.jfrog.access_token), [])
80+
jwt_payload = try(local.jwt_parts[1], "")
81+
payload_padding = local.jwt_payload == "" ? "" : (
82+
length(local.jwt_payload) % 4 == 0 ? "" :
83+
length(local.jwt_payload) % 4 == 2 ? "==" :
84+
length(local.jwt_payload) % 4 == 3 ? "=" :
85+
""
86+
)
87+
88+
jwt_username = try(
89+
regex(
90+
"/users/([^/]+)",
91+
jsondecode(base64decode("${local.jwt_payload}${local.payload_padding}"))["sub"]
92+
)[0],
93+
""
94+
)
95+
96+
username = coalesce(
97+
local.jwt_username != "" ? local.jwt_username : null,
98+
var.username_field == "email" ? data.coder_workspace_owner.me.email : data.coder_workspace_owner.me.name
99+
)
81100
jfrog_host = split("://", var.jfrog_url)[1]
82101
common_values = {
83102
JFROG_URL = var.jfrog_url

0 commit comments

Comments
 (0)