OAuth 2.0 with PKCE
Most providers require a client ID, client secret, and redirect URI. The API is nearly identical across providers but always check each provider's guide before implementing.
import { Google } from "arctic";
const google = new Google(clientId, clientSecret, redirectURI);
Create authorization URL
Generate a state and code verifier using generateState() and generateCodeVerifier(). Use them to create an authorization URL with createAuthorizationURL(), store the state and code verifier as cookies, and redirect the user to the authorization url.
import { generateState, generateCodeVerifier } from "arctic";
const state = generateState();
const codeVerifier = generateCodeVerifier();
const scopes = ["user:email", "repo"];
const url = google.createAuthorizationURL(state, codeVerifier, scopes);
// store state as cookie
setCookie("state", state, {
secure: true, // set to false in localhost
path: "/",
httpOnly: true,
maxAge: 60 * 10 // 10 min
});
// store code verifier as cookie
setCookie("code_verifier", codeVerifier, {
secure: true, // set to false in localhost
path: "/",
httpOnly: true,
maxAge: 60 * 10 // 10 min
});
return redirect(url);
Validate authorization code
Compare the state, and use validateAuthorizationCode() to validate the authorization code and code verifier. This returns an OAuth2Tokens, or throw one of OAuth2RequestError, ArcticFetchError, or a standard Error (parse errors).
import { OAuth2RequestError, ArcticFetchError } from "arctic";
const code = request.url.searchParams.get("code");
const state = request.url.searchParams.get("state");
const storedState = getCookie("state");
const storedCodeVerifier = getCookie("code_verifier");
if (code === null || storedState === null || state !== storedState || storedCodeVerifier === null) {
// 400
throw new Error("Invalid request");
}
try {
const tokens = await google.validateAuthorizationCode(code, storedCodeVerifier);
const accessToken = tokens.accessToken();
} catch (e) {
if (e instanceof OAuth2RequestError) {
// Invalid authorization code, credentials, or redirect URI
const code = e.code;
// ...
}
if (e instanceof ArcticFetchError) {
// Failed to call `fetch()`
const cause = e.cause;
// ...
}
// Parse error
}
Calling OAuth2Tokens.accessToken() for example parses the response and returns the access_token field. If it doesn't exist, it will throw a parse Error. See each provider's guides for the actual return values.
const accessToken = tokens.accessToken();
const accessTokenExpiresInSeconds = tokens.accessTokenExpiresInSeconds();
const accessTokenExpiresAt = tokens.accessTokenExpiresAt();
const refreshToken = tokens.refreshToken();
const idToken = tokens.idToken();
Arctic provides decodeIdToken() for decoding the token's payload.
const claims = decodeIdToken(idToken);