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

# Session Tokens

> Generate scoped session tokens from your backend to securely control access to StackOne APIs

Session tokens provide temporary, policy-restricted access to StackOne APIs without exposing your API keys in frontend code or external systems.

## Overview

Session tokens let you:

* **Restrict API access** - Define exactly which endpoints and operations the token can access
* **Secure frontend integrations** - Use tokens in client-side code without exposing API keys
* **Scope by account** - Limit tokens to specific linked accounts or providers
* **Control duration** - Set expiration times for token validity

Generate session tokens server-side using your [API key](/guides/api-keys), then pass them to frontend code, webhooks, or third-party systems.

## How Session Tokens Work

<Steps>
  <Step title="Create token server-side">
    Your backend calls the StackOne API with your API key and a policy definition
  </Step>

  <Step title="Receive scoped token">
    StackOne returns a session token restricted by your policy
  </Step>

  <Step title="Use token in restricted context">
    Pass the token to frontend code, webhooks, or external systems where API keys shouldn't be exposed
  </Step>

  <Step title="Token enforces policy">
    The session token only allows the operations defined in your policy
  </Step>
</Steps>

## Policy-Based Restrictions

Session tokens use the `scopes` field to define granular access control policies. Each permission rule uses glob patterns to match resources.

### Permission Structure

```json theme={null}
{
  "scopes": {
    "accountIds": ["acc_123", "acc_456"],
    "permissions": [
      {
        "id": "read-users",
        "effect": "allow",
        "tools": ["read-*", "list-*"]
      },
      {
        "id": "specific-accounts",
        "effect": "allow",
        "accounts": ["acc_*_production"]
      }
    ]
  }
}
```

### Permission Fields

| Field       | Type              | Description                                                  |
| ----------- | ----------------- | ------------------------------------------------------------ |
| `id`        | string            | Unique identifier for the permission rule                    |
| `effect`    | "allow" \| "deny" | Whether to allow or deny matched resources                   |
| `tools`     | string\[]         | Glob patterns for tool names (e.g., `"read-*"`, `"*-users"`) |
| `operation` | string\[]         | Glob patterns for operation names                            |
| `accounts`  | string\[]         | Glob patterns for account IDs                                |

<Note>
  Each permission rule must specify **exactly one** of: `tools`, `operation`, or `accounts`. All rules are deny-by-default - you must explicitly allow access.
</Note>

### Glob Pattern Examples

```javascript theme={null}
// Allow all read operations
{ "effect": "allow", "tools": ["read-*"] }

// Allow specific operations
{ "effect": "allow", "tools": ["read-users", "read-departments"] }

// Deny write operations
{ "effect": "deny", "tools": ["write-*", "delete-*"] }

// Complex patterns
{ "effect": "allow", "tools": ["{read,list}-{users,posts}"] }

// Account patterns
{ "effect": "allow", "accounts": ["acc_*_production"] }
```

### Session Configuration

Additional fields control session behavior:

| Field        | Type                   | Default      | Description                                       |
| ------------ | ---------------------- | ------------ | ------------------------------------------------- |
| `expires_in` | number                 | 1800         | Token validity in seconds                         |
| `provider`   | string                 | -            | Restrict to specific provider (e.g., "bamboohr")  |
| `account_id` | string                 | -            | Limit access to a single account                  |
| `shared`     | boolean                | true         | Whether account can be used by multiple end users |
| `type`       | "test" \| "production" | "production" | Test accounts auto-expire after 90 days           |
| `metadata`   | object                 | -            | Custom metadata (max 1MB)                         |

<Warning>
  Policies are defined when creating the session token. Once created, a token's permissions cannot be expanded - you must generate a new token with broader permissions.
</Warning>

## Creating Session Tokens

### API Endpoint

