mirror of
https://github.com/CompassConnections/Compass.git
synced 2026-05-18 13:47:08 -04:00
Add google Auth
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -47,3 +47,4 @@ notebooks
|
||||
martin
|
||||
|
||||
/src/generated/prisma
|
||||
*.db
|
||||
|
||||
89
docs/google-oauth-setup.md
Normal file
89
docs/google-oauth-setup.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# Google OAuth Setup Guide
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. A Google Cloud Platform (GCP) account
|
||||
2. A GCP project with the Google+ API enabled
|
||||
3. OAuth consent screen configured
|
||||
|
||||
## Step 1: Create OAuth Credentials
|
||||
|
||||
1. Go to the [Google Cloud Console](https://console.cloud.google.com/)
|
||||
2. Select your project or create a new one
|
||||
3. Navigate to "APIs & Services" > "Credentials"
|
||||
4. Click "Create Credentials" and select "OAuth client ID"
|
||||
|
||||
## Step 2: Configure OAuth Consent Screen
|
||||
|
||||
1. If you haven't configured the consent screen, click "Configure Consent Screen"
|
||||
2. Choose "External" user type and click "Create"
|
||||
3. Fill in the required app information:
|
||||
- App name (e.g., "My App")
|
||||
- User support email (your email)
|
||||
- Developer contact information (your email)
|
||||
4. Click "Save and Continue"
|
||||
5. Skip the "Scopes" step (we'll use the default scopes)
|
||||
6. Add test users (your email) if you're in testing mode
|
||||
7. Click "Save and Continue"
|
||||
|
||||
## Step 3: Create OAuth Client ID
|
||||
|
||||
1. Go back to "Credentials"
|
||||
2. Click "Create Credentials" > "OAuth client ID"
|
||||
3. Select "Web application" as the application type
|
||||
4. Enter a name (e.g., "Web Client")
|
||||
5. Under "Authorized JavaScript origins", add:
|
||||
- `http://localhost:3000`
|
||||
- `http://localhost:3001`
|
||||
6. Under "Authorized redirect URIs", add:
|
||||
- `http://localhost:3000/api/auth/callback/google`
|
||||
- `http://localhost:3001/api/auth/callback/google`
|
||||
7. Click "Create"
|
||||
|
||||
## Step 4: Set Up Environment Variables
|
||||
|
||||
Create or update your `.env.local` file with the following variables:
|
||||
|
||||
```env
|
||||
NEXTAUTH_URL=http://localhost:3000
|
||||
NEXTAUTH_SECRET=your-secret-key-here # Generate with: openssl rand -base64 32
|
||||
GOOGLE_CLIENT_ID=your-google-client-id
|
||||
GOOGLE_CLIENT_SECRET=your-google-client-secret
|
||||
DATABASE_URL=file:./dev.db
|
||||
```
|
||||
|
||||
## Step 5: Update Database Schema
|
||||
|
||||
Run the following command to update your database schema:
|
||||
|
||||
```bash
|
||||
npx prisma db push
|
||||
```
|
||||
|
||||
## Step 6: Restart Your Development Server
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## Testing Google OAuth
|
||||
|
||||
1. Visit the login page at `http://localhost:3000/login`
|
||||
2. Click the "Sign in with Google" button
|
||||
3. You should be redirected to Google's sign-in page
|
||||
4. After signing in, you'll be redirected back to your app
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- If you get a "redirect_uri_mismatch" error, double-check the Authorized Redirect URIs in your Google Cloud Console
|
||||
- Make sure the Google+ API is enabled in your GCP project
|
||||
- Check your browser's console and network tab for any errors
|
||||
- Ensure your `.env.local` file has the correct values and is in the root of your project
|
||||
|
||||
## Production Deployment
|
||||
|
||||
When deploying to production:
|
||||
1. Update the `NEXTAUTH_URL` to your production URL
|
||||
2. Add your production domain to the Authorized JavaScript origins and redirect URIs in the Google Cloud Console
|
||||
3. Ensure your production environment has the same environment variables set
|
||||
4. Consider using a more secure database than SQLite for production
|
||||
83
scripts/setup-env.js
Executable file
83
scripts/setup-env.js
Executable file
@@ -0,0 +1,83 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const readline = require('readline').createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
// Check if .env.local exists, if not create it
|
||||
const envPath = path.join(__dirname, '../.env.local');
|
||||
|
||||
const questions = [
|
||||
{
|
||||
name: 'NEXTAUTH_SECRET',
|
||||
message: 'Enter a secure random string for NEXTAUTH_SECRET (you can generate one with `openssl rand -base64 32`): ',
|
||||
validate: input => input.length >= 32 || 'Secret must be at least 32 characters long'
|
||||
},
|
||||
{
|
||||
name: 'NEXTAUTH_URL',
|
||||
message: 'Enter your NEXTAUTH_URL (e.g., http://localhost:3000): ',
|
||||
default: 'http://localhost:3000',
|
||||
validate: input => input.startsWith('http') || 'Must be a valid URL starting with http:// or https://'
|
||||
},
|
||||
{
|
||||
name: 'GOOGLE_CLIENT_ID',
|
||||
message: 'Enter your Google OAuth Client ID: ',
|
||||
validate: input => !!input || 'Google Client ID is required'
|
||||
},
|
||||
{
|
||||
name: 'GOOGLE_CLIENT_SECRET',
|
||||
message: 'Enter your Google OAuth Client Secret: ',
|
||||
validate: input => !!input || 'Google Client Secret is required'
|
||||
}
|
||||
];
|
||||
|
||||
async function setupEnv() {
|
||||
console.log('Setting up your environment variables...\n');
|
||||
|
||||
let envVars = [];
|
||||
|
||||
for (const q of questions) {
|
||||
const answer = await new Promise((resolve) => {
|
||||
const ask = () => {
|
||||
readline.question(q.message, (input) => {
|
||||
const value = input.trim() || q.default || '';
|
||||
if (q.validate) {
|
||||
const validation = q.validate(value);
|
||||
if (validation !== true) {
|
||||
console.log(validation);
|
||||
return ask();
|
||||
}
|
||||
}
|
||||
resolve(value);
|
||||
});
|
||||
};
|
||||
ask();
|
||||
});
|
||||
|
||||
envVars.push(`${q.name}=${answer}`);
|
||||
}
|
||||
|
||||
// Add any additional environment variables
|
||||
envVars.push('DATABASE_URL=file:./dev.db');
|
||||
|
||||
// Write to .env.local
|
||||
fs.writeFileSync(envPath, envVars.join('\n') + '\n');
|
||||
|
||||
console.log('\n✅ Environment variables have been saved to .env.local');
|
||||
console.log('\nNext steps:');
|
||||
console.log('1. Run `npx prisma db push` to update your database schema');
|
||||
console.log('2. Restart your development server with `npm run dev`\n');
|
||||
|
||||
readline.close();
|
||||
}
|
||||
|
||||
// Create .env.local if it doesn't exist
|
||||
if (!fs.existsSync(envPath)) {
|
||||
setupEnv();
|
||||
} else {
|
||||
console.log('.env.local already exists. Please update it with the following variables:');
|
||||
console.log(questions.map(q => `${q.name}=`).join('\n'));
|
||||
console.log('\nYou can also delete .env.local and run this script again to create it interactively.');
|
||||
readline.close();
|
||||
}
|
||||
@@ -24,7 +24,7 @@ export default function DashboardPage() {
|
||||
}
|
||||
|
||||
if (status === 'unauthenticated') {
|
||||
router.push('/login');
|
||||
// router.push('/login');
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
28
src/auth.ts
28
src/auth.ts
@@ -1,5 +1,7 @@
|
||||
import type { NextAuthConfig } from 'next-auth';
|
||||
import Credentials from 'next-auth/providers/credentials';
|
||||
import Google from 'next-auth/providers/google';
|
||||
import { PrismaAdapter } from '@auth/prisma-adapter';
|
||||
import { prisma } from './lib/prisma';
|
||||
import { compare } from 'bcryptjs';
|
||||
|
||||
@@ -37,7 +39,21 @@ export const authConfig = {
|
||||
return session;
|
||||
},
|
||||
},
|
||||
adapter: PrismaAdapter(prisma),
|
||||
providers: [
|
||||
Google({
|
||||
clientId: process.env.GOOGLE_CLIENT_ID,
|
||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
||||
allowDangerousEmailAccountLinking: true,
|
||||
profile(profile) {
|
||||
return {
|
||||
id: profile.sub,
|
||||
name: profile.name,
|
||||
email: profile.email,
|
||||
image: profile.picture,
|
||||
};
|
||||
},
|
||||
}),
|
||||
Credentials({
|
||||
name: 'Credentials',
|
||||
credentials: {
|
||||
@@ -80,4 +96,16 @@ export const authConfig = {
|
||||
},
|
||||
secret: process.env.NEXTAUTH_SECRET,
|
||||
trustHost: true,
|
||||
debug: process.env.NODE_ENV === 'development',
|
||||
cookies: {
|
||||
sessionToken: {
|
||||
name: `__Secure-next-auth.session-token`,
|
||||
options: {
|
||||
httpOnly: true,
|
||||
sameSite: 'lax',
|
||||
path: '/',
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
},
|
||||
},
|
||||
},
|
||||
} satisfies NextAuthConfig;
|
||||
|
||||
@@ -5,7 +5,7 @@ declare global {
|
||||
var prisma: PrismaClient | undefined;
|
||||
}
|
||||
|
||||
const globalForPrisma = global as unknown as { prisma: PrismaClient };
|
||||
const globalForPrisma = globalThis as unknown as { prisma: PrismaClient };
|
||||
|
||||
export const prisma = globalForPrisma.prisma || new PrismaClient();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user