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

# Tenant Tokens

> Issue short-lived tokens that act inside one tenant, narrow what they can do, and keep them fresh in long-running services.

A tenant token lets your service act inside one tenant on behalf of a customer.
Your platform issues it with [partner credentials](/docs/platform/authentication/partner-credentials), uses it for a few minutes, and lets it expire.
Anything created with the token belongs to that tenant.

The examples use a tenant ID, such as one returned when you [create a tenant](/docs/platform/tenants/create).

## What a tenant token can do

A tenant token works with every Namespace client, so your service can do anything inside the customer's tenant that the customer could do themselves:

| Client | What your service can do with it |
| - | - |
| Compute | Create and manage [instances](/docs/platform/instances/quickstart), run commands in them, and manage [cache volumes](/docs/platform/storage/cache-volumes) and persistent volumes. |
| Builds | Run container image builds and read their history. |
| Registry | Push, pull, and list images in the tenant's [container registry](/docs/platform/storage/container-registry). |
| Vault | Store and read [secrets](/docs/platform/storage/secrets). |
| IAM | Read the tenant's [policies](/docs/platform/tenants/policies), and create, list, and revoke [revokable tokens](/docs/platform/authentication/revokable-tokens). |

Everything the token creates belongs to its tenant and is invisible to every other tenant.
A tenant token cannot manage tenants: creating, updating, or deleting tenants, setting their policies, and issuing tenant tokens need [partner credentials](/docs/platform/authentication/partner-credentials).

