Skip to content
twitch.apiv2.0

Authentication

Tokens at a glance

The two kinds of Twitch tokens, the flow that fits your application, and what the library does with tokens so that you do not have to.

Every request to the Twitch API carries an access token. There are two kinds: an app access token, which identifies your application, and a user access token, which a user grants to your application so that it can act for them. This page tells you which one you need, how to get it, and what the client does with it afterwards.

With a client ID and a client secret, the client requests the app token by itself. Registering a user token unlocks the endpoints that act for that user.

import { Twitch } from "@ix-xs/twitch.api";
const twitch = new Twitch({
clientId: process.env.TWITCH_CLIENT_ID!,
clientSecret: process.env.TWITCH_CLIENT_SECRET!,
});
// Public data: the app token is requested on this first call.
const user = await twitch.users.getByLogin("twitchdev");
// Acting for someone: register their token once.
const broadcaster = await twitch.auth.addUser({ accessToken, refreshToken });
await twitch.polls.create({ title: "Next game?", choices: ["Hades", "Celeste"], duration: 120 });
App access tokenUser access token
IdentifiesYour applicationOne user who authorized your application
Obtained withThe client ID and the client secretA flow in which the user approves a list of scopes
Good forPublic data (users.get, streams.get, games.top, search.channels), webhook and conduit subscriptions, the few endpoints reserved to applications (conduits.list, users.authorization)Everything that reads private data or acts for the user (users.me, streams.followed, polls.create, channels.update), and WebSocket subscriptions
ScopesNoneThe ones the user granted, listed in Scopes
RenewalRequested again with the client secretRefreshed with its refresh token
Rate limitOne bucket for the applicationOne bucket per user

Each endpoint accepts an app token, a user token, or either one. The reference page of every method says which under “Token”, for example users.me. You never pass the token yourself: the client reads what the endpoint accepts and picks one. On an endpoint that accepts either kind, { as: "app" } forces the app token. The rules are in Acting as a user.

A flow is the way a user hands a token to your application. Pick it from where your code runs.

Your applicationFlowClient secretHow
Web serverAuthorization codeRequiredAuthorization code flow
CLI, desktop app, bot on your own machineDevice codeNot neededDevice code flow
Browser-only app, with no backendDevice code, or implicitMust not be thereDevice code flow, or the implicit flow below
Backend job with no userNone, the app token is enoughRequiredBuild the client with clientId and clientSecret

A bot that always runs as the same account is the second row: sign in once with the device code flow, keep the token in a store, and the bot starts without asking again. See Storing tokens.

The implicit flow returns an access token in the fragment of the redirect URL, with no refresh token. authorizeUrl builds its URL when you set responseType to "token", and addUser registers the token it returns.

const url = twitch.auth.authorizeUrl({
redirectUri: "https://example.com/",
scopes: ["user:read:follows"],
responseType: "token",
state,
});
// Back on your page: #access_token=...&scope=...&state=...
const fragment = new URLSearchParams(location.hash.slice(1));
if (fragment.get("state") !== state) throw new Error("State mismatch");
const user = await twitch.auth.addUser({ accessToken: fragment.get("access_token")! });

Such a token cannot be renewed. When it expires the user is dropped and has to sign in again, which is why the device code flow is the better choice when you can show a code.

Once the client knows your credentials and your users, tokens need no code of yours.

  • App token on demand. The first call that needs it requests it, and calls made at the same moment share that one request. It is kept in memory, requested again 60 seconds before it expires, and requested again if Twitch rejects it. The request itself is retried after a network failure or a 5xx.
  • Refresh before expiry. A user token that expires within 60 seconds is refreshed before the request is sent, provided it has a refresh token. Calls that need the same refresh share one request to Twitch.
  • Refresh after a real 401. When Twitch answers 401, the client asks Twitch whether the token is still valid. A dead token is renewed and the call is sent once more. A valid token means the 401 is about something else, and the error reaches you as is. Errors has the details.
  • Hourly validation. Twitch requires applications that keep user sessions to validate their tokens every hour. A timer does it from the moment a user is registered, and it never keeps the process alive. Turn it off with validateTokens: false.
  • Persistence. With a tokens store, users are restored on first use and every new or refreshed token is written back. Without one, tokens live in memory.
  • Scope checks. A user token that lacks the scope an endpoint needs fails with a TwitchScopeError before any request is sent.
  • A dead token is reported once. When a token cannot be renewed, the user is removed and the tokenInvalid event fires. Managing users shows how to react.

A client built with only a clientId is a public client. It cannot request an app token, and it does not need one for most things.

import { Twitch } from "@ix-xs/twitch.api";
const twitch = new Twitch({ clientId: process.env.TWITCH_CLIENT_ID! });
await twitch.auth.addUser({ accessToken, refreshToken });
// Accepts either kind of token: the registered user's token is used.
const streams = await twitch.streams.get({ game_id: "509658" }).take(10);
What you callWithout a client secret
The device code flow, refreshing, validating, revokingWorks
An endpoint that accepts either kind of tokenUses the token of the registered user when exactly one is registered, or of the one you name with { as }. With several users and nobody named, it fails with a TwitchAuthError that asks you to choose
An endpoint reserved to applications, webhooks, conduitsFails with a TwitchAuthError saying it “needs an app access token, which requires a clientSecret”
twitch.auth.exchangeCode()Fails with A clientSecret is required to exchange an authorization code.

When a token comes from somewhere else and you do not want the client to manage it, pass it for one call with the token request option. It is sent as is: no refresh, no scope check, no choice of user.

const me = await twitch.users.me({ token: accessToken });

To read the app token the client holds, for another tool that needs one, call twitch.auth.appToken(). It resolves with a valid token and requests a new one when needed.