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);