Skip to content

Add org uuid to the trace publishing token#756

Open
menakaj wants to merge 1 commit intowso2:mainfrom
menakaj:main
Open

Add org uuid to the trace publishing token#756
menakaj wants to merge 1 commit intowso2:mainfrom
menakaj:main

Conversation

@menakaj
Copy link
Copy Markdown
Contributor

@menakaj menakaj commented Apr 27, 2026

Purpose

Describe the problems, issues, or needs driving this feature/fix and include links to related issues in the following format: Resolves issue1, issue2, etc.

Goals

Describe the solutions that this feature/fix will introduce to resolve the problems described above

Approach

Describe how you are implementing the solutions. Include an animated GIF or screenshot if the change affects the UI (email documentation@wso2.com to review all UI text). Include a link to a Markdown file or Google doc if the feature write-up is too long to paste here.

User stories

Summary of user stories addressed by this change>

Release note

Brief description of the new feature or bug fix as it will appear in the release notes

Documentation

Link(s) to product documentation that addresses the changes of this PR. If no doc impact, enter �N/A� plus brief explanation of why there�s no doc impact

Training

Link to the PR for changes to the training content in https://github.com/wso2/WSO2-Training, if applicable

Certification

Type �Sent� when you have provided new/updated certification questions, plus four answers for each question (correct answer highlighted in bold), based on this change. Certification questions/answers should be sent to certification@wso2.com and NOT pasted in this PR. If there is no impact on certification exams, type �N/A� and explain why.

Marketing

Link to drafts of marketing content that will describe and promote this feature, including product page changes, technical articles, blog posts, videos, etc., if applicable

Automation tests

  • Unit tests

    Code coverage information

  • Integration tests

    Details about the test cases and coverage

Security checks

Samples

Provide high-level details about the samples related to this feature

Related PRs

List any other related PRs

Migrations (if applicable)

Describe migration steps and platforms on which migration has been tested

Test environment

List all JDK versions, operating systems, databases, and browser/versions on which this feature/fix was tested

Learning

Describe the research phase and any blog posts, patterns, libraries, or add-ons you used to solve the problem.

Summary by CodeRabbit

  • New Features

    • Token generation now includes organization identity information in generated tokens.
    • Added validation requiring organization context for token requests; requests without valid organization context are rejected.
  • Tests

    • Token generation tests updated to verify organization identity claims are properly included.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 27, 2026

📝 Walkthrough

Walkthrough

The changes extend JWT token generation with organization identity. The agent token controller and services now extract the OuId from JWT claims, validate its presence, and include it as OrgId in downstream token generation requests. The token manager populates this value into generated JWT claims.

Changes

Cohort / File(s) Summary
Token Generation Validation
agent-manager-service/controllers/agent_token_controller.go, agent-manager-service/services/agent_manager.go
Extract OuId from JWT claims, validate presence, and reject with 403 Forbidden if missing. Populate OrgId in GenerateTokenRequest.
Token Claims Structure
agent-manager-service/services/agent_token_manager.go
Add OrgId field to GenerateTokenRequest and AgentTokenClaims (with JSON tag org_id). Populate the claim during token signing.
Test Infrastructure
agent-manager-service/middleware/jwtassertion/test_utils.go, agent-manager-service/tests/agent_token_test.go
Update mock JWT middleware to include OuId and OuHandle claims. Extend token generation test to validate org_id claim presence and equality.
Frontend Auth Stub
console/workspaces/libs/auth/src/no-auth/hooks/authHooks.ts
Replace hard-coded JWT in getToken stub with new token containing ouId claim.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A token now carries its org with pride,
With claims from JWT claims verified—
OuId flows through, no more denied,
From claims to requests, organization's guide!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is entirely a template with no actual content filled in—all sections remain as template placeholders without substance. Fill in all required sections with actual details: Purpose/issue links, Goals, Approach, User stories, Release notes, Documentation, Testing, Security checks, and any other applicable sections.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title directly aligns with the primary change: adding organization UUID (OuId/OrgId) to generated agent tokens for trace publishing.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
console/workspaces/libs/auth/src/no-auth/hooks/authHooks.ts (1)

22-31: ⚠️ Potential issue | 🟡 Minor

Inconsistent sub claim between demoUserInfo and JWT payload.

