---
title: "Authenticate"
description: "Pass credentials to a provider, and limit what they can do."
canonical_url: "https://forges.link/guides/authentication"
---
# Authenticate

> Pass credentials to a provider, and limit what they can do.

Every provider takes an `auth` option that tells it which credentials to send. The types it accepts depend on the forge, so check the [provider page](https://forges.link/providers) for yours. This guide covers the options that work the same way everywhere, and what you can do to keep a credential from doing more than you intend.

## Use a token

Most forges accept a token, which is also the simplest way to authenticate:

```ts
import { gitlab } from 'forges/gitlab'

const forge = gitlab({
  auth: { type: 'token', token: process.env.GITLAB_TOKEN! },
}).create()
```

If the token expires, as an OAuth access token does, you can pass a function instead of a string. The provider calls it before every request, so a token that you refresh in the meantime is picked up without creating a new provider:

```ts
import { github } from 'forges/github'

const forge = github({
  auth: { type: 'token', token: () => session.accessToken() },
}).create()
```

The type of authentication also decides which capabilities a provider has, so it can't change once the provider exists. When a user signs in or out, create a new provider instead.

Besides `token`, there are a few other types. Use `basic` for a username and password, and `app` for GitHub App and Cursor Origin App credentials. Tangled also accepts `app_password` and `oauth`.

## Read without credentials

If you leave out `auth`, you get an anonymous provider. It sends no credentials and can only make public reads, so writes, notifications and subscriptions all report `false` in its capabilities, as does any read that the forge only serves to signed-in users. [Check what works without credentials](https://forges.link/guides/capabilities#check-what-works-without-credentials) shows how to tell them apart:

```ts
import { github } from 'forges/github'

const publicGitHub = github({}).create()
```

## Check how a provider authenticates

When you receive a provider from somewhere else, you can find out how it authenticates. `provider.authKind` is the `auth.type` it was created with, or `'anonymous'` if it sends no credentials. `capabilities.authKinds` lists every type that the forge accepts:

```ts
const signedIn = forge.authKind !== 'anonymous'
```

## Limit a credential to reads

If a part of your program should only ever read, set `readOnly: true` on the provider. Every write then reports `false` in the capabilities and rejects with `ReadOnlyError`. This also covers `provider.request()` with any method other than `GET`, `HEAD` or `OPTIONS`, unless you declare the request as a read with `mutates: false`:

```ts
import { gitlab } from 'forges/gitlab'

const audit = gitlab({
  auth: { type: 'token', token: process.env.GITLAB_TOKEN! },
  readOnly: true,
}).create()
```

Some requests use a method that normally changes data but only read. A GraphQL query is sent as a `POST`, for instance. For these, pass `mutates: false` to `provider.request()` so the provider lets them through. On GitHub, `graphql()` needs no such option, because it reads the document to tell a query from a mutation.

<warning>

`readOnly` is a safeguard inside `forges`. It relies on what your code declares, and it doesn't restrict the permissions of the credential on the forge. To be safe, create a read-only token as well.

</warning>

## Show the scopes an operation needs

If a call fails because the token lacks a permission, it helps to tell the user which one they need. `provider.scopesFor(verb)` returns the token scopes or app permissions that an operation requires on that forge, which makes it useful for a consent screen or an error message:

```ts
const needed = forge.scopesFor('threads.merge')
```

The result can have `token`, `permissions` and `note` fields, and all of them are optional. If there is no mapping for the verb, you get an empty object.

## Authenticate as a GitHub App

To act as a GitHub App, pass the app ID, its private key and the installation to use:

```ts
const app = github({
  auth: {
    type: 'app',
    appId: 123456,
    privateKey: process.env.GITHUB_APP_PRIVATE_KEY!,
    installationId: 7890,
  },
}).create()
```

You don't have to deal with installation tokens yourself, because the provider creates them when it needs one and caches them. If your app is installed on several accounts, see the [GitHub provider page](https://forges.link/providers/github#authentication) for how to work with more than one installation.


## Sitemap

See the full [sitemap](https://forges.link/sitemap.md) for all pages.
