@jakobinn/expo-auth-utils
v2.0.0
Published
Secure Google OAuth for web applications using the PKCE flow.
Downloads
5
Maintainers
Readme
@jakobinn/expo-auth-utils
A secure, reusable NPM package for handling Google OAuth in web applications using the PKCE (Proof Key for Code Exchange) flow.
Features
- Secure PKCE Flow: Implements the OAuth 2.0 PKCE extension for enhanced security
- TypeScript Support: Full TypeScript definitions included
- Browser Compatible: Works in all modern browsers with Web Crypto API support
- Session Storage: Automatically manages state during OAuth redirects
- CSRF Protection: Built-in state parameter validation
- Zero Dependencies: Lightweight package with no external dependencies
Installation
npm install @jakobinn/expo-auth-utilsQuick Start
1. Initialize the OAuth Client
import { GoogleWebAppOAuth } from '@jakobinn/expo-auth-utils';
const oauth = new GoogleWebAppOAuth({
clientId: 'your-google-client-id.apps.googleusercontent.com',
redirectUri: 'https://yourapp.com/auth/callback',
scopes: ['openid', 'profile', 'email'],
});
### 2. Start the Sign-In Process
```typescript
// This will redirect the user to Google's login page
await oauth.signIn();3. Handle the Callback
On your callback page (e.g., /auth/callback):
import { GoogleWebAppOAuth } from '@jakobinn/expo-auth-utils';
const oauth = new GoogleWebAppOAuth({
clientId: 'your-google-client-id.apps.googleusercontent.com',
redirectUri: 'https://yourapp.com/auth/callback',
scopes: ['openid', 'profile', 'email'],
});
try {
const { code, codeVerifier } = oauth.handleRedirect();
// Send code and codeVerifier to your server for token exchange
const response = await fetch('/api/auth/google/exchange', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ code, codeVerifier }),
});
const { token, user } = await response.json();
// Handle successful authentication
} catch (error) {
// Handle authentication errors
console.error('OAuth error:', error.message);
}
## Complete Example
### Login Page (`/login`)
```tsx
"use client";
import { GoogleWebAppOAuth } from '@jakobinn/expo-auth-utils';
const oauth = new GoogleWebAppOAuth({
clientId: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID!,
redirectUri: 'http://localhost:3000/auth/callback',
scopes: ['openid', 'profile', 'email'],
});
export default function LoginPage() {
const handleLogin = async () => {
try {
await oauth.signIn(); // Redirects to Google
} catch (error) {
console.error("OAuth initiation failed", error);
}
};
return (
<div>
<h1>Sign In</h1>
<button onClick={handleLogin}>
Sign in with Google
</button>
</div>
);
}
### Callback Page (`/auth/callback`)
```tsx
"use client";
import { useEffect } from 'react';
import { GoogleWebAppOAuth } from '@jakobinn/expo-auth-utils';
const oauth = new GoogleWebAppOAuth({
clientId: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID!,
redirectUri: 'http://localhost:3000/auth/callback',
scopes: ['openid', 'profile', 'email'],
});
async function exchangeCodeOnServer(code: string, codeVerifier: string) {
const response = await fetch('/api/auth/google/exchange', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ code, codeVerifier }),
});
if (!response.ok) {
throw new Error('Failed to exchange code for token');
}
return response.json();
}
export default function AuthCallbackPage() {
useEffect(() => {
const processAuth = async () => {
try {
const { code, codeVerifier } = oauth.handleRedirect();
console.log("Received code, exchanging for token...");
const { jwt, user } = await exchangeCodeOnServer(code, codeVerifier);
console.log("Authentication successful!", { jwt, user });
// Redirect to dashboard or set user state
window.location.href = '/dashboard';
} catch (error) {
console.error("OAuth callback failed:", error);
window.location.href = '/login?error=' + encodeURIComponent(error.message);
}
};
processAuth();
}, []);
return <div>Processing authentication...</div>;
}API Reference
GoogleWebAppOAuth
Constructor
new GoogleWebAppOAuth(config: WebGoogleOAuthConfig)Configuration
interface WebGoogleOAuthConfig {
clientId: string; // Your Google OAuth client ID
redirectUri: string; // Your app's callback URL
scopes: string[]; // Array of OAuth scopes
}Methods
signIn(): Promise<void>
Initiates the OAuth flow by redirecting the user to Google's authorization page.
handleRedirect(): AuthResult
Processes the OAuth callback and returns the authorization code and PKCE verifier.
interface AuthResult {
code: string; // Authorization code from Google
codeVerifier: string; // PKCE code verifier for server exchange
}Security Features
- PKCE Flow: Prevents authorization code interception attacks
- State Parameter: CSRF protection with cryptographically secure random state
- Session Storage: Temporary storage that's cleared after use
- Automatic Cleanup: Stored data is automatically cleared after callback processing
Browser Compatibility
This package requires browsers that support:
- Web Crypto API (
crypto.subtle) sessionStorageURLSearchParamsTextEncoder
Most modern browsers (Chrome 60+, Firefox 55+, Safari 11+, Edge 79+) support these features.
Development
# Install dependencies
npm install
# Build the package
npm run build
# Development mode with watch
npm run dev
# Type checking
npm run type-checkLicense
MIT
