Registry stack documentation: machine-readable Markdown.
Index of all pages: https://docs.registrystack.org/v/0.38.0/llms.txt
Full corpus: https://docs.registrystack.org/v/0.38.0/llms-full.txt

# Request an access token from your own code

> Configure an issuer-neutral private key JWT client-credentials exchange with an explicit token endpoint, resource, and scopes.

Use a private key JWT client assertion when an application needs its own short-lived access token
for Evidence Gateway, Base Registry Engine (BReg), or Registry Relay. The deployment's OAuth issuer owns
client registration and token issuance. The resource server independently verifies the resulting
token against its configured issuer, audience, algorithm, token type, and authority claims.

## Before you start

Obtain these values from the issuer administrator:

- The exact HTTPS token endpoint.
- The registered client identifier.
- The client's private JWK and registered key identifier.
- The client-assertion audience. This often equals the issuer identifier or token endpoint, but
  the issuer contract decides the exact value.
- The RFC 8707 resource identifier for the intended resource server.
- The non-empty scopes approved for this client and resource.

Keep the private key in the calling process's secret store. The issuer registration holds only the
public key. Do not add a client secret as a fallback when assertion authentication fails.

## Configure a maintained client binding

The Evidence Gateway Node binding performs the exchange, refreshes before token expiry, coalesces
concurrent refreshes, and invalidates a cached token after an authentication refusal. Configure its
credential source explicitly:

```typescript
const token = {
  privateKeyJwt: {
    tokenEndpoint: "https://issuer.example.org/oauth2/token",
    clientId: "permit-desk",
    clientKey: privateJwk,
    audience: "https://issuer.example.org",
    resource: "urn:registry:evidence",
    scopes: ["evidence:evaluate"],
  },
};
```

The Python binding uses the same contract with snake-case field names:

```python
token = {
    "private_key_jwt": {
        "token_endpoint": "https://issuer.example.org/oauth2/token",
        "client_id": "permit-desk",
        "client_key": private_jwk,
        "audience": "https://issuer.example.org",
        "resource": "urn:registry:evidence",
        "scopes": ["evidence:evaluate"],
    }
}
```

Pass this `token` value in the client configuration shown by
[request Evidence from an application](../../tutorials/request-evidence-from-an-application/).
The Relay and BReg client bindings expose the same private key JWT credential provider for their
own resource URLs and registered scopes.

{/* Evidence: crates/registry-platform-httputil/src/client/private_key_jwt.rs;
    crates/registry-evidence-client-node/client.d.ts;
    crates/registry-evidence-client-py/src/convert.rs. */}

## Raw token request contract

If another client library performs the exchange, it must create a fresh signed JWT assertion for
each request. Its `iss` and `sub` are the registered client identifier, `aud` is the configured
assertion audience, `jti` is fresh, and `iat` and `exp` fit the issuer's accepted lifetime. The
protected header names the registered key with `kid` and uses the registered signing algorithm.

Send the assertion in an OAuth form:

```text
grant_type=client_credentials
client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
client_assertion=<signed-client-assertion>
resource=urn:registry:evidence
scope=evidence:evaluate
```

Treat the endpoint as HTTPS, disable redirects, apply a bounded timeout and response-size limit,
and never log the assertion, private key, access token, or token response. Keep `resource` and
`scope` immutable for one configured provider so a caller cannot redirect cached authority to a
different service.

## Troubleshooting

| Symptom | Check |
| --- | --- |
| The issuer returns `invalid_client` | Confirm the client identifier, registered public key, `kid`, signing algorithm, assertion audience, clock, and fresh `jti`. |
| The issuer rejects the request shape | Confirm the exact token endpoint, `client_credentials` grant, assertion type URN, resource, and non-empty scopes. |
| The resource server rejects the token | Confirm the token issuer, audience or resource, token type, algorithm, scopes, and configured authority claim names. |
| A migrated configuration names `mint` | Replace the retired key with the owning component's `token_client` or private key JWT configuration and provide the explicit endpoint, audience, client, key, resource, and scopes. The retired key is rejected rather than aliased. |

## Next

- [Request Evidence from an application](../../tutorials/request-evidence-from-an-application/)
- [Configure Evidence Gateway](../evidence/)
- [Evidence Gateway security model](../../security/evidence/)