feat: Add agent registration read and credential validation methods#1642
feat: Add agent registration read and credential validation methods#1642m0tzy wants to merge 7 commits into
Conversation
validateCredential now verifies access_token credentials against the environment's cached JWKS and returns the decoded claims without a network request. A new checkForRevoked option (access_token only) additionally calls the server to confirm the token has not been revoked. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tion result Local access_token verification now enforces the token audience (defaulting to the configured client ID, with an `audience` override for resource-scoped tokens whose aud is the resource). The validation result is now a discriminated union on `valid`, so a valid result narrows registrationId to a non-null string. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The validate endpoint now accepts an optional audience on the access_token variant, so checkForRevoked requests forward the same audience the SDK verifies against locally, letting the server verify the JWT aud claim too. The audience option is narrowed to a single string to match the endpoint's contract. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Agent registration ids use the agent_reg_ prefix (not agent_registration_), claims use agent_reg_claim_, and claim attempts use agent_reg_claim_attempt_. Also exercise the non-null claim_completion path in the getRegistration test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Greptile SummaryThis PR adds an agents SDK surface. The main changes are:
Confidence Score: 3/5The new agents SDK surface is mostly covered, but the revocation-check merge path can return conflicting registration identities. Endpoint wiring, serialization, local access-token validation, and mocked request behavior are exercised. The remaining concern is in the successful access-token revocation path, where the server verdict and local token claims are combined without confirming they refer to the same registration. src/agents/agents.ts needs attention around the
What T-Rex did
Prompt To Fix All With AIFix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
src/agents/agents.ts:120-121
**Remote Claims Can Diverge**
When `checkForRevoked` is enabled, this merge keeps the server's `registrationId` but attaches claims from the locally verified token without checking that both identify the same registration. If the validation API returns a valid response for a different registration than the JWT `sub`, callers receive two different identities in one successful result.
Reviews (4): Last reviewed commit: "refactor(agents): Require core access to..." | Re-trigger Greptile |
- Reject access tokens missing the agent identity claims (sub/jti/ organization_id) instead of reporting them valid with empty identifiers. - Treat a valid server verdict with a null registration_id as invalid. - URL-encode the registration id in the getRegistration request path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…piry Mark iss/aud/exp/iat (and sub/jti/organization_id) required on SerializedAgentAccessTokenClaims and guarantee them via a single hasRequiredAgentClaims guard, so decoded claims never surface empty values. Also reject a token whose exp is in the past explicitly, and keep the raw jti claim name instead of mapping it to jwtId. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| const remote = await this.validateCredentialRemotely(options); | ||
| return remote.valid ? { ...remote, claims } : remote; |
There was a problem hiding this comment.
When checkForRevoked is enabled, this merge keeps the server's registrationId but attaches claims from the locally verified token without checking that both identify the same registration. If the validation API returns a valid response for a different registration than the JWT sub, callers receive two different identities in one successful result.
Rule Used: JWTs should always be validated before use and the... (source)
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/agents.ts
Line: 120-121
Comment:
**Remote Claims Can Diverge**
When `checkForRevoked` is enabled, this merge keeps the server's `registrationId` but attaches claims from the locally verified token without checking that both identify the same registration. If the validation API returns a valid response for a different registration than the JWT `sub`, callers receive two different identities in one successful result.
**Rule Used:** JWTs should always be validated before use and the... ([source](https://app.greptile.com/workos/-/custom-context?memory=e0f82177-2285-4c61-8843-a81dfdf8fd23))
How can I resolve this? If you propose a fix, please make it concise.
Summary
Adds two SDK methods for the new API-key-authenticated agent-auth endpoints introduced in workos/workos#63723, surfaced under
workos.agents:workos.agents.getRegistration(id)→GET /agents/registrations/:id. Reads a single agent registration scoped to the API key's environment, returning its derivedstatus/kind, agent identity, organization, and claim state.workos.agents.validateCredential({ type, credential })→POST /agents/credentials/validate. Validates an agent credential (api_keyoraccess_token) and returns{ valid, registrationId, expiresAt }. Read-only — it never consumes or mutates the credential.The module follows the existing per-module layout (
interfaces/serializers/fixtures/ spec), deserializing the API's snake_case payloads into camelCase. It's wired into theWorkOSclient (readonly agents) and re-exported fromsrc/index.ts.Notes
agent-auth-public-apiflag and excluded from the public OpenAPI spec, so they won't appear in codegen yet. When they're eventually published to the spec, oagen may want to regenerate this module.404against environments whereagent-auth-public-apiis not enabled — expected while the feature is flag-gated.Testing
jest src/agents— 3 tests pass (registration read, valid credential, invalid credential)tsc --noEmit,eslint, andprettier --checkall cleanindex.barrelspec passes🤖 Generated with Claude Code
Closes AUTH-6622