Create session tokens via the `POST /sessions` endpoint:

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    import { StackOne } from "@stackone/stackone-client-ts";

    const stackOne = new StackOne({
      security: {
        username: process.env.STACKONE_API_KEY,
        password: "",
      },
    });

    // Create session with scoped permissions
    const result = await stackOne.sessions.create({
      tenantId: "customer-123",
      tenantName: "Acme Inc",
      endUserId: "user@example.com",
      provider: "bamboohr",
      expiresIn: 3600, // 1 hour
      scopes: {
        permissions: [
          {
            id: "read-only",
            effect: "allow",
            tools: ["read-*", "list-*"]
          }
        ]
      }
    });

    const token = result.sessionToken.token;
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    from stackone_client import StackOne

    client = StackOne(
        api_key_auth=os.environ["STACKONE_API_KEY"]
    )

    # Create session with scoped permissions
    result = client.sessions.create(
        tenant_id="customer-123",
        tenant_name="Acme Inc",
        end_user_id="user@example.com",
        provider="bamboohr",
        expires_in=3600,  # 1 hour
        scopes={
            "permissions": [
                {
                    "id": "read-only",
                    "effect": "allow",
                    "tools": ["read-*", "list-*"]
                }
            ]
        }
    )

    token = result.session_token.token
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST https://api.stackone.com/sessions \
      -H "Authorization: Basic $(echo -n 'v1.eu1.xxx:' | base64)" \
      -H "Content-Type: application/json" \
      -d '{
        "tenant_id": "customer-123",
        "tenant_name": "Acme Inc",
        "end_user_id": "user@example.com",
        "provider": "bamboohr",
        "expires_in": 3600,
        "scopes": {
          "permissions": [
            {
              "id": "read-only",
              "effect": "allow",
              "tools": ["read-*", "list-*"]
            }
          ]
        }
      }'
    ```
  </Tab>
</Tabs>

### Common Use Cases

<AccordionGroup>
  <Accordion title="Read-only access to all tools">
    ```json theme={null}
    {
      "scopes": {
        "permissions": [
          {
            "id": "read-only",
            "effect": "allow",
            "tools": ["read-*", "list-*", "get-*"]
          }
        ]
      }
    }
    ```
  </Accordion>

  <Accordion title="Access to specific accounts only">
    ```json theme={null}
    {
      "scopes": {
        "accountIds": ["acc_123", "acc_456"],
        "permissions": [
          {
            "id": "allow-all",
            "effect": "allow",
            "tools": ["*"]
          }
        ]
      }
    }
    ```
  </Accordion>

  <Accordion title="Allow reads, deny writes">
    ```json theme={null}
    {
      "scopes": {
        "permissions": [
          {
            "id": "deny-writes",
            "effect": "deny",
            "tools": ["write-*", "update-*", "delete-*"]
          },
          {
            "id": "allow-reads",
            "effect": "allow",
            "tools": ["*"]
          }
        ]
      }
    }
    ```
  </Accordion>
</AccordionGroup>

## Using Session Tokens

After creating a session token, use it in place of your API key for authentication:

```bash theme={null}
# Using API key
curl -X GET https://api.stackone.com/accounts \
  -H "Authorization: Basic $(echo -n 'v1.eu1.xxx:' | base64)"

# Using session token
curl -X GET https://api.stackone.com/accounts \
  -H "Authorization: Bearer SESSION_TOKEN_HERE"
```

<Tip>
  Session tokens use Bearer authentication (`Authorization: Bearer TOKEN`) while API keys use Basic authentication. This makes them easy to identify and rotate independently.
</Tip>

## Managing Session Tokens

### List Sessions

Retrieve all active session tokens:

```bash theme={null}
curl -X GET https://api.stackone.com/sessions \
  -H "Authorization: Basic $(echo -n 'v1.eu1.xxx:' | base64)"
```

### Get Session Details

Retrieve information about a specific session:

```bash theme={null}
curl -X GET https://api.stackone.com/sessions/{session_id} \
  -H "Authorization: Basic $(echo -n 'v1.eu1.xxx:' | base64)"
```

### Update Session Permissions

Modify the scopes of an existing session:

```bash theme={null}
curl -X PATCH https://api.stackone.com/sessions/{session_id} \
  -H "Authorization: Basic $(echo -n 'v1.eu1.xxx:' | base64)" \
  -H "Content-Type: application/json" \
  -d '{
    "scopes": {
      "permissions": [
        {
          "id": "updated-permissions",
          "effect": "allow",
          "tools": ["read-*"]
        }
      ]
    }
  }'
```

### Revoke Session

Immediately invalidate a session token:

```bash theme={null}
curl -X DELETE https://api.stackone.com/sessions/{session_id} \
  -H "Authorization: Basic $(echo -n 'v1.eu1.xxx:' | base64)"
```

<Warning>
  Revoking a session immediately invalidates the token. Any API calls using that token will fail with a 401 error.
</Warning>

## Customizing the Hub Behavior

<Snippet file="guides/hub-customization.mdx" />