By default, a token can use all of these. To limit a token to the actions it needs, see [Narrow what a token can do](#narrow-what-a-token-can-do).

## Issue a tenant token

Your platform issues tenant tokens with its partner client.

<Steps titleSize="h3">
  <Step title="Create a partner client">
    A partner client authenticates with a token source that signs partner tokens.
    [Partner credentials](/docs/platform/authentication/partner-credentials) shows how to build `partnerTokenSource` and explains each field.

    <CodeGroup>
      ```typescript TypeScript theme={null}
      import { createIAMClient } from "@namespacelabs/sdk/api/iam";

      const partnerClient = createIAMClient({ tokenSource: partnerTokenSource });
      ```

      ```go Go theme={null}
      import "namespacelabs.dev/integrations/api/iam"

      partnerClient, err := iam.NewClient(ctx, partnerTokenSource{privateKey})
      if err != nil {
      	log.Fatal(err)
      }
      defer partnerClient.Close()
      ```
    </CodeGroup>
  </Step>

  <Step title="Request the token">
    `IssueTenantToken` takes the tenant ID, an actor ID, and a duration.

    <CodeGroup>
      ```typescript TypeScript theme={null}
      const { bearerToken } = await partnerClient.tenants.issueTenantToken({
        tenantId: "tenant_lqrj7qre0ts32",
        actorId: "user:4821",
        durationSecs: 15n * 60n,
      });
      ```

      ```go Go theme={null}
      issued, err := partnerClient.Tenants.IssueTenantToken(ctx, &iamv1beta.IssueTenantTokenRequest{
      	TenantId:     "tenant_lqrj7qre0ts32",
      	ActorId:      "user:4821",
      	DurationSecs: 15 * 60,
      })
      if err != nil {
      	log.Fatal(err)
      }

      bearerToken := issued.BearerToken
      ```
    </CodeGroup>

    The actor ID is a string you choose to identify who in your system the token acts for, such as the customer's user or one of your services.
    Namespace embeds it in the token.
    Anyone holding the token can read it, so use a stable identifier from your own system, such as `user:4821` or `service:billing`, rather than personal data like an email address.

    If you leave out the duration, the token lasts about 15 minutes.
  </Step>

  <Step title="Save the token to a file (optional)">
    If the token is used by a separate process, such as a script or the `nsc` CLI, write it to a token file.
    The file holds the token in a `bearer_token` field. Restrict it to the current user, because anyone who can read it can act inside the tenant.

    <CodeGroup>
      ```typescript TypeScript theme={null}
      import { writeFileSync } from "node:fs";

      writeFileSync("tenant-token.json", JSON.stringify({ bearer_token: bearerToken }), {
        mode: 0o600,
      });
      ```

      ```go Go theme={null}
      import (
      	"encoding/json"
      	"os"
      )

      contents, err := json.Marshal(map[string]string{"bearer_token": bearerToken})
      if err != nil {
      	log.Fatal(err)
      }

      if err := os.WriteFile("tenant-token.json", contents, 0o600); err != nil {
      	log.Fatal(err)
      }
      ```
    </CodeGroup>

    The file stops working when the token expires.

    <Tip>
      Point the `NSC_TOKEN_FILE` environment variable at the file.
      The `nsc` CLI, and SDK clients that load default credentials, then authenticate as the tenant:

      ```bash theme={null}
      NSC_TOKEN_FILE="$(pwd)/tenant-token.json" nsc list
      ```
    </Tip>
  </Step>
</Steps>

<Note>
  Tenant tokens cannot be revoked. Once issued, a token is valid until it expires, so keep durations short. If you need to end a credential's access early, use a [revokable token](/docs/platform/authentication/revokable-tokens) instead.
</Note>

## Create a tenant client

A tenant client acts inside the tenant the token belongs to.

<Steps titleSize="h3">
  <Step title="Create the client from the token">
    Pass the token to any Namespace client.
    Here it creates an IAM client, which can read and manage things that belong to the tenant.

    <CodeGroup>
      ```typescript TypeScript theme={null}
      import { createIAMClient } from "@namespacelabs/sdk/api/iam";
      import { fromBearerToken } from "@namespacelabs/sdk/auth";

      const tenantClient = createIAMClient({
        tokenSource: fromBearerToken(bearerToken),
      });
      ```

      ```go Go theme={null}
      type bearerTokenSource string

      func (t bearerTokenSource) IssueToken(context.Context, time.Duration, bool) (string, error) {
      	return string(t), nil
      }

      tenantClient, err := iam.NewClient(ctx, bearerTokenSource(bearerToken))
      if err != nil {
      	log.Fatal(err)
      }
      defer tenantClient.Close()
      ```
    </CodeGroup>

    If you saved the token to a file, load it instead with `loadDefaults()` in TypeScript or `auth.LoadDefaults()` in Go. Both read the file named by `NSC_TOKEN_FILE`.

    For local development, `loadDefaults()` can also use your `nsc login`. See [Build on your own workspace](/docs/platform/authentication/local-development).

    The same token works with the Compute client, which is how your service runs [instances](/docs/platform/instances/quickstart) inside the customer's tenant.
  </Step>

  <Step title="Test the token">
    Reading the tenant's policies is a read-only call that only works with a tenant token, which makes it a safe first request.

    <CodeGroup>
      ```typescript TypeScript theme={null}
      const { policies } = await tenantClient.tenants.describePolicies({});

      console.log(`Authenticated. Policies found: ${policies.length}.`);
      ```

      ```go Go theme={null}
      resp, err := tenantClient.Tenants.DescribePolicies(ctx, &iamv1beta.DescribePoliciesRequest{})
      if err != nil {
      	log.Fatal(err)
      }

      fmt.Printf("Authenticated. Policies found: %d.\n", len(resp.Policies))
      ```
    </CodeGroup>

    ```text Output theme={null}
    Authenticated. Policies found: 1.
    ```

    A new tenant has one policy, an empty usage policy. [Tenant policies](/docs/platform/tenants/policies) explains what it controls.
  </Step>
</Steps>

## Narrow what a token can do

By default, a tenant token can do anything inside its tenant.
When a token only needs a few actions, grant just those with `access`.
For example, a token for a dashboard that only displays a customer's instances needs nothing beyond listing them:

<CodeGroup>
  ```typescript TypeScript theme={null}
  const { bearerToken } = await partnerClient.tenants.issueTenantToken({
    tenantId: "tenant_lqrj7qre0ts32",
    actorId: "service:dashboard",
    durationSecs: 15n * 60n,
    access: {
      grants: [{ resourceType: "instance", resourceId: "*", actions: ["list"] }],
    },
  });
  ```

  ```go Go theme={null}
  issued, err := partnerClient.Tenants.IssueTenantToken(ctx, &iamv1beta.IssueTenantTokenRequest{
  	TenantId:     "tenant_lqrj7qre0ts32",
  	ActorId:      "service:dashboard",
  	DurationSecs: 15 * 60,
  	Access: &iamv1beta.AccessPolicy{
  		Grants: []*iamv1beta.Permission{{
  			ResourceType: "instance",
  			ResourceId:   "*",
  			Actions:      []string{"list"},
  		}},
  	},
  })
  ```
</CodeGroup>

This token can list the tenant's instances, and any other call fails with a permission error.
Each grant names a resource type, a resource ID or `*` for all, and a list of actions.
The [permissions reference](/docs/platform/workspaces/permissions) lists every resource type and its actions.

## Keep tokens fresh in long-running services

A token from `fromBearerToken` in TypeScript, or a fixed-token source in Go, stops working when the token expires.
That is fine for a short task. A service that keeps a client for longer than the token's lifetime should give the client a token source that issues a new tenant token on demand.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import type { TokenSource } from "@namespacelabs/sdk/auth";
  import { createComputeClient } from "@namespacelabs/sdk/api/compute";

  function tenantTokenSource(tenantId: string, actorId: string): TokenSource {
    return {
      async issueToken() {
        const { bearerToken } = await partnerClient.tenants.issueTenantToken({
          tenantId,
          actorId,
          durationSecs: 15n * 60n,
        });
        return bearerToken;
      },
    };
  }

  const compute = createComputeClient({
    tokenSource: tenantTokenSource("tenant_lqrj7qre0ts32", "service:billing"),
  });
  ```

  ```go Go theme={null}
  import (
  	"namespacelabs.dev/integrations/api/compute"
  	"namespacelabs.dev/integrations/auth"
  )

  tokens := auth.TenantTokenSource(partnerClient, "tenant_lqrj7qre0ts32")

  computeClient, err := compute.NewClient(ctx, tokens)
  if err != nil {
  	log.Fatal(err)
  }
  defer computeClient.Close()
  ```
</CodeGroup>

The TypeScript SDK reuses each token until fewer than five minutes of validity remain, then calls `issueToken` again.
In Go, `auth.TenantTokenSource` issues a new tenant token for every request and does not set an actor ID. If you need either behavior to differ, implement your own `IssueToken` as in the TypeScript example.

## Next steps

<Columns cols={2}>
  <Card title="Revokable tokens" icon="ban" href="/docs/platform/authentication/revokable-tokens">
    Long-lived tenant credentials you can revoke.
  </Card>

  <Card title="Tenant policies" icon="gauge" href="/docs/platform/tenants/policies">
    Read and change a tenant's limits.
  </Card>
</Columns>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.