The demoUserInfo object declares sub: 'default' (line 29), but the JWT token's payload contains "sub": "8f307351-25c5-4fc6-85e0-f51c2d458f06". Since the real Asgardio implementation spreads tokenInfo?.payload into the userInfo object, this mismatch could cause unpredictable behavior when code decodes the token versus using userInfo directly.

🔧 Align the JWT payload with demoUserInfo

Update the JWT payload to use "sub": "default" to match line 29, or update demoUserInfo.sub to match the JWT. For consistency, the stub token payload should mirror the stub userInfo.

Also applies to: 42-42

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@console/workspaces/libs/auth/src/no-auth/hooks/authHooks.ts` around lines 22
- 31, demoUserInfo.sub ('default') is inconsistent with the stub JWT payload's
"sub" (GUID); update one to match the other so tokenInfo?.payload spread
produces identical sub values—either change demoUserInfo.sub to
"8f307351-25c5-4fc6-85e0-f51c2d458f06" or change the JWT payload's "sub" to
"default" (also apply the same change to the other stub payload instance
referenced around the second occurrence).
agent-manager-service/middleware/jwtassertion/test_utils.go (1)

32-39: ⚠️ Potential issue | 🔴 Critical

Mock OuId value diverges from the test assertion.

The mock seeds OuId: "mock-org-id", but agent-manager-service/tests/agent_token_test.go (line 149) asserts the generated JWT claim equals "mock-ou-id". Whichever side is intended to be authoritative, these two literals must agree, otherwise TestGenerateAgentToken/Generating a token for an external agent should return 200 with valid token will fail. See the corresponding comment on agent_token_test.go for the related JSON-tag mismatch (org_id vs ou_id) that needs to be resolved at the same time.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@agent-manager-service/middleware/jwtassertion/test_utils.go` around lines 32
- 39, The mock TokenClaims in test_utils.go sets OuId to "mock-org-id" which
conflicts with the test assertion expecting "mock-ou-id" in
TestGenerateAgentToken; update the mock TokenClaims.OuId value to exactly match
the expected literal ("mock-ou-id") or update the test assertion to match the
mock, and at the same time reconcile the JSON tag mismatch between the struct
field and test expectation (ensure the claim field name used by
TokenClaims/RegisteredClaims serialization matches the test's expected key:
"ou_id" vs "org_id"). Locate and fix the TokenClaims.OuId value and the JSON tag
on the TokenClaims struct so the generated JWT claim and the test assertion are
consistent.
🧹 Nitpick comments (2)
console/workspaces/libs/auth/src/no-auth/hooks/authHooks.ts (1)

42-42: JWT payload missing expected user claims.

The JWT payload only contains standard claims (iss, iat, exp, aud, sub) and the new ouId field, but is missing several claims present in demoUserInfo (lines 22-31): username, displayName, orgHandle, orgId, orgName, sessionState, and allowedScopes.

Since the real Asgardio implementation spreads the decoded JWT payload into the UserInfo object, the stub token should contain equivalent claims to ensure consistent behavior when code decodes and uses the token versus directly accessing userInfo.

💡 Populate JWT payload with demoUserInfo fields

Consider regenerating the JWT with a payload that includes all relevant fields from demoUserInfo:

{
  "iss": "Agent Management Platform Local",
  "iat": 1761727469,
  "exp": 1793263469,
  "aud": "localhost",
  "sub": "default",
  "username": "john.doe",
  "displayName": "John Doe",
  "orgHandle": "default",
  "orgId": "default",
  "orgName": "Default",
  "ouId": "faa183f1-3983-4f63-bb35-86fa723fd5ef"
}

