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

# Authenticate with Namespace

> Use workload identity federation, local credentials, and explicit token sources with the TypeScript Compute SDK.

Use workload identity federation for CI/CD and other automated workloads that can obtain an OIDC token. Use `nsc login` for local development, or provide an explicit token source when the default credential resolution does not fit your environment.

## Workload identity federation

Federation lets an external workload exchange its OIDC identity for short-lived, scoped Namespace credentials. Prefer this approach for automated workloads instead of storing a shared, long-lived token.

Federation happens before the TypeScript SDK starts. The SDK does not exchange third-party OIDC tokens directly. A provider integration or the Namespace CLI establishes the Namespace credential, then `createComputeClient()` loads it through the default credential resolution.

The general flow is:

1. Configure a Namespace trust relationship that restricts the accepted OIDC issuer, subject, audience, and grants.
2. Obtain an OIDC token from the workload's identity provider.
3. Exchange that token for short-lived Namespace credentials.
4. Start the TypeScript application and create a client without an explicit `tokenSource`.

<Info>
  Applications running inside a Namespace workload already receive a workload credential. `createComputeClient()` discovers it automatically through `NSC_TOKEN_FILE` or `/var/run/nsc/token.json`, so no external exchange step is needed.
</Info>

### Exchange an OIDC token

Configure a [trust relationship](/docs/reference/cli/auth-trust-relationships-add), obtain the provider's OIDC token, and exchange it before starting the application:

```bash {1-3} theme={null}
nsc auth exchange-oidc-token \
  --token "$OIDC_TOKEN" \
  --tenant_id "$NAMESPACE_WORKSPACE_ID"
node dist/manage-instances.js
```

The exchange stores a short-lived Namespace credential in the standard Namespace token configuration, where `loadDefaults()` can find it.

### Provider-specific setup

See the federation guides for [OpenID Connect](/docs/federation/openid), [GitHub Actions](/docs/federation/github-actions), [CircleCI](/docs/federation/circleci), [Google Cloud](/docs/federation/gcp), [AWS](/docs/federation/aws), and [RWX](/docs/federation/rwx). These guides cover obtaining the provider token and configuring trust with Namespace; the SDK consumes the resulting Namespace credential in the same way for every provider.

## Local development with `nsc login`

For local, interactive development, [install the Namespace CLI](/docs/reference/cli/installation) and [authenticate in the browser](/docs/reference/cli/login):

```bash theme={null}
nsc login
```

`nsc login` is the short alias for `nsc auth login`. Both open a browser where you select the workspace to log in to.

The SDK reads the credentials written by `nsc login` from the platform-specific user configuration directory. You do not need to load them explicitly:

```typescript {3} theme={null}
import { createComputeClient } from "@namespacelabs/sdk/api/compute";

const client = createComputeClient();
const instances = await client.compute.listInstances({});
```

## Default credential resolution

`createComputeClient()` uses `loadDefaults` when `tokenSource` is omitted. Credentials are resolved in this order:

1. The token file named by `NSC_TOKEN_FILE`.
2. The workload token at `/var/run/nsc/token.json`, when that file exists.
3. The current user's Namespace token file.

## `loadDefaults()`

Loads the first available token source using the default resolution order above.

<h3 id="loaddefaults-example">
  Example
</h3>

Pass the function itself to defer file access until the client first needs a token:

```typescript {1,5} theme={null}
import { loadDefaults } from "@namespacelabs/sdk/auth";
import { createComputeClient } from "@namespacelabs/sdk/api/compute";

const client = createComputeClient({
  tokenSource: loadDefaults,
});
```

You can also call and await `loadDefaults()` to load credentials immediately.

<h3 id="loaddefaults-api-reference">
  API reference
</h3>

```typescript theme={null}
loadDefaults(): Promise<TokenSource>
```

<h4 id="loaddefaults-arguments-and-options">
  Arguments and options
</h4>

This function does not accept arguments.

<h4 id="loaddefaults-return-value">
  Return value
</h4>

Returns a promise that resolves to the first available `TokenSource`.

***

## `loadUserToken()`

Loads credentials for the user who ran `nsc login`. Use this when an application must not fall back to workload credentials.

