Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 34 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
# @aieng-auth

> Production-ready Google OAuth SSO for all your web applications
Production-ready Google OAuth SSO for Vector internal web applications.

Seamless single sign-on across multiple apps using **one shared Google OAuth client**. Perfect for organizations that want to add authentication to internal tools with minimal configuration.
## Key Features

## 🎯 Key Features
- Share one Google OAuth client across multiple apps for seamless SSO
- Client-side OAuth with PKCE security (no backend required)
- Domain restriction by email (e.g., @vectorinstitute.ai)
- React hooks and components with full TypeScript support

- **Single OAuth Client, Multiple Apps** - All your apps share one Google OAuth client for seamless SSO
- **3-Step Integration** - Install, wrap, configure. That's it.
- **Domain Restriction** - Restrict access to specific email domains (e.g., @vectorinstitute.ai)
- **Zero Backend Required** - Pure client-side OAuth with PKCE security
- **Framework Support** - React hooks + components (Next.js coming soon)
- **TypeScript First** - Fully typed for excellent DX
## Packages

## 📦 Packages
- `@aieng-auth/core` - Framework-agnostic OAuth client with PKCE
- `@aieng-auth/react` - React hooks and components (AuthProvider, useAuth, ProtectedRoute)
- `demo-react` - Demo application

- **`@aieng-auth/core`** ✅ - Framework-agnostic OAuth client with PKCE
- **`@aieng-auth/react`** ✅ - React hooks and components (AuthProvider, useAuth, ProtectedRoute)
- **`demo-react`** ✅ - Live demo application

## 🚀 Quick Start
## Quick Start

### 1. Install