This ensures that decoding the stub token yields the same user information as the demoUserInfo object.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@console/workspaces/libs/auth/src/no-auth/hooks/authHooks.ts` at line 42, The
JWT returned by getToken() is missing user claims present in demoUserInfo
(username, displayName, orgHandle, orgId, orgName, sessionState, allowedScopes),
causing mismatch when code decodes the token vs using userInfo; regenerate or
replace the hardcoded token in getToken to a JWT whose payload includes those
demoUserInfo fields (matching names: username, displayName, orgHandle, orgId,
orgName, sessionState, allowedScopes, plus existing ouId/iss/aud/sub/iat/exp) so
decoded token and demoUserInfo are equivalent; update the token string in
getToken to the new JWT.
agent-manager-service/services/agent_token_manager.go (1)

244-300: Consider validating req.OrgId at the service boundary.

Both current call sites (controllers/agent_token_controller.go and services/agent_manager.go) validate that OrgId is non-empty before reaching here, so this is defensive only. However, the service is a public API and a future caller could pass req.OrgId == "", which would silently produce a token with "org_id": "". A short guard would localize the invariant and prevent that drift.

🛡️ Proposed defensive check
 func (s *agentTokenManagerService) GenerateToken(ctx context.Context, req GenerateTokenRequest) (*spec.TokenResponse, error) {
 	s.logger.Info("Generating token for agent",
 		"agentName", req.AgentName,
 		"orgName", req.OrgName,
 		"projectName", req.ProjectName,
 	)
+
+	if req.OrgId == "" {
+		return nil, fmt.Errorf("OrgId is required: %w", utils.ErrInvalidInput)
+	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@agent-manager-service/services/agent_token_manager.go` around lines 244 -
300, Add a defensive guard at the start of
agentTokenManagerService.GenerateToken to reject empty OrgId: check if req.OrgId
== "" (before calling s.ocClient.GetComponent) and if so log an error and return
an invalid-input error (e.g., combine utils.ErrInvalidInput with a descriptive
error like "org id is required") so the service never issues a token with an
empty OrgId.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@agent-manager-service/services/agent_manager.go`:
- Around line 433-438: The code in generateAgentAPIKey checks
jwtassertion.GetTokenClaims(ctx) but when callerClaims is nil or
callerClaims.OuId == "" it logs and returns "", translatePipelineError(err)
which uses a nil err and thus returns nil; change this to return a meaningful
sentinel error (e.g., utils.ErrMissingOrgIdentity or utils.ErrForbidden) instead
of translatePipelineError, so callers get a non-nil error and upstream can map
to 403; update the return in the failing branch to return "",
utils.ErrMissingOrgIdentity (or your project’s equivalent) and keep the existing
log statement to preserve diagnostics.

In `@agent-manager-service/tests/agent_token_test.go`:
- Around line 141-149: The test is asserting the wrong claim key and value;
update the assertions in agent_token_test.go to match the implementation: check
for "org_id" (not "ou_id") and expect the value "mock-org-id" for the org claim
— this aligns with AgentTokenClaims.OrgId (json:"org_id") in
agent-manager-service/services/agent_token_manager.go and the mock setting
TokenClaims.OuId = "mock-org-id" in
agent-manager-service/middleware/jwtassertion/test_utils.go; change
require.Contains(t, claims, "ou_id") → require.Contains(t, claims, "org_id") and
require.Equal(t, "mock-ou-id", claims["ou_id"]) → require.Equal(t,
"mock-org-id", claims["org_id"]).

---

Outside diff comments:
In `@agent-manager-service/middleware/jwtassertion/test_utils.go`:
- Around line 32-39: The mock TokenClaims in test_utils.go sets OuId to
"mock-org-id" which conflicts with the test assertion expecting "mock-ou-id" in
TestGenerateAgentToken; update the mock TokenClaims.OuId value to exactly match
the expected literal ("mock-ou-id") or update the test assertion to match the
mock, and at the same time reconcile the JSON tag mismatch between the struct
field and test expectation (ensure the claim field name used by
TokenClaims/RegisteredClaims serialization matches the test's expected key:
"ou_id" vs "org_id"). Locate and fix the TokenClaims.OuId value and the JSON tag
on the TokenClaims struct so the generated JWT claim and the test assertion are
consistent.

In `@console/workspaces/libs/auth/src/no-auth/hooks/authHooks.ts`:
- Around line 22-31: demoUserInfo.sub ('default') is inconsistent with the stub
JWT payload's "sub" (GUID); update one to match the other so tokenInfo?.payload
spread produces identical sub values—either change demoUserInfo.sub to
"8f307351-25c5-4fc6-85e0-f51c2d458f06" or change the JWT payload's "sub" to
"default" (also apply the same change to the other stub payload instance
referenced around the second occurrence).

---

Nitpick comments:
In `@agent-manager-service/services/agent_token_manager.go`:
- Around line 244-300: Add a defensive guard at the start of
agentTokenManagerService.GenerateToken to reject empty OrgId: check if req.OrgId
== "" (before calling s.ocClient.GetComponent) and if so log an error and return
an invalid-input error (e.g., combine utils.ErrInvalidInput with a descriptive
error like "org id is required") so the service never issues a token with an
empty OrgId.

In `@console/workspaces/libs/auth/src/no-auth/hooks/authHooks.ts`:
- Line 42: The JWT returned by getToken() is missing user claims present in
demoUserInfo (username, displayName, orgHandle, orgId, orgName, sessionState,
allowedScopes), causing mismatch when code decodes the token vs using userInfo;
regenerate or replace the hardcoded token in getToken to a JWT whose payload
includes those demoUserInfo fields (matching names: username, displayName,
orgHandle, orgId, orgName, sessionState, allowedScopes, plus existing
ouId/iss/aud/sub/iat/exp) so decoded token and demoUserInfo are equivalent;
update the token string in getToken to the new JWT.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 61275ac8-a18d-4faa-9e2b-26c95307e541

📥 Commits

Reviewing files that changed from the base of the PR and between abc5b15 and 0889741.

📒 Files selected for processing (6)
  • agent-manager-service/controllers/agent_token_controller.go
  • agent-manager-service/middleware/jwtassertion/test_utils.go
  • agent-manager-service/services/agent_manager.go
  • agent-manager-service/services/agent_token_manager.go
  • agent-manager-service/tests/agent_token_test.go
  • console/workspaces/libs/auth/src/no-auth/hooks/authHooks.ts

Comment on lines +433 to +438
// Extract OrgId from the caller's JWT claims
callerClaims := jwtassertion.GetTokenClaims(ctx)
if callerClaims == nil || callerClaims.OuId == "" {
s.logger.Error("GenerateToken: missing organization identity in caller token")
return "", translatePipelineError(err)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: returns ("", nil) when JWT claims are missing.

At Line 437, err is guaranteed to be nil here (the only assignment to err in scope is the pipeline fetch above, whose error path already returned). translatePipelineError(nil) returns nil, so when the caller's JWT claims are missing or lack OuId, this function silently returns an empty token string with no error. Every caller of generateAgentAPIKey (e.g., buildCreateTraitRequests, attachOTELInstrumentationTrait, attachEnvInjectionTrait, generateTracingEnvVars) will then propagate an empty API key into traits/env vars and continue as if nothing went wrong — producing broken agents that publish traces without authentication.

Additionally, even when an error is returned, translatePipelineError is the wrong semantic translation for an authentication/authorization failure. A dedicated sentinel (e.g., utils.ErrInvalidInput, utils.ErrForbidden, or a new utils.ErrMissingOrgIdentity) would let upstream HTTP handlers map this to 403 instead of "deployment pipeline not found".

🐛 Proposed fix
 	// Extract OrgId from the caller's JWT claims
 	callerClaims := jwtassertion.GetTokenClaims(ctx)
 	if callerClaims == nil || callerClaims.OuId == "" {
-		s.logger.Error("GenerateToken: missing organization identity in caller token")
-		return "", translatePipelineError(err)
+		s.logger.Error("generateAgentAPIKey: missing organization identity in caller token", "agentName", agentName)
+		return "", fmt.Errorf("missing organization identity in caller token: %w", utils.ErrInvalidInput)
 	}

Adjust the wrapped sentinel to whatever your error model uses for "forbidden / missing auth context".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@agent-manager-service/services/agent_manager.go` around lines 433 - 438, The
code in generateAgentAPIKey checks jwtassertion.GetTokenClaims(ctx) but when
callerClaims is nil or callerClaims.OuId == "" it logs and returns "",
translatePipelineError(err) which uses a nil err and thus returns nil; change
this to return a meaningful sentinel error (e.g., utils.ErrMissingOrgIdentity or
utils.ErrForbidden) instead of translatePipelineError, so callers get a non-nil
error and upstream can map to 403; update the return in the failing branch to
return "", utils.ErrMissingOrgIdentity (or your project’s equivalent) and keep
the existing log statement to preserve diagnostics.

