<!-- llms.txt: https://workos.com/llms.txt -->

# Credentials

Credentials allow you to make API calls to a connected third-party service on behalf of a user. For OAuth integrations, WorkOS handles token refresh automatically, so you always receive a valid, non-expired token. For API-key integrations, WorkOS returns the stored secret.

## Get an access token for a connected account

Fetches a valid OAuth access token for a user's connected account. WorkOS automatically handles token refresh, ensuring you always receive a valid, non-expired token.

:::code-group

```bash language="curl" title="Request" tab="1"
curl --request POST \
  --url "https://api.workos.com/data-integrations/github/token" \
  --header "Authorization: Bearer sk_example_123456789" \
  --header "Content-Type: application/json" \
  -d @- <<'BODY'
    {
        "user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT",
        "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT"
    }
BODY
```

```js language="js" title="Request" tab="1"
import { WorkOS } from '@workos-inc/node';

const workos = new WorkOS('sk_example_123456789');

const token = await workos.pipes.getAccessToken({
  userId: 'user_01EHZNVPK3SFK441A1RGBFSHRT',
  organizationId: 'org_01EHZNVPK3SFK441A1RGBFSHRT',
  provider: 'github',
});
```

```rb language="ruby" title="Request" tab="1"
require "workos"

WorkOS.configure do |config|
  config.api_key = "sk_example_123456789"
end

WorkOS.client.pipes.create_data_integration_token(
  slug: "github",
  user_id: "user_01EHZNVPK3SFK441A1RGBFSHRT"
)
```

```py language="python" title="Request" tab="1"
from workos import WorkOSClient

client = WorkOSClient(api_key="sk_example_123456789", client_id="client_123456789")

client.pipes.create_data_integration_token(
    slug="github", user_id="user_01EHZNVPK3SFK441A1RGBFSHRT"
)
```

```go language="go" title="Request" tab="1"
package main

import (
	"context"

	"github.com/workos/workos-go/v10"
)

func main() {
	client := workos.NewClient("sk_example_123456789")

	_, err := client.Pipes().CreateDataIntegrationToken(context.Background(), "github", &workos.PipesCreateDataIntegrationTokenParams{
		UserID: "user_01EHZNVPK3SFK441A1RGBFSHRT",
	})
	if err != nil {
		panic(err)
	}
}
```

```php language="php" title="Request" tab="1"
<?php

use WorkOS\WorkOS;

$workos = new WorkOS(
    apiKey: "sk_example_123456789",
    clientId: "client_123456789",
);

$workos
    ->pipes()
    ->createDataIntegrationToken(
        slug: "github",
        userId: "user_01EHZNVPK3SFK441A1RGBFSHRT",
    );
```

```java language="java" title="Request" tab="1"
import com.workos.WorkOS;
import com.workos.pipes.PipesApi.CreateDataIntegrationTokenOptions;

WorkOS workos = new WorkOS("sk_example_123456789");

CreateDataIntegrationTokenOptions options = CreateDataIntegrationTokenOptions.builder()
                                                .userId("user_01EHZNVPK3SFK441A1RGBFSHRT")
                                                .build();

workos.pipes.createDataIntegrationToken("github", options);
```

```cs language="dotnet" title="Request" tab="1"
using WorkOS;

var client = new WorkOSClient(new WorkOSOptions {
    ApiKey = "sk_example_123456789",
    ClientId = "client_123456789",
});

await client.Pipes.CreateDataIntegrationTokenAsync("github", new PipesCreateDataIntegrationTokenOptions {
    UserId = "user_01EHZNVPK3SFK441A1RGBFSHRT",
});
```

```rust language="rust" title="Request" tab="1"
use workos::Client;
use workos::pipes::CreateDataIntegrationTokenParams;

#[tokio::main]
async fn main() -> Result<(), workos::Error> {
    let client = Client::builder()
        .api_key("sk_example_123456789")
        .client_id("client_123456789")
        .build();

    let _result = client
        .pipes()
        .create_data_integration_token(
            "github",
            CreateDataIntegrationTokenParams {
                user_id: "user_01EHZNVPK3SFK441A1RGBFSHRT".into(),
                ..Default::default()
            }
        )
        .await?;

    Ok(())
}
```

