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
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"] // etc
});
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);
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);
// store state as cookie
setCookie("state", state, {
secure: true, // set to false in localhost
path: "/",
httpOnly: true,
maxAge: 60 * 10 // 10 min
});
return redirect(url);
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) {
// 400
throw new Error("Invalid request");
}
try {
const tokens = await github.validateAuthorizationCode(code);
} catch (e) {
if (e instanceof OAuth2RequestError) {
const { message, description, request } = e;
}
// unknown error
}
See also:
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"] // etc
});
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);
Generate state and code verifier using generateState()
and generateCodeVerifier()
, and store them as cookies. Use them to create an authorization URL with createAuthorizationURL()
and redirect the user to it.
import { generateState, generateCodeVerifier } from "arctic";
const state = generateState();
const codeVerifier = generateCodeVerifier();
const url = await github.createAuthorizationURL(state, codeVerifier);
// store state and code verifier as cookie
setCookie("state", state, {
secure: true, // set to false in localhost
path: "/",
httpOnly: true,
maxAge: 60 * 10 // 10 min
});
setCookie("code_verifier", state, {
secure: true, // set to false in localhost
path: "/",
httpOnly: true,
maxAge: 60 * 10 // 10 min
});
return redirect(url);
Compare the state, and 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 state = request.url.searchParams.get("state");
const codeVerifier = request.url.searchParams.get("code_verifier");
const storedState = getCookie("state");
if (!code || !codeVerifier || state !== storedState) {
// 400
throw new Error("Invalid request");
}
try {
const tokens = await github.validateAuthorizationCode(code, codeVerifier);
} catch (e) {
if (e instanceof OAuth2RequestError) {
// see https://oslo.js.org/reference/oauth2/OAuth2RequestError/
const { request, message, description } = e;
}
// unknown error
}
See also:
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) {
// get fetch Request and Response
const { request, response } = e;
}
// unknown error
}
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) {
// see https://oslo.js.org/reference/oauth2/OAuth2RequestError/
const { request, message, description } = e;
}
// unknown error
}