arctic
Library for handling OAuth 2.0 with built-in providers. Light weight, fully-typed, runtime-agnostic. Built using oslo
. For a more flexible OAuth 2.0 client, see oslo/oauth2
.
npm install arctic
Providers
OAuth 2.0
See OAuth 2.0 providers for instructions.
- Apple
- Discord
- Facebook
- Github
- Google
- LinkedIn
- Twitch
OAuth 2.0 with PKCE
See OAuth 2.0 providers with PKCE for instructions.
- Line
- Microsoft Entra
- Spotify
- Twitter
OAuth 2.0 providers
Most providers require the client_id
and client_secret
. You may also optionally pass scope
. For OIDC clients, openid
and profile
scope are always included.
import { GitHub } from "arctic";
const github = new GitHub(clientId, clientSecret, {
scope: ["user:email"]
});
Some providers also require the redirect URI.
import { Google } from "arctic";
const redirectURI = "http://localhost:3000/login/google/callback";
const google = new Google(clientId, clientSecret, redirectURI);
Create authorization URL
Generate state using generateState()
and store it as a cookie. Use it to create an authorization URL with createAuthorizationURL()
and redirect the user to it.
import { generateState } from "arctic";
const state = generateState();
const url = await github.createAuthorizationURL(state);
setCookie("state", state, {
secure: true,
path: "/",
httpOnly: true,
maxAge: 60 * 10
});
return redirect(url);
Validate authorization code
Compare the state, and use validateAuthorizationCode()
to validate the authorization code. This returns an object with an access token, and a refresh token if requested. If the code is invalid, it will throw an AccessTokenRequestError
.
import { OAuth2RequestError } from "arctic";
const code = request.url.searchParams.get("code");
const state = request.url.searchParams.get("state");
const storedState = getCookie("state");
if (!code || !storedState || state !== storedState) {
throw new Error("Invalid request");
}
try {
const tokens = await github.validateAuthorizationCode(code);
} catch (e) {
if (e instanceof OAuth2RequestError) {
const { message, description, request } = e;
}
}
Other
See also:
OAuth 2.0 providers with PKCE
Most providers require the client_id
and client_secret
. You may also optionally pass scope
. For OIDC clients, openid
and profile
scope are always included.
import { GitHub } from "arctic";
const github = new GitHub(clientId, clientSecret, {
scope: ["user:email"]
});
Some providers also require the redirect URI.
import { Google } from "arctic";
const redirectURI = "http://localhost:3000/login/google/callback";
const github = new GitHub(clientId, clientSecret, redirectURI);
Create authorization URL
When using the PKCE flow, state
is not necessary. Generate a code verifier using generateCodeVerifier()
, and store it as a cookie. Use them to create an authorization URL with createAuthorizationURL()
and redirect the user to it.
import { generateState, generateCodeVerifier } from "arctic";
const codeVerifier = generateCodeVerifier();
const url = await github.createAuthorizationURL(state, codeVerifier);
setCookie("code_verifier", state, {
secure: true,
path: "/",
httpOnly: true,
maxAge: 60 * 10
});
return redirect(url);
Validate authorization code
Use validateAuthorizationCode()
to validate the authorization code with the code verifier. This returns an object with an access token, and a refresh token if requested. If the code is invalid, it will throw an AccessTokenRequestError
.
import { OAuth2RequestError } from "arctic";
const code = request.url.searchParams.get("code");
const codeVerifier = request.url.searchParams.get("code_verifier");
try {
const tokens = await github.validateAuthorizationCode(code, codeVerifier);
} catch (e) {
if (e instanceof OAuth2RequestError) {
const { request, message, description } = e;
}
}
Other
See also:
Other
Get the current user
Some providers expose getUser()
to get the current user from an access token. This will throw an RequestError
if the access token is invalid.
import { RequestError } from "arctic";
try {
const user = await github.getUser(tokens.accessToken);
} catch (e) {
if (e instanceof RequestError) {
const { request, response } = e;
}
}
Refresh access tokens
Some providers expose refreshAccessToken()
to get a new access token from a refresh token. This will throw an OAuth2RequestError
if the refresh token is invalid.
import { OAuth2RequestError } from "arctic";
try {
const tokens = await google.refreshAccessToken(refreshToken);
} catch (e) {
if (e instanceof OAuth2RequestError) {
const { request, message, description } = e;
}
}