Arctic

Generic OAuth 2.0 client

Arctic provides a generic client for OAuth 2.0 authorization code flow based on RFC 6749, RFC 7009, and RFC 7636. Please be aware that the client strictly follows the RFCs and may not work with providers that aren't spec-compliant. Some common non-compliant behaviors are:

  • Does not support HTTP Basic Authentication scheme for client authentication.
  • Returns non-400 status codes for errors.
  • Returns custom error JSON response body.

Only client password authentication is supported.

Initialization

Initialize OAuth2Client with your client ID, client password (secret), and redirect URI. clientSecret and redirectURI can be null.

import * as arctic from "arctic";

const client = new arctic.OAuth2Client(clientId, clientPassword, redirectURI);

Create authorization URL

Use OAuth2Client.createAuthorizationURL() to create an authorization URL.

import * as arctic from "arctic";

const state = arctic.generateState();
const url = client.createAuthorizationURL(authorizationEndpoint, state, scopes);

For PKCE flows, use OAuth2Client.createAuthorizationURLWithPKCE().

import * as arctic from "arctic";

const state = arctic.generateState();
const codeVerifier = arctic.generateCodeVerifier();
const url = client.createAuthorizationURLWithPKCE(
	authorizationEndpoint,
	state,
	arctic.CodeChallengeMethod.S256,
	codeVerifier,
	scopes
);

Validate authorization code

Use OAuth2Client.validateAuthorizationCode() to validate authorization codes. This returns an OAuth2Tokens instance, or throw one of OAuth2RequestError, ArcticFetchError, UnexpectedResponseError, or UnexpectedErrorResponseBodyError..

import * as arctic from "arctic";

try {
	const tokens = await client.validateAuthorizationCode(tokenEndpoint, code, null);
	const accessToken = tokens.accessToken();
} catch (e) {
	if (e instanceof arctic.OAuth2RequestError) {
		// Invalid authorization code, credentials, or redirect URI
		const code = e.code;
		// ...
	}
	if (e instanceof arctic.ArcticFetchError) {
		// Failed to call `fetch()`
		const cause = e.cause;
		// ...
	}
	// Parse error
}

Pass the code verifier for PKCE.

const tokens = await client.validateAuthorizationCode(tokenEndpoint, code, codeVerifier);

Refresh access token

Use OAuth2Client.refreshAccessToken() to refresh access tokens. This also returns an OAuth2Tokens instance and throws the same errors as OAuth2Client.validateAuthorizationCode().

import * as arctic from "arctic";

try {
	// Pass an empty `scopes` array to keep using the same scopes.
	const tokens = await client.refreshAccessToken(tokenEndpoint, refreshToken, scopes);
	const accessToken = tokens.accessToken();
} catch (e) {
	if (e instanceof arctic.OAuth2RequestError) {
		// Invalid tokens, credentials, or redirect URI
		const code = e.code;
		// ...
	}
	if (e instanceof arctic.ArcticFetchError) {
		// Failed to call `fetch()`
		const cause = e.cause;
		// ...
	}
	// Parse error
}

Revoke token

Use OAuth2.revokeToken() to revoke tokens. This also throws the same errors as OAuth2Client.validateAuthorizationCode().

import * as arctic from "arctic";

try {
	await client.revokeToken(tokenRevocationEndpoint, token);
} catch (e) {
	if (e instanceof arctic.OAuth2RequestError) {
		// Invalid tokens, credentials, or redirect URI
		const code = e.code;
		// ...
	}
	if (e instanceof arctic.ArcticFetchError) {
		// Failed to call `fetch()`
		const cause = e.cause;
		// ...
	}
	// Parse error
}