Comment on lines +141 to +149
require.Contains(t, claims, "ou_id")
require.Contains(t, claims, "iss")
require.Contains(t, claims, "exp")
require.Contains(t, claims, "iat")

// Validate the component_uid matches what we expect
require.Equal(t, tokenComponentUid, claims["component_uid"])
require.Equal(t, tokenEnvUid, claims["environment_uid"])
require.Equal(t, "mock-ou-id", claims["ou_id"])
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Test assertions for the new claim won't match the produced token (will fail at runtime).

Two mismatches make these assertions impossible to satisfy as-is:

  1. Key: AgentTokenClaims.OrgId is tagged json:"org_id" in agent-manager-service/services/agent_token_manager.go (line 67), so the claim is serialized as org_id — not ou_id. require.Contains(t, claims, "ou_id") will fail.
  2. Value: The mock middleware sets TokenClaims.OuId = "mock-org-id" in agent-manager-service/middleware/jwtassertion/test_utils.go (line 34). That value flows through callerClaims.OuId → req.OrgId → claims.OrgId, so even with the right key the value will be "mock-org-id", not "mock-ou-id".

Given the PR's intent ("Add org uuid to the trace publishing token") and the chosen field/tag names, aligning the test with the implementation is the simpler fix.

🐛 Suggested fix to align the test with the implementation
 		require.Contains(t, claims, "component_uid")
 		require.Contains(t, claims, "environment_uid")
