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

# Create a Tenant with the Platform API

> Create a tenant for a customer, then act inside it on the customer's behalf with a tenant token.

In this quickstart, your platform creates a tenant for its first customer, then acts inside that tenant on the customer's behalf.
Along the way you use both clients a platform needs: a partner client that manages tenants, and a tenant client that works inside one.

## Before you start

You need partner credentials from Namespace: a partner ID, an issuer, a key ID, and a private key in PEM format.
[Partner credentials](/docs/platform/authentication/partner-credentials) explains each value.

<Info>
  No partner account yet? You can still build the parts of your platform that run inside a tenant by using your own workspace. See [Build on your own workspace](/docs/platform/authentication/local-development).
</Info>

## Getting started

<Steps titleSize="h3">
  <Step title="Add a client library">
    <CodeGroup>
      ```bash TypeScript theme={null}
      npm install @namespacelabs/sdk @bufbuild/protobuf
      ```

      ```bash Go theme={null}
      go get namespacelabs.dev/integrations github.com/golang-jwt/jwt/v4
      ```
    </CodeGroup>
  </Step>

  <Step title="Create a partner client">
    The partner client authenticates as your platform.
    It signs a short-lived partner token with your private key whenever it needs one.

    <CodeGroup>
      ```typescript TypeScript theme={null}
      import { sign } from "node:crypto";
      import { readFileSync } from "node:fs";
      import { createIAMClient } from "@namespacelabs/sdk/api/iam";
      import type { TokenSource } from "@namespacelabs/sdk/auth";

      const partnerId = "user_01abcdefghjkmnpqrstvwxyz00";
      const issuer = "https://auth.example.com";
      const keyId = "0123456789abcdef0123456789abcdef01234567";
      const privateKey = readFileSync("partner-key.pem");

      function base64url(value: object): string {
        return Buffer.from(JSON.stringify(value)).toString("base64url");
      }

      const partnerTokenSource: TokenSource = {
        async issueToken() {
          const now = Math.floor(Date.now() / 1000);
          const header = base64url({ alg: "ES256", typ: "JWT", kid: keyId });
          const claims = base64url({
            iss: issuer,
            sub: partnerId,
            aud: "namespace.so",
            iat: now,
            exp: now + 20 * 60,
          });
          const signature = sign("sha256", Buffer.from(`${header}.${claims}`), {
            key: privateKey,
            dsaEncoding: "ieee-p1363",
          });

          return `oidc_${header}.${claims}.${signature.toString("base64url")}`;
        },
      };

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

      ```go Go theme={null}
      package main

      import (
      	"context"
      	"crypto/ecdsa"
      	"fmt"
      	"log"
      	"os"
      	"time"

      	"github.com/golang-jwt/jwt/v4"
      	"google.golang.org/protobuf/encoding/protojson"
      	"namespacelabs.dev/integrations/api/iam"
      	iamv1beta "namespacelabs.dev/integrations/proto/namespace/cloud/iam/v1beta"
      )

      const (
      	partnerID = "user_01abcdefghjkmnpqrstvwxyz00"
      	issuer    = "https://auth.example.com"
      	keyID     = "0123456789abcdef0123456789abcdef01234567"
      )

      type partnerTokenSource struct {
      	privateKey *ecdsa.PrivateKey
      }

      func (p partnerTokenSource) IssueToken(ctx context.Context, minDuration time.Duration, force bool) (string, error) {
      	now := time.Now()
      	token := jwt.NewWithClaims(jwt.SigningMethodES256, jwt.RegisteredClaims{
      		Issuer:    issuer,
      		Subject:   partnerID,
      		Audience:  jwt.ClaimStrings{"namespace.so"},
      		IssuedAt:  jwt.NewNumericDate(now),
      		ExpiresAt: jwt.NewNumericDate(now.Add(20 * time.Minute)),
      	})
      	token.Header["kid"] = keyID

      	signed, err := token.SignedString(p.privateKey)
      	if err != nil {
      		return "", err
      	}

      	return "oidc_" + signed, nil
      }

      func main() {
      	ctx := context.Background()

      	pemBytes, err := os.ReadFile("partner-key.pem")
      	if err != nil {
      		log.Fatal(err)
      	}

      	privateKey, err := jwt.ParseECPrivateKeyFromPEM(pemBytes)
      	if err != nil {
      		log.Fatal(err)
      	}

      	partnerClient, err := iam.NewClient(ctx, partnerTokenSource{privateKey})
      	if err != nil {
      		log.Fatal(err)
      	}
      	defer partnerClient.Close()

      	// The Go snippets in the following steps continue here.
      }
      ```
    </CodeGroup>

    Replace the partner ID, issuer, key ID, and key file with your own. [Partner credentials](/docs/platform/authentication/partner-credentials) explains each field.
  </Step>

  <Step title="Create a tenant">
    Create a tenant for your first customer.
    `EnsureTenantForExternalAccount` links the tenant to your own ID for the customer, here `customer-1`, and returns the existing tenant if you run it again.

    <CodeGroup>
      ```typescript TypeScript theme={null}
      const { tenant } = await partnerClient.tenants.ensureTenantForExternalAccount({
        externalAccountId: "customer-1",
        visibleName: "Customer 1",
      });

      const tenantId = tenant!.id;
      console.log(tenantId);
      ```

      ```go Go theme={null}
      ensured, err := partnerClient.Tenants.EnsureTenantForExternalAccount(ctx, &iamv1beta.EnsureTenantForExternalAccountRequest{
      	ExternalAccountId: "customer-1",
      	VisibleName:       "Customer 1",
      })
      if err != nil {
      	log.Fatal(err)
      }

      tenantID := ensured.Tenant.Id
      fmt.Println(tenantID)
      ```
    </CodeGroup>

    ```text Output theme={null}
    tenant_lqrj7qre0ts32
    ```

    The tenant ID is Namespace's ID for the tenant. You use it to issue tokens for the tenant in step 5.
  </Step>

  <Step title="List your tenants">
    List the tenants your platform owns. The new tenant appears in the list.

    <CodeGroup>
      ```typescript TypeScript theme={null}
      const { tenants } = await partnerClient.tenants.listTenants({ limit: 100 });

      for (const t of tenants) {
        console.log(t.id, t.externalAccountId, t.visibleName);
      }
      ```

      ```go Go theme={null}
      list, err := partnerClient.Tenants.ListTenants(ctx, &iamv1beta.ListTenantsRequest{Limit: 100})
      if err != nil {
      	log.Fatal(err)
      }

      for _, t := range list.Tenants {
      	fmt.Println(t.Id, t.ExternalAccountId, t.VisibleName)
      }
      ```
    </CodeGroup>

    ```text Output theme={null}
    tenant_lqrj7qre0ts32 customer-1 Customer 1
    ```

    This returns the first 100 tenants. [List and find tenants](/docs/platform/tenants/list) shows how to page through more.
  </Step>

  <Step title="Issue a tenant token">
    So far, every call has acted as your platform.
    To work inside the customer's tenant, issue a tenant token for it.
    The actor ID identifies who in your system the token acts for, here a user of Customer 1.

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

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

    <Note>
      From here on, you act on Customer 1's behalf. Everything created with this token belongs to Customer 1's tenant, and no other tenant is reachable with it. The token expires after 15 minutes.
    </Note>
  </Step>

  <Step title="Create a tenant client">
    A tenant client authenticates with the tenant token.

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

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

      ```go Go theme={null}
      // At package level, next to partnerTokenSource:
      type bearerTokenSource string

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

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

  <Step title="Read the tenant's policies">
    Policies set what a tenant can use, such as how many instances it can run at once.
    The request has no tenant ID. It reads the policies of the tenant the token belongs to, which is why it needs the tenant client.

    <CodeGroup>
      ```typescript TypeScript theme={null}
      import { toJsonString } from "@bufbuild/protobuf";
      import { DescribePoliciesResponseSchema } from "@namespacelabs/sdk/proto/namespace/cloud/iam/v1beta/tenants_pb";

      const policies = await tenantClient.tenants.describePolicies({});

      console.log(toJsonString(DescribePoliciesResponseSchema, policies, { prettySpaces: 2 }));
      ```

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

      fmt.Println(protojson.Format(policies))
      ```
    </CodeGroup>

    ```json Output theme={null}
    {
      "policies": [
        {
          "policy": "namespace.cloud.compute.v1beta.UsagePolicy",
          "value": "{}"
        }
      ],
      "revision": "1"
    }
    ```

    A new tenant starts with an empty usage policy, so it has no limits of its own yet.
  </Step>
</Steps>

The tenant stays until you delete it. [Delete tenants](/docs/platform/tenants/delete) shows how.

## Next steps

<Columns cols={3}>
  <Card title="Partner and tenant clients" icon="users" href="/docs/platform/tenants/clients">
    What each client is for.
  </Card>

  <Card title="Tenant policies" icon="gauge" href="/docs/platform/tenants/policies">
    Set limits for the tenant.
  </Card>

  <Card title="Run an instance" icon="play" href="/docs/platform/instances/quickstart">
    Pass the tenant token to a Compute client to run an instance in the tenant.
  </Card>
</Columns>


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