```json language="json" title="Response" tab="2"
{
  "active": true,
  "access_token": {
    "object": "access_token",
    "access_token": "gho_16C7e42F292c6912E7710c838347Ae178B4a",
    "expires_at": "2025-12-31T23:59:59.000Z",
    "scopes": [
      "repo",
      "user:email"
    ],
    "missing_scopes": []
  }
}
```

:::

## Vend credentials for a connected account

Returns credentials for a user's connected account. Branches on the installation's `auth_method`: OAuth installations return an access token (refreshed if needed); API-key installations return the stored secret; client-credentials installations return a minted access token with its `expires_at`, `scopes`, `missing_scopes`, and a `metadata` object of non-sensitive fields captured from the provider's token response, such as the host to send subsequent API requests to.

For client credentials, `expires_at` is a cache lease rather than a provider guarantee. Some providers omit `expires_in` from their token response; when that happens, WorkOS synthesizes a one-hour expiry so the token is re-minted before it is likely stale. Until the lease is within five minutes of expiring, vending returns the cached token, so a token the provider invalidated early keeps coming back. To force a fresh mint, [update the connected account](https://workos.com/docs/reference/pipes/connected-account/update) with `access_token` set to `null`, or with `expires_at` set to the current time, and then vend again.

The scopes a client-credentials token carries are granted by the connected organization's own client application, so the scopes configured on the integration are requests or defaults. `missing_scopes` lists configured scopes the provider reported as not granted; when a provider's token response omits `scope` altogether, the requested scopes are recorded as granted, so `missing_scopes` can be empty even when the organization's app withheld some.

:::code-group

```bash language="curl" title="Request" tab="1"
curl --request POST \
  --url "https://api.workos.com/data-integrations/github/credentials" \
  --header "Authorization: Bearer sk_example_123456789" \
  --header "Content-Type: application/json" \
  -d @- <<'BODY'
    {
        "user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT"
    }
BODY
```

```js language="js" title="Request" tab="1"
import { WorkOS } from '@workos-inc/node';

const workos = new WorkOS('sk_example_123456789');

const credential = await workos.pipes.createDataIntegrationCredential({
  slug: 'github',
  userId: 'user_01EHZNVPK3SFK441A1RGBFSHRT',
});
```

```rb language="ruby" title="Request" tab="1"
require "workos"

WorkOS.configure do |config|
  config.api_key = "sk_example_123456789"
end

WorkOS.client.pipes.create_data_integration_credential(
  slug: "github",
  user_id: "user_01EHZNVPK3SFK441A1RGBFSHRT"
)
```

```py language="python" title="Request" tab="1"
from workos import WorkOSClient

client = WorkOSClient(api_key="sk_example_123456789", client_id="client_123456789")

client.pipes.create_data_integration_credential(
    slug="github", user_id="user_01EHZNVPK3SFK441A1RGBFSHRT"
)
```

```go language="go" title="Request" tab="1"
package main

import (
	"context"

	"github.com/workos/workos-go/v10"
)

func main() {
	client := workos.NewClient("sk_example_123456789")

	_, err := client.Pipes().CreateDataIntegrationCredential(context.Background(), "github", &workos.PipesCreateDataIntegrationCredentialParams{
		UserID: "user_01EHZNVPK3SFK441A1RGBFSHRT",
	})
	if err != nil {
		panic(err)
	}
}
```

```php language="php" title="Request" tab="1"
<?php

use WorkOS\WorkOS;

$workos = new WorkOS(
    apiKey: "sk_example_123456789",
    clientId: "client_123456789",
);

$workos
    ->pipes()
    ->createDataIntegrationCredential(
        slug: "github",
        userId: "user_01EHZNVPK3SFK441A1RGBFSHRT",
    );
```

```java language="java" title="Request" tab="1"
import com.workos.WorkOS;
import com.workos.pipes.PipesApi.CreateDataIntegrationCredentialOptions;

WorkOS workos = new WorkOS("sk_example_123456789");

CreateDataIntegrationCredentialOptions options =
    CreateDataIntegrationCredentialOptions.builder()
        .userId("user_01EHZNVPK3SFK441A1RGBFSHRT")
        .build();

workos.pipes.createDataIntegrationCredential("github", options);
```

```cs language="dotnet" title="Request" tab="1"
using WorkOS;

var client = new WorkOSClient(new WorkOSOptions {
    ApiKey = "sk_example_123456789",
    ClientId = "client_123456789",
});

await client.Pipes.CreateDataIntegrationCredentialAsync("github", new PipesCreateDataIntegrationCredentialOptions {
    UserId = "user_01EHZNVPK3SFK441A1RGBFSHRT",
});
```

```rust language="rust" title="Request" tab="1"
use workos::Client;
use workos::pipes::CreateDataIntegrationCredentialParams;

#[tokio::main]
async fn main() -> Result<(), workos::Error> {
    let client = Client::builder()
        .api_key("sk_example_123456789")
        .client_id("client_123456789")
        .build();

    let _result = client
        .pipes()
        .create_data_integration_credential(
            "github",
            CreateDataIntegrationCredentialParams {
                user_id: "user_01EHZNVPK3SFK441A1RGBFSHRT".into(),
                ..Default::default()
            }
        )
        .await?;

    Ok(())
}
```

```json language="json" title="Response" tab="2"
{
  "active": true,
  "credential": {
    "object": "credential",
    "auth_method": "oauth",
    "value": "gho_16C7e42F292c6912E7710c838347Ae178B4a",
    "expires_at": "2025-12-31T23:59:59.000Z",
    "scopes": [
      "repo",
      "user:email"
    ],
    "missing_scopes": []
  }
}
```

:::

### data_integration

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `object` | "data_integration" | Yes | Distinguishes the Data Integration object. |
| `id` | string | Yes | Unique identifier of the Data Integration. |
| `slug` | string | Yes | The provider slug for this Data Integration. |
| `integration_type` | string | Yes | The integration type derived from the provider. |
| `description` | string | No | An optional description of the Data Integration. |
| `enabled` | boolean | Yes | Whether the Data Integration is enabled. |
| `state` | "valid" \| "invalid" \| "requested" | Yes | The state of the Data Integration. |
| `scopes` | string[] | No | The OAuth scopes configured for the Data Integration. `null` when the provider's configured scopes are used. |
| `redirect_uri` | string | Yes | The OAuth redirect URI to register with the provider when configuring the custom application. Empty for `api_key` and `client_credentials` integrations, which run no authorization redirect. |
| `auth_methods` | ("oauth" \| "api_key" \| "client_credentials")[] | Yes | How accounts authenticate with the provider for this Data Integration. |
| `credentials` | object | No | The integration-level OAuth app credentials. `null` for `api_key` and `client_credentials` integrations, which hold no integration-level credentials (secrets are installed per-tenant). |
| `installation` | object | No | The tenant installation created when an API key was supplied at creation time; `null` otherwise. Not populated on list/get responses. |
| `config` | object | Yes | Provider-specific config values set on the Data Integration (e.g. a Snowflake `account`), keyed by config field. Only fields the provider declares are accepted. |
| `custom_provider` | object | No | The OAuth definition when this is a custom provider; `null` for built-in providers. |
| `created_at` | string | Yes | An ISO 8601 timestamp. |
| `updated_at` | string | Yes | An ISO 8601 timestamp. |

### POST /data-integrations/{slug}/token

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `user_id` | string | Yes | A [User](/reference/authkit/user) identifier. The user must have an active connection to the specified integration. |
| `organization_id` | string | No | An [Organization](/reference/organization) identifier. Optional parameter to scope the integration lookup to a specific organization. |

#### Parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `slug` | string | Yes | The identifier of the integration. |

#### Returns

| Field | Type | Description |
| --- | --- | --- |
| `active` | boolean | Indicates whether the access token is valid and ready for use, or if reauthorization is required. |
| `access_token` | object | The [access token](/reference/pipes/access-token) object, present when `active` is `true`. |
| `error` | "needs_reauthorization" \| "not_installed" | - `"not_installed"`: The user does not have the integration installed. `"needs_reauthorization"`: The user needs to reauthorize the integration. |

### POST /data-integrations/{slug}/credentials

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `user_id` | string | Yes | A [User](/reference/authkit/user) identifier. |
| `organization_id` | string | No | An [Organization](/reference/organization) identifier. Optional parameter to scope the connection to a specific organization. |

#### Parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `slug` | string | Yes | The identifier of the integration. |

#### Returns

| Field | Type | Description |
| --- | --- | --- |
| `active` | boolean | Indicates credentials are available. |
| `credential` | object | The credential object containing the vended secret. |
| `error` | "not_installed" \| "needs_reauthorization" | The reason credentials are unavailable. Additional values may be added in the future; handle unknown values gracefully. `"not_installed"`: The user does not have the integration installed. `"needs_reauthorization"`: The user needs to reauthorize the integration. |