> **Building with AI coding agents?** Install the authstack plugin with one command. This equips your agent with accurate Scalekit implementation patterns.
>
> **Recommended** (the `-y` flags skip prompts, so the command runs without an interactive terminal):
> ```bash
> npx -y @scalekit-inc/cli setup -y
> ```
>
> Global:
> ```bash
> npm install -g @scalekit-inc/cli
> scalekit setup -y
> ```
>
> Supports Claude Code, Cursor, GitHub Copilot, Codex + skills for other Agent Skills-compatible agents in `~/.agents/skills`.
> 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
<div class="sdk-client-page">

Use `scalekitClient.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.

        Request context

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

        Resource object.

```go
resource, err := scalekitClient.Resources().GetResource(ctx, "res_xxx")
if err != nil {
  // handle error
}
fmt.Println(resource.Resource)
```

</div>

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

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

        Request context

        The resource type to filter by. Supported value: `scalekit.ResourceTypeMcpServer`.

        Optional fields: `PageSize` (max 30), `PageToken`.

        Paginated resources.

```go
resources, err := scalekitClient.Resources().ListResources(ctx, scalekit.ResourceTypeMcpServer, scalekit.ListResourcesOptions{
  PageSize: 20,
})
if err != nil {
  // handle error
}
for _, r := range resources.Resources {
  fmt.Println(r.Id, r.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.

        Request context

        The resource to create the client for (format: `res_...`).

        The client properties. `Scopes` should be the same or a subset of the scopes available for the resource. `CustomClaims` is a flat key/value 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. There is no `Audience` field - audience is always server-determined.

        The created client and its plaintext secret.

```go
import (
  clients "github.com/scalekit-inc/scalekit-sdk-go/v2/pkg/grpc/scalekit/v1/clients"
)

resource, err := scalekitClient.Resources().GetResource(ctx, "res_xxx")
if err != nil {
  // handle error
}
var allowedScopes []string
for _, s := range resource.Resource.Scopes {
  if s.Enabled {
    allowedScopes = append(allowedScopes, s.Name)
  }
}

created, err := scalekitClient.Resources().CreateResourceClient(ctx, "res_xxx", &clients.ResourceClient{
  Name:   "My Resource Client",
  Scopes: allowedScopes,
})
if err != nil {
  // handle error
}

fmt.Println(created.Client.ClientId)
// Store created.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, along with the end-users who have granted it consent.

        Request context

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

        The client ID (format: `m2m_...`).

        The resource client.

```go
got, err := scalekitClient.Resources().GetResourceClient(ctx, "res_xxx", "m2m_xxx")
if err != nil {
  // handle error
}
fmt.Println(got.Client.Name)
```

</div>

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

      Lists resource clients.

        Request context

        The resource whose clients to list (format: `res_...`).

        The resource's clients, plus `TotalDcrClients` and `TotalStaticClients` counts.

```go
list, err := scalekitClient.Resources().ListResourceClients(ctx, "res_xxx")
if err != nil {
  // handle error
}
fmt.Println(list.TotalDcrClients, list.TotalStaticClients)
for _, c := range list.Clients {
  fmt.Println(c.ClientId, c.Name)
}
```

</div>

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

      Updates a resource client.

        Request context

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

        The client ID to update (format: `m2m_...`).

        Pointer fields - only the ones set (non-nil) are changed. `Name`/`Description` are a no-op server-side when set to an empty string, not a clear. `Scopes`, `CustomClaims`, and `RedirectUris` replace their existing values; set an empty (non-nil) slice to clear one of them. There's no `Audience` field.

        The updated client.

```go
resource, err := scalekitClient.Resources().GetResource(ctx, "res_xxx")
if err != nil {
  // handle error
}
var allowedScopes []string
for _, s := range resource.Resource.Scopes {
  if s.Enabled {
    allowedScopes = append(allowedScopes, s.Name)
  }
}

newName := "Updated Name"
updated, err := scalekitClient.Resources().UpdateResourceClient(ctx, "res_xxx", "m2m_xxx", scalekit.UpdateResourceClientOptions{
  Name:   &newName,
  Scopes: &allowedScopes,
})
if err != nil {
  // handle error
}

fmt.Println(updated.Client.Name, updated.Client.Scopes)
```

</div>

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

      Deletes resource clients. Returns an error if the client is missing or scoped to a different resource.

        Request context

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

        The client ID to delete (format: `m2m_...`).

        `nil` on success.

```go
if err := scalekitClient.Resources().DeleteResourceClient(ctx, "res_xxx", "m2m_xxx"); err != nil {
  // handle error
}
```

</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.

        Request context

        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.

```go
secret, err := scalekitClient.Resources().CreateResourceClientSecret(ctx, "res_xxx", "m2m_xxx")
if err != nil {
  // handle error
}
// Store secret.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 fails.

        Request context

        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_...`).

        `nil` on success.

```go
if err := scalekitClient.Resources().DeleteResourceClientSecret(ctx, "res_xxx", "m2m_xxx", "sks_xxx"); err != nil {
  // handle error
}
```

</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.

        Request context

        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.

```go
consents, err := scalekitClient.Resources().ListUserConsents(ctx, "res_xxx", scalekit.ListUserConsentsOptions{
  PageSize: 20,
  UserIds:  []string{"user_456"}, // optional; takes precedence over Search
})
if err != nil {
  // handle error
}
fmt.Println(consents.TotalSize, consents.NextPageToken)
for _, c := range consents.Consents {
  fmt.Println(c.Id, c.ExternalUserId, c.ClientId, c.Scopes)
}
```

</div>

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

      Revokes a single end-user consent held by a resource 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.

        Request context

        The resource 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 returns an error on failure.

```go
if _, err := scalekitClient.Resources().RevokeUserConsent(ctx, "m2m_xxx", "usrcnst_789"); err != nil {
  // handle error
}
```

</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 |