-		require.Contains(t, claims, "ou_id")
+		require.Contains(t, claims, "org_id")
 		require.Contains(t, claims, "iss")
 		require.Contains(t, claims, "exp")
 		require.Contains(t, claims, "iat")

 		// Validate the component_uid matches what we expect
 		require.Equal(t, tokenComponentUid, claims["component_uid"])
 		require.Equal(t, tokenEnvUid, claims["environment_uid"])
-		require.Equal(t, "mock-ou-id", claims["ou_id"])
+		require.Equal(t, "mock-org-id", claims["org_id"])

Alternatively, if the on-the-wire claim name was intended to be ou_id (mirroring the upstream OuId from caller claims), update the JSON tag in agent_token_manager.go to json:"ou_id" and the mock value in test_utils.go to "mock-ou-id" instead.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
require.Contains(t, claims, "ou_id")
require.Contains(t, claims, "iss")
require.Contains(t, claims, "exp")
require.Contains(t, claims, "iat")
// Validate the component_uid matches what we expect
require.Equal(t, tokenComponentUid, claims["component_uid"])
require.Equal(t, tokenEnvUid, claims["environment_uid"])
require.Equal(t, "mock-ou-id", claims["ou_id"])
require.Contains(t, claims, "org_id")
require.Contains(t, claims, "iss")
require.Contains(t, claims, "exp")
require.Contains(t, claims, "iat")
// Validate the component_uid matches what we expect
require.Equal(t, tokenComponentUid, claims["component_uid"])
require.Equal(t, tokenEnvUid, claims["environment_uid"])
require.Equal(t, "mock-org-id", claims["org_id"])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@agent-manager-service/tests/agent_token_test.go` around lines 141 - 149, The
test is asserting the wrong claim key and value; update the assertions in
agent_token_test.go to match the implementation: check for "org_id" (not
"ou_id") and expect the value "mock-org-id" for the org claim — this aligns with
AgentTokenClaims.OrgId (json:"org_id") in
agent-manager-service/services/agent_token_manager.go and the mock setting
TokenClaims.OuId = "mock-org-id" in
agent-manager-service/middleware/jwtassertion/test_utils.go; change
require.Contains(t, claims, "ou_id") → require.Contains(t, claims, "org_id") and
require.Equal(t, "mock-ou-id", claims["ou_id"]) → require.Equal(t,
"mock-org-id", claims["org_id"]).

@AnoshanJ
Copy link
Copy Markdown
Contributor

Missing: Claim mapping and collector config for org_id

The PR adds org_id to the JWT token, but the downstream pipeline isn't wired up to propagate it into the actual traces. Without these changes, the org_id claim is present in the token but never reaches the stored trace data.

Two additional changes are needed:

1. Gateway claim mapping (deployments/values/otel-collector-rest-api.yaml)

Add org_id to claimMappings so the gateway forwards it as an HTTP header to the collector:

claimMappings:
  sub: x-user-id
  component_uid: x-user-component
  environment_uid: x-user-environment
  project_uid: x-user-project
  org_id: x-user-org           # add this

2. Collector resource processor (deployments/values/oc-collector-configmap.yaml)

Add a resource attribute entry so the collector extracts the header into a trace attribute:

resource:
  attributes:
    # ... existing attributes ...
    - key: openchoreo.dev/org-uid
      from_context: metadata.x-user-org
      action: upsert

Without both pieces, the org_id claim won't flow through: token → gateway header → collector attribute → stored trace.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants