Citra
A curated collection of OAuth 2.0 provider configurations, each bundled with the correct endpoints and request details. Ready-to-use foundation for secure authentication in TypeScript applications.
View on GitHubWhy Citra?
Interchangeability
All OAuth 2.0 providers follow the same flow. Citra abstracts this into a unified interface.
Type Safety
TypeScript generics and type guards catch configuration mistakes at compile time.
Inspired by Arctic, Citra reduces boilerplate and minimizes integration errors by enforcing a uniform configuration approach.
Installation
bun install citraGetting Started
Citra uses strong TypeScript typing to help you build OAuth clients safely. Each provider includes its own typed configuration schema, ensuring you can't pass unsupported parameters or omit required ones.
1import { createOAuth2Client } from 'citra';
2
3const googleClient = await createOAuth2Client('google', {
4 clientId: 'YOUR_CLIENT_ID',
5 clientSecret: 'YOUR_CLIENT_SECRET',
6 redirectUri: 'https://yourapp.com/auth/callback'
7});Building the Authorization URL
Generate a fully customized authorization URL for redirecting users to the provider's login page. Every option is strongly typed and context-aware, with full control over PKCE, scopes, and provider-specific parameters.
1const currentState = generateState();
2const codeVerifier = generateCodeVerifier();
3const authUrl = await googleClient.createAuthorizationUrl({
4 codeVerifier,
5 scope: ['profile', 'openid'],
6 searchParams: [
7 ['access_type', 'offline'],
8 ['prompt', 'consent']
9 ],
10 state: currentState
11});
12
13// Store state and PKCE verifier in HttpOnly cookies
14const headers = new Headers();
15headers.set('Location', authUrl.toString());
16headers.append(
17 'Set-Cookie',
18 `oauth_state=${currentState}; HttpOnly; Path=/; Secure; SameSite=Lax`
19);
20headers.append(
21 'Set-Cookie',
22 `pkce_code_verifier=${codeVerifier}; HttpOnly; Path=/; Secure; SameSite=Lax`
23);Handling the Callback
Exchange the authorization code and PKCE verifier for an OAuth2 token response:
1// Parse callback URL parameters
2const request = new Request('https://yourapp.com/auth/callback');
3const params = new URL(request.url).searchParams;
4const code = params.get('code');
5const callback_state = params.get('state');
6
7// Retrieve stored state and code verifier from cookies
8const cookieHeader = request.headers.get('cookie') ?? '';
9const cookies = cookieHeader.trim()
10 ? Object.fromEntries(
11 cookieHeader
12 .split('; ')
13 .filter(c => c.includes('='))
14 .map(c => c.split('='))
15 )
16 : {};
17
18const stored_state = cookies['oauth_state'];
19const codeVerifier = cookies['pkce_code_verifier'];
20
21// Validate required cookies are present
22if (!stored_state) {
23 throw new Error('Missing oauth_state cookie');
24}
25if (!codeVerifier) {
26 throw new Error('Missing pkce_code_verifier cookie');
27}
28
29// Validate state to prevent CSRF attacks
30if (!callback_state || callback_state !== stored_state) {
31 throw new Error('Invalid state mismatch');
32}
33
34// Validate code is present
35if (!code) {
36 throw new Error('Authorization code not found');
37}
38
39// Exchange authorization code for tokens
40const tokenResponse = await googleClient.validateAuthorizationCode({
41 code,
42 codeVerifier
43});Fetching the User Profile
Exchange the access token for user information:
1// Get the access token from server session
2const session = await getSession(request);
3const accessToken = session.accessToken;
4
5const profile = await googleClient.fetchUserProfile(accessToken);
6console.log(profile);Token Management
If supported by the provider, you can refresh and revoke tokens:
1// Get the refresh token from server session
2const session = await getSession(request);
3const refreshToken = session.refreshToken;
4
5if (refreshToken) {
6 const newTokens = await googleClient.refreshAccessToken(refreshToken);
7}1// Get the access token from server session
2const session = await getSession(request);
3const accessToken = session.accessToken;
4
5if (isRevocableProviderOption('google')) {
6 await googleClient.revokeToken(accessToken);
7}Supported Providers
Citra supports 66 OAuth 2.0 providers:
Facebook
LinkedIn
Mercado Libre
Okta
osu!
Polar
Polar Access Link
Polar Team Pro
Slack
Synology
Twitter / X
Withings
Zoom