<h3 id="loadusertoken-example">
  Example
</h3>

```typescript {1,5} theme={null}
import { loadUserToken } from "@namespacelabs/sdk/auth";
import { createComputeClient } from "@namespacelabs/sdk/api/compute";

const client = createComputeClient({
  tokenSource: loadUserToken,
});
```

The provider is evaluated lazily. Pass `await loadUserToken()` instead when you want missing or invalid credentials to fail during client setup.

<h3 id="loadusertoken-api-reference">
  API reference
</h3>

```typescript theme={null}
loadUserToken(): Promise<TokenSource>
```

<h4 id="loadusertoken-arguments-and-options">
  Arguments and options
</h4>

This function does not accept arguments.

<h4 id="loadusertoken-return-value">
  Return value
</h4>

Returns a promise that resolves to the current user's `TokenSource`.

***

## `loadWorkloadToken()`

Loads a workload bearer token from `NSC_TOKEN_FILE`, or from `/var/run/nsc/token.json` when the environment variable is unset. It does not fall back to user credentials.

<h3 id="loadworkloadtoken-example">
  Example
</h3>

```typescript {1,5} theme={null}
import { loadWorkloadToken } from "@namespacelabs/sdk/auth";
import { createComputeClient } from "@namespacelabs/sdk/api/compute";

const client = createComputeClient({
  tokenSource: loadWorkloadToken,
});
```

Workload token files must contain a `bearer_token`. Workload bearer tokens are returned directly and are not refreshed through a user session.

<h3 id="loadworkloadtoken-api-reference">
  API reference
</h3>

```typescript theme={null}
loadWorkloadToken(): Promise<TokenSource>
```

<h4 id="loadworkloadtoken-arguments-and-options">
  Arguments and options
</h4>

This function does not accept arguments.

<h4 id="loadworkloadtoken-return-value">
  Return value
</h4>

Returns a promise that resolves to a workload `TokenSource`.

***

## `fromBearerToken()`

Creates a token source from an existing bearer token. Use this when another trusted component supplies the credential.

<h3 id="frombearertoken-example">
  Example
</h3>

```typescript {1,5} theme={null}
import { fromBearerToken } from "@namespacelabs/sdk/auth";
import { createComputeClient } from "@namespacelabs/sdk/api/compute";

const client = createComputeClient({
  tokenSource: fromBearerToken(process.env.NAMESPACE_TOKEN!),
});
```

The SDK does not renew an explicitly supplied bearer token. The application is responsible for supplying a token that remains valid for its operations.

<Warning>
  Prefer workload identity federation when the environment supports OIDC. If federation is unavailable, use a scoped, expiring [revokable token](/docs/reference/cli/token-create) and keep it out of source control.
</Warning>

<h3 id="frombearertoken-api-reference">
  API reference
</h3>

```typescript theme={null}
fromBearerToken(token: string): TokenSource
```

<h4 id="frombearertoken-arguments-and-options">
  Arguments and options
</h4>

<ResponseField name="token" type="string" required>
  The bearer token used to authenticate Namespace requests.
</ResponseField>

<h4 id="frombearertoken-return-value">
  Return value
</h4>

Returns a `TokenSource` that issues the supplied bearer token.

## `TokenSource`

A token source issues a bearer token with at least the requested remaining lifetime.

```typescript theme={null}
interface TokenSource {
  issueToken(minDuration: number, force?: boolean): Promise<string>;
}
```

<ResponseField name="minDuration" type="number" required>
  The requested minimum remaining token lifetime in milliseconds.
</ResponseField>

<ResponseField name="force" type="boolean">
  Requests a fresh token instead of a cached token. A custom source should honor this when it can refresh credentials.
</ResponseField>

`ComputeClientOpts.tokenSource` accepts either a `TokenSource` or a zero-argument function that returns one, synchronously or asynchronously. The SDK invokes provider functions on first use and retries resolution on a later request if the provider rejects.

The client keeps issued tokens in memory and reuses a token while its JWT `exp` claim satisfies the requested lifetime. Tokens without an `exp` claim are treated as non-expiring. Concurrent requests that need a token share a compatible in-flight issuance request. Compute RPCs request at least five minutes of remaining validity.

User credentials created by `nsc login` include a session credential. The SDK uses it to issue short-lived bearer tokens and refreshes them before they have too little validity for an operation. Explicit and workload bearer tokens have no session-based refresh.

***

## `bearerAuthInterceptor()`

Create a Connect interceptor that authenticates compute RPCs with tokens from a `TokenSource`. Use it when supplying a custom transport through `ComputeClientOpts.transport`.

<h3 id="bearerauthinterceptor-example">
  Example
</h3>

When `ComputeClientOpts.transport` is set, the SDK uses that Connect transport as-is and ignores `region` and `tokenSource`. The transport is then responsible for authentication, so add `bearerAuthInterceptor()` to it:

```typescript {6-12} theme={null}
import { createConnectTransport } from "@connectrpc/connect-node";
import { bearerAuthInterceptor } from "@namespacelabs/sdk/api";
import { loadDefaults } from "@namespacelabs/sdk/auth";
import { createComputeClient } from "@namespacelabs/sdk/api/compute";

const tokenSource = await loadDefaults();
const transport = createConnectTransport({
  httpVersion: "1.1",
  baseUrl: "https://us.compute.namespaceapis.com",
  useBinaryFormat: false,
  interceptors: [bearerAuthInterceptor(tokenSource)],
});

const client = createComputeClient({ transport });
```

This is the same transport the SDK builds for you when you pass `region` instead.

<h3 id="bearerauthinterceptor-api-reference">
  API reference
</h3>

```typescript theme={null}
bearerAuthInterceptor(source: TokenSourceInput, minDuration?: number): Interceptor
```

<h4 id="bearerauthinterceptor-arguments-and-options">
  Arguments and options
</h4>

<ResponseField name="source" type="TokenSourceInput" required>
  A `TokenSource`, or a zero-argument function that returns one synchronously or asynchronously. The interceptor wraps it with the SDK's in-memory token cache. Passing a source already wrapped by the SDK is a no-op.
</ResponseField>

<ResponseField name="minDuration" type="number" default="300000">
  The minimum remaining token validity requested for every RPC, in milliseconds. The default is the SDK-wide five-minute minimum.
</ResponseField>

<h4 id="bearerauthinterceptor-return-value">
  Return value
</h4>

Returns a Connect `Interceptor` that obtains a token before each request and adds it as an `Authorization: Bearer` header. Valid tokens are reused, and concurrent requests share a compatible in-flight issuance request.

The interceptor does not refresh a token and retry a request after the server rejects its authentication. The resulting Connect error is returned to the caller.

Omitting the interceptor from a custom transport leaves compute RPCs unauthenticated.

## Authentication errors

`loadDefaults()` and `loadUserToken()` reject with `NotLoggedInError` when the user token file is missing. Prompt the user to run `nsc login` or handle the error by name:

```typescript {5-7} theme={null}
import { NotLoggedInError, loadUserToken } from "@namespacelabs/sdk/auth";

try {
  await loadUserToken();
} catch (error) {
  if (error instanceof NotLoggedInError) {
    console.error("Run `nsc login` and try again.");
  } else {
    throw error;
  }
}
```

A malformed token file surfaces as its underlying file or JSON error when it is named by `NSC_TOKEN_FILE`, or when you call `loadUserToken()` or `loadWorkloadToken()` directly. `loadDefaults()` is more forgiving: it ignores any failure while accessing or loading the standard workload token at `/var/run/nsc/token.json` and falls back to the user token, so a corrupt file at that path is not reported.

Token issuance failures surface as their underlying errors, and rejected RPC authentication surfaces as a Connect error with code `Unauthenticated`.

## Related documentation

<Columns cols={2}>
  <Card title="Compute Client" icon="plug" href="/docs/reference/typescript-sdk/compute/compute-client">
    Configure authentication, region, and transport.
  </Card>

  <Card title="Create and manage instances" icon="server" href="/docs/reference/typescript-sdk/compute/manage">
    Create, inspect, extend, suspend, and destroy instances.
  </Card>
</Columns>