Expand Down Expand Up @@ -68,7 +64,7 @@ function MyComponent() {
}
```

## 🏗️ Architecture: Single OAuth Client Model
## Architecture

```
┌─────────────────────────────────────────────┐
Expand Down Expand Up @@ -96,28 +92,22 @@ function MyComponent() {
Seamless SSO across all apps
```

**For Developers**: Adding auth to a new app is simple:
All apps share one OAuth client. To add auth to a new app:

1. Get the shared client ID from your admin
2. Ask admin to register your redirect URI
3. Install package and configure (2 env vars)
4. Done!

## 🔧 Setup Google OAuth
2. Ask admin to add your redirect URI to the OAuth client
3. Install and configure with environment variables

### One-Time Admin Setup
## Setup Google OAuth

1. Go to [Google Cloud Console](https://console.cloud.google.com/)
2. Create a project or select existing
3. Enable Google+ API
4. Create OAuth 2.0 credentials:
- Application type: **Web application**
- Authorized redirect URIs: Add all your app callback URLs
5. Copy the Client ID
### Admin Setup (One-Time)

### Per-App Setup
1. Create OAuth 2.0 credentials in [Google Cloud Console](https://console.cloud.google.com/)
2. Set application type to Web application
3. Add all app callback URLs to Authorized redirect URIs
4. Share the Client ID with developers

Each developer just needs:
### Developer Setup

```bash
# .env
Expand All @@ -126,41 +116,27 @@ VITE_REDIRECT_URI=http://localhost:3000/callback
VITE_ALLOWED_DOMAINS=vectorinstitute.ai
```

## 📖 Demo
## Demo

See the live demo in `apps/demo-react`:
Run the demo app:

```bash
cd apps/demo-react
cp .env.example .env
# Add your Google OAuth Client ID
cp .env.example .env # Add your Google OAuth Client ID
pnpm dev
```

## 🔒 Security
## Security

- **PKCE (Proof Key for Code Exchange)** - Prevents authorization code interception
- **SHA-256 Challenge** - Cryptographically secure
- **Memory Storage (default)** - XSS-immune token storage
- **Domain Validation** - Restrict access by email domain
- **Automatic Token Refresh** - Seamless session management
- PKCE (Proof Key for Code Exchange) with SHA-256 challenge
- Memory storage (XSS-immune)
- Domain validation for email restrictions
- Automatic token refresh

## 🛠️ Development
## Development

```bash
# Install dependencies
pnpm install

# Build all packages
pnpm build

# Run tests
pnpm test

# Run demo
cd apps/demo-react && pnpm dev
pnpm install # Install dependencies
pnpm build # Build all packages
pnpm test # Run tests
```

## 📝 License

MIT
22 changes: 5 additions & 17 deletions apps/demo-nextjs/src/app/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ export default async function DashboardPage() {
return (
<div className="container">
<div className="header">
<h1>📊 Dashboard</h1>
<p>Protected page - server-side authentication</p>
<h1>Dashboard</h1>
<p>Protected page with server-side authentication</p>
</div>

<div className="nav">
Expand All @@ -27,13 +27,12 @@ export default async function DashboardPage() {
</div>

<div className="card">
<h2>Welcome, {user?.name}!</h2>
<h2>Welcome, {user?.name}</h2>
<p style={{ color: '#666', marginBottom: '1.5rem' }}>
This page is protected by server-side middleware. You can only see it because you&apos;re
authenticated.
This page is protected by server-side middleware.
</p>

<div className="status success">Server-Side Authentication Active</div>
<div className="status success">Server-side authentication active</div>

<div style={{ marginTop: '1.5rem' }}>
<h3>Session Information</h3>
Expand All @@ -42,17 +41,6 @@ export default async function DashboardPage() {
</div>
</div>
</div>

<div className="card">
<h3>💡 Next.js Benefits</h3>
<ul style={{ marginLeft: '1.5rem', lineHeight: '1.8', color: '#666' }}>
<li>✅ Tokens never exposed to browser JavaScript</li>
<li>✅ HTTP-only cookies prevent XSS attacks</li>
<li>✅ Server Components can check auth without client JS</li>
<li>✅ Middleware can protect entire route groups</li>
<li>✅ Automatic session refresh on the server</li>
</ul>
</div>
</div>
);
}
20 changes: 10 additions & 10 deletions apps/demo-nextjs/src/app/globals.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600;700&display=swap');

* {
box-sizing: border-box;
padding: 0;
Expand All @@ -11,12 +13,10 @@ body {
}

body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
font-family: 'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
background: linear-gradient(135deg, #EB088A 0%, #313CFF 100%);
min-height: 100vh;
padding: 2rem;
}
Expand Down Expand Up @@ -74,7 +74,7 @@ body {
}

.button {
background: #667eea;
background: #EB088A;
color: white;
border: none;
border-radius: 8px;
Expand All @@ -86,22 +86,22 @@ body {
}

.button:hover {
background: #5568d3;
background: #d10779;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
box-shadow: 0 4px 12px rgba(235, 8, 138, 0.3);
}

.button.secondary {
background: #6c757d;
background: #000000;
}

.button.secondary:hover {
background: #5a6268;
background: #333333;
}

.info-box {
background: #f8f9fa;
border-left: 4px solid #667eea;
border-left: 4px solid #EB088A;
padding: 1rem;
margin: 1rem 0;
border-radius: 4px;
Expand Down
50 changes: 21 additions & 29 deletions apps/demo-nextjs/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,23 @@ export default async function HomePage() {
return (
<div className="container">
<div className="header">
<h1>🔐 Google OAuth SSO Demo (Next.js)</h1>
<p>Server-side sessions with App Router</p>
<h1>Google OAuth SSO Demo (Next.js)</h1>
<p>Server-side authentication with App Router</p>
</div>

{!isAuthenticated ? (
<>
<div className="card">
<h2>Welcome!</h2>
<h2>Welcome</h2>
<p style={{ marginBottom: '1.5rem', color: '#666' }}>
This demo shows server-side OAuth with Next.js App Router. Unlike the React SPA,
tokens are stored securely in HTTP-only cookies.
Server-side OAuth with HTTP-only cookies for secure token storage.
</p>

<div className="info-box">
<strong>✨ Next.js Integration:</strong>
<strong>Features:</strong>
<ul style={{ marginLeft: '1.5rem', marginTop: '0.5rem' }}>
<li>Server-side session management</li>
<li>HTTP-only cookies (XSS immune)</li>
<li>HTTP-only cookies (XSS protection)</li>
<li>API routes for OAuth flow</li>
<li>Middleware for protected routes</li>
</ul>
Expand All @@ -40,30 +39,26 @@ export default async function HomePage() {

<div className="grid">
<div className="feature-card">
<h3>🔒 More Secure</h3>
<p>Tokens never touch the browser. Stored in HTTP-only cookies on the server.</p>
<h3>Secure Storage</h3>
<p>Tokens stored in HTTP-only cookies, never exposed to browser.</p>
</div>

<div className="feature-card">
<h3>⚡ SSR Ready</h3>
<p>
Authentication works with Server Components. No client-side JavaScript required.
</p>
<h3>Server Components</h3>
<p>Authentication integrated with Next.js Server Components.</p>
</div>

<div className="feature-card">
<h3>🎯 Production Ready</h3>
<p>Built for production with session management and automatic token refresh.</p>
<h3>Auto Refresh</h3>
<p>Session management with automatic token refresh.</p>
</div>
</div>
</>
) : (
<>
<div className="card">
<h2>✅ Authenticated</h2>
<p style={{ marginBottom: '1.5rem', color: '#666' }}>
You&apos;re signed in with server-side session management!
</p>
<h2>Authenticated</h2>
<p style={{ marginBottom: '1.5rem', color: '#666' }}>Server-side session active.</p>

<div className="user-info">
{user?.picture && (
Expand Down Expand Up @@ -93,23 +88,20 @@ export default async function HomePage() {

<div style={{ display: 'flex', gap: '1rem', marginTop: '1.5rem' }}>
<Link href="/dashboard">
<button className="button">Go to Dashboard</button>
<button className="button">Dashboard</button>
</Link>
<LogoutButton />
</div>
</div>

<div className="card">
<h3>🎨 How This Works</h3>
<h3>Authentication Flow</h3>
<ul style={{ marginLeft: '1.5rem', lineHeight: '1.8', color: '#666' }}>
<li>User clicks &quot;Sign in with Google&quot;</li>
<li>Server initiates OAuth flow with PKCE</li>
<li>
Google redirects to <code>/api/auth/callback</code>
</li>
<li>Server exchanges code for tokens</li>
<li>Tokens stored in encrypted session cookie</li>
<li>Server components can access session directly</li>
<li>Server initiates OAuth with PKCE</li>
<li>Redirect to Google for authorization</li>
<li>Exchange code for tokens at callback</li>
<li>Store tokens in encrypted session cookie</li>
<li>Server components access session directly</li>
</ul>
</div>
</>
Expand Down
4 changes: 2 additions & 2 deletions apps/demo-react/SETUP_GCLOUD.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ open "https://console.cloud.google.com/apis/credentials?project=coderd"
2. Select **"Internal"** (for @vectorinstitute.ai users only)
- This restricts access to your Google Workspace organization
3. Fill in required fields:
- **App name**: `AIEng Auth Demo`
- **App name**: `aieng-auth demo`
- **User support email**: Your email
- **Developer contact**: Your email
4. Click **"Save and Continue"**
Expand All @@ -33,7 +33,7 @@ open "https://console.cloud.google.com/apis/credentials/oauthclient?project=code
```

1. **Application type**: Select **"Web application"**
2. **Name**: `AIEng Auth Demo`
2. **Name**: `aieng-auth demo`
3. **Authorized JavaScript origins**:
- Add: `http://localhost:3000`
4. **Authorized redirect URIs**:
Expand Down
2 changes: 1 addition & 1 deletion apps/demo-react/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>CyberArk Auth Demo</title>
<title>aieng-auth demo</title>
</head>
<body>
<div id="root"></div>
Expand Down
Loading
Loading