> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kavachos.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Verifiable credentials

> Issue and verify W3C Verifiable Credentials for agent identity, permissions, and delegation.

## Why verifiable credentials matter for agents

When agent A calls agent B, how does B know what A is allowed to do? Today, most systems answer this with a network call back to a central auth server. That works inside one organization, but falls apart when agents cross trust boundaries.

W3C Verifiable Credentials solve this. A credential is a signed JSON document that says "agent X has permissions Y, issued by authority Z." The agent carries the credential and presents it directly. The verifier checks the cryptographic signature and reads the permissions. No network call needed.

This matters for three reasons:

1. **Offline verification** -- an agent can prove its identity and permissions without the issuing server being reachable
2. **Cross-organization trust** -- if you trust the issuer's DID, you trust the credential, regardless of where the agent lives
3. **Delegation chains** -- a credential can encode a chain of delegations, so a sub-agent can prove it was authorized by its parent

<Info>
  VCs build on top of KavachOS DID support. If you have not set up DIDs yet, see the [DID identity](/did) page first.
</Info>

## Issuing credentials

Create an issuer bound to a DID keypair. The issuer can produce credentials in JWT or JSON-LD format.

```typescript theme={"system"}
import { generateDidKey } from 'kavachos/did';
import { createVCIssuer } from 'kavachos/vc';

const keyPair = await generateDidKey();

const issuer = createVCIssuer({
  issuerDid: keyPair.did,
  privateKeyJwk: keyPair.privateKeyJwk,
  publicKeyJwk: keyPair.publicKeyJwk,
  defaultTtl: 86400, // 24 hours
});
```

### Agent identity credential

Encodes who the agent is, what it can do, and how much you trust it.

<Tabs>
  <Tab title="JWT">
    ```typescript theme={"system"}
    const result = await issuer.issueAgentCredential({
      agentId: 'agent-data-processor',
      name: 'Data Processor',
      agentType: 'autonomous',
      permissions: ['read:datasets', 'write:reports'],
      trustLevel: 0.85,
      format: 'jwt',
    });

    if (result.success) {
      // Send the JWT to the agent -- it carries this as a bearer credential
      const jwt = result.data.jwt;
    }
    ```
  </Tab>

  <Tab title="JSON-LD">
    ```typescript theme={"system"}
    const result = await issuer.issueAgentCredential({
      agentId: 'agent-data-processor',
      name: 'Data Processor',
      agentType: 'autonomous',
      permissions: ['read:datasets', 'write:reports'],
      trustLevel: 0.85,
      format: 'json-ld',
    });

    if (result.success) {
      // The credential includes an embedded proof
      const vc = result.data.credential;
      console.log(vc.proof.type); // "JsonWebSignature2020"
    }
    ```
  </Tab>
</Tabs>

### Permission credential

Grants specific permissions to an agent without encoding the full identity.

```typescript theme={"system"}
const result = await issuer.issuePermissionCredential({
  agentId: 'agent-helper',
  permissions: ['read:files', 'execute:tools'],
  ttl: 3600, // 1 hour
});
```

### Delegation credential

Encodes a chain of delegations so a sub-agent can prove it was authorized by its parent, which was authorized by its parent, and so on.

```typescript theme={"system"}
const result = await issuer.issueDelegationCredential({
  agentId: 'sub-agent',
  chain: [
    {
      delegator: 'did:key:z6MkRoot...',
      delegatee: 'did:key:z6MkMiddle...',
      permissions: ['read:data', 'write:data'],
      createdAt: new Date().toISOString(),
    },
    {
      delegator: 'did:key:z6MkMiddle...',
      delegatee: 'sub-agent',
      permissions: ['read:data'],
      createdAt: new Date().toISOString(),
    },
  ],
  delegationScope: ['read:data'],
});
```

## Verifying credentials

Create a verifier to check credentials from any source. The verifier validates the signature, checks expiry, and optionally checks revocation status.

```typescript theme={"system"}
import { createVCVerifier } from 'kavachos/vc';

const verifier = createVCVerifier({
  // Optional: resolve DIDs to public keys automatically
  resolveDidKey: async (did) => {
    // Look up the DID document and return the public key
    const doc = await myDidResolver.resolve(did);
    return doc?.verificationMethod[0]?.publicKeyJwk ?? null;
  },
  // Optional: check revocation
  checkRevocationStatus: async (status) => {
    const list = await fetch(status.statusListCredential);
    // Check if the credential at statusListIndex is revoked
    return isRevoked(await list.json(), status.statusListIndex);
  },
});
```

### Verify a JWT credential

```typescript theme={"system"}
const result = await verifier.verifyCredential(jwtString);

if (result.success) {
  console.log(result.data.issuer);    // "did:key:z6Mk..."
  console.log(result.data.format);    // "jwt"
  console.log(result.data.expiresAt); // Date or null
}
```

### Verify a JSON-LD credential

```typescript theme={"system"}
const result = await verifier.verifyCredential(credentialObject);

if (result.success) {
  console.log(result.data.format); // "json-ld"
}
```

### Verify a presentation (multiple credentials)

An agent might present several credentials at once to prove both identity and permissions.

```typescript theme={"system"}
const presentation = {
  '@context': ['https://www.w3.org/ns/credentials/v2'],
  type: ['VerifiablePresentation'],
  holder: 'did:key:z6MkAgent...',
  verifiableCredential: [agentCredential, permissionCredential],
};

const result = await verifier.verifyPresentation(presentation);

if (result.success) {
  for (const verified of result.data.credentials) {
    console.log(verified.issuer, verified.credential.type);
  }
}
```

### Extract permissions

After verification, pull out the KavachOS-specific permissions.

```typescript theme={"system"}
const extracted = verifier.extractPermissions(verifiedCredential);

console.log(extracted.agentId);        // "agent-data-processor"
console.log(extracted.permissions);    // ["read:datasets", "write:reports"]
console.log(extracted.trustLevel);     // 0.85
console.log(extracted.delegationScope); // []
```

## Portable identity

The key advantage of VCs is portability. An agent issued a credential by KavachOS instance A can present it to service B without B ever talking to A.

```
Agent                     Service B
  |                          |
  |-- present VC ----------->|
  |                          |-- check signature (local)
  |                          |-- check expiry (local)
  |                          |-- extract permissions
  |                          |
  |<-- authorized -----------|
```

The only requirement is that service B trusts the issuer's DID. This can be configured as a simple allowlist of trusted DIDs, or through a more formal trust framework.

## Integration with DID support

VCs work with both `did:key` and `did:web` identifiers. The issuer DID is embedded in the credential's `issuer` field. When verifying, the verifier resolves the DID to get the public key.

For `did:key`, resolution is local (the key is embedded in the identifier). For `did:web`, the verifier fetches the DID document from the well-known URL.

```typescript theme={"system"}
import { generateDidKey } from 'kavachos';
import { createVCIssuer, createVCVerifier } from 'kavachos/vc';

// Issuer creates credentials with their did:key
const issuerKeys = await generateDidKey();
const issuer = createVCIssuer({
  issuerDid: issuerKeys.did,
  privateKeyJwk: issuerKeys.privateKeyJwk,
  publicKeyJwk: issuerKeys.publicKeyJwk,
});

// Verifier trusts this issuer's DID
const trustedKeys = new Map([[issuerKeys.did, issuerKeys.publicKeyJwk]]);

const verifier = createVCVerifier({
  resolveDidKey: async (did) => trustedKeys.get(did) ?? null,
});
```
