> **Building with AI coding agents?** Install the authstack plugin with one command. This equips your agent with accurate Scalekit implementation patterns.
>
> **Recommended**:
> ```bash
> npx @scalekit-inc/cli setup
> ```
>
> Global:
> ```bash
> npm install -g @scalekit-inc/cli
> scalekit setup
> ```
>
> Supports Claude Code, Cursor, GitHub Copilot, Codex + skills for 40+ agents.
> Skills: integrate-agentkit, implement-saaskit, add-mcp-oauth, implement-sso, implement-scim.
> [Full setup guide](https://docs.scalekit.com/dev-kit/build-with-ai/)

---

# Resource

Manage resource clients and the consents your end users grant against them
{/* The `sdk-client-page` and `sdk-method-section` wrappers are required raw
    elements, not layout decoration: `@/styles/sdk-reference.css` scopes every
    ClassBrowser override under `.sdk-client-page` so the styles survive
    ClientRouter navigation, and `.sdk-method-section` frames each method block.
    No Starlight component emits these hooks. */}

<div class="sdk-client-page">

Use `scalekit.resources` to manage resource clients and to read and revoke the consents your end users grant against one. A consent records that one end user allowed a specific resource client to act on their behalf.

The same audit and revoke actions are available in the dashboard under [Managing MCP clients](/authenticate/mcp/managing-mcp-clients/).

### getResource
<div class="sdk-method-section">
  
    
      

      Retrieves a single resource by id.

      
        The resource to fetch (format: `res_...`).
      
      
        Resource object.
      

```typescript wrap showLineNumbers=false
const res = await scalekit.resources.getResource('res_xxx');
console.log(res.resource);
```

    
  
</div>

### listResources
<div class="sdk-method-section">
  
    
      

      Lists resources of a given type in the environment, with pagination.

      
        The resource type to filter by. Supported value: `ResourceType.MCP_SERVER`.
      
      
        Optional fields: `pageSize` (max 30), `pageToken`.
      
      
        Paginated resources.
      

```typescript wrap showLineNumbers=false

const res = await scalekit.resources.listResources(ResourceType.MCP_SERVER, {
  pageSize: 20,
});

for (const resource of res.resources) {
  console.log(resource.id, resource.scopes);
}
```

    
  
</div>

### createResourceClient
<div class="sdk-method-section">
  
    
      

      Creates a resource client. Returns the created `client` and a `plainSecret` - the plaintext client secret, only available at creation time.

      
        The resource to create the client for (format: `res_...`).
      
      
        Optional client properties. `name` defaults to "Resource Client" if omitted. `scopes` should be the same or a subset of the scopes available for the resource. `customClaims` is a flat JSON structure only. `expiry` (access token lifetime in seconds) defaults to the resource's configured expiry. `redirectUris` are the allowed redirect URIs for a pre-registered client.
      
      
        The created client and its plaintext secret.
      

```typescript wrap showLineNumbers=false
const resResource = await scalekit.resources.getResource('res_xxx');
const allowedScopes = resResource.resource?.scopes.filter((s) => s.enabled).map((s) => s.name);

const res = await scalekit.resources.createResourceClient('res_xxx', {
  name: 'My Resource Client',
  scopes: allowedScopes,
});

console.log(res.client?.clientId);
// Store res.plainSecret in your secret manager now - it is never returned again.
// It grants full access as this client, so if it leaks, replace it right away:
// create a new secret and delete the compromised one (delete first if you're
// already at your secret limit; if it's your only secret, raise the limit
// before rotating).
```

    
  
</div>

### getResourceClient
<div class="sdk-method-section">
  
    
      

      Fetches a single resource client. For a DCR client, the response also includes the end-users who have granted it consent.

      
        The resource the client must belong to (format: `res_...`).
      
      
        The client ID (format: `m2m_...`).
      
      
        The resource client.
      

```typescript wrap showLineNumbers=false
const res = await scalekit.resources.getResourceClient('res_xxx', 'm2m_xxx');
console.log(res.client?.name);
```

    
  
</div>

### listResourceClients
<div class="sdk-method-section">
  
    
      

      Lists resource clients.

      
        The resource whose clients to list (format: `res_...`).
      
      
        The resource's clients, plus `totalDcrClients` and `totalStaticClients` counts.
      

```typescript wrap showLineNumbers=false
const res = await scalekit.resources.listResourceClients('res_xxx');

console.log(res.totalDcrClients, res.totalStaticClients);
for (const c of res.clients) {
  console.log(c.clientId, c.name);
}
```

    
  
</div>

### updateResourceClient
<div class="sdk-method-section">
  
    
      

      Updates a resource client.

      
        The resource the client must belong to (format: `res_...`).
      
      
        The client ID to update (format: `m2m_...`).
      
      
        Fields to update - only fields present are changed. `name`/`description` are a no-op server-side when passed as an empty string, not a clear. `scopes`, `customClaims`, and `redirectUris` replace their existing values; pass an empty value (`[]` or `{}`) to clear one of them.
      
      
        The updated client.
      

```typescript wrap showLineNumbers=false
const resResource = await scalekit.resources.getResource('res_xxx');
const allowedScopes = resResource.resource?.scopes.filter((s) => s.enabled).map((s) => s.name);

const res = await scalekit.resources.updateResourceClient('res_xxx', 'm2m_xxx', {
  name: 'Updated Name',
  scopes: allowedScopes,
});

console.log(res.client?.name, res.client?.scopes);
```

    
  
</div>

### deleteResourceClient
<div class="sdk-method-section">
  
    
      

      Deletes resource clients. Throws if the client is missing or scoped to a different resource.

      
        The resource the client must belong to (format: `res_...`).
      
      
        The client ID to delete (format: `m2m_...`).
      
      
        Empty response on success.
      

```typescript wrap showLineNumbers=false
await scalekit.resources.deleteResourceClient('res_xxx', 'm2m_xxx');
```

    
  
</div>

### createResourceClientSecret
<div class="sdk-method-section">
  
    
      

      Creates a new secret for a resource client. Only 2 client secrets are recommended to exist at a given point in time - use `deleteResourceClientSecret` to remove an existing one first if you need more.

      The plaintext client secret is only ever returned here, at creation time.

      
        The resource the client must belong to (format: `res_...`).
      
      
        The client ID to create a secret for (format: `m2m_...`).
      
      
        The new secret, including its plaintext value.
      

```typescript wrap showLineNumbers=false
const res = await scalekit.resources.createResourceClientSecret('res_xxx', 'm2m_xxx');
// Store res.plainSecret in your secret manager now - it is never returned again.
// It grants full access as this client, so if it leaks, replace it right away:
// create a new secret and delete the compromised one (delete first if you're
// already at your secret limit; if it's your only secret, raise the limit
// before rotating).
```

    
  
</div>

### deleteResourceClientSecret
<div class="sdk-method-section">
  
    
      

      Permanently deletes a secret from a resource client. A client must always keep at least 1 secret - calling this on a client's last remaining secret throws an error.

      
        The resource the client must belong to (format: `res_...`).
      
      
        The client ID the secret belongs to (format: `m2m_...`).
      
      
        The secret ID to delete (format: `sks_...`).
      
      
        Empty response on success.
      

```typescript wrap showLineNumbers=false
await scalekit.resources.deleteResourceClientSecret('res_xxx', 'm2m_xxx', 'sks_xxx');
```

    
  
</div>

### listUserConsents
<div class="sdk-method-section">
  
    
      

      Lists the end-user consents granted against a resource, with pagination. Use this to audit who authorized a client, and to find the `consentId` you need before revoking.

      Filter by user in one of two ways. Pass `userIds` to match external user IDs exactly and case-sensitively. Pass `search` for a case-insensitive substring match. When you give both, `userIds` wins and `search` is ignored.

      
        The resource whose consents to list (format: `res_...`).
      
      
        Optional fields: `search`, `pageSize` (max 30), `pageToken`, `userIds` (max 25, takes precedence over `search`).
      
      
        Consents with `id`, `externalUserId`, `clientId`, `clientName`, `scopes`, and `grantedAt`, plus `totalSize` and the `nextPageToken` / `prevPageToken` cursors.
      

```typescript wrap showLineNumbers=false
const res = await scalekit.resources.listUserConsents('res_xxx', {
  pageSize: 20,
  userIds: ['user_456'], // optional; takes precedence over search
});

console.log(res.totalSize, res.nextPageToken);
for (const consent of res.consents) {
  console.log(consent.id, consent.externalUserId, consent.clientId, consent.scopes);
}
```

    
  
</div>

### revokeUserConsent
<div class="sdk-method-section">
  
    
      

      Revokes a single end-user consent held by an API client. The client is prompted for consent again on its next authorization attempt, and every active refresh token issued to that client for the same user is revoked.

      Access tokens that Scalekit already issued stay valid until they expire. See [How revocation affects active access tokens](/authenticate/mcp/managing-mcp-clients/#how-revocation-affects-active-access-tokens) for ways to shorten that window.

      
        The API client that holds the consent (format: `m2m_...`), not the resource ID.
      
      
        The consent to revoke (format: `usrcnst_...`), taken from `listUserConsents`.
      
      
        Empty response on success. The call throws on failure.
      

```typescript wrap showLineNumbers=false
await scalekit.resources.revokeUserConsent('m2m_xxx', 'usrcnst_789');
```

    
  
</div>

</div>


---

## More Scalekit documentation

| Resource | What it contains | When to use it |
|----------|-----------------|----------------|
| [/llms.txt](/llms.txt) | Structured index with routing hints per product area | Start here — find which documentation set covers your topic before loading full content |
| [/llms-full.txt](/llms-full.txt) | Complete documentation for all Scalekit products in one file | Use when you need exhaustive context across multiple products or when the topic spans several areas |
| [sitemap-0.xml](https://docs.scalekit.com/sitemap-0.xml) | Full URL list of every documentation page | Use to discover specific page URLs you can fetch for targeted, page-level answers |
