-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathauth.config.ts
119 lines (108 loc) · 3.38 KB
/
auth.config.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import 'server-only';
import { PrismaAdapter } from '@auth/prisma-adapter';
import { type NextAuthConfig } from 'next-auth';
import Credentials from 'next-auth/providers/credentials';
import Github from 'next-auth/providers/github';
import Google from 'next-auth/providers/google';
import Resend from 'next-auth/providers/resend';
import { db } from '@/lib/db';
import { getHashedUserIpFromHeaders } from '@/lib/nextjs/headers';
import { VerifiedCredentialsUserSchema } from '@/schemas';
import type { AdapterUser, VerificationToken } from '@auth/core/adapters';
/**
* Custom Auth.js adapter extending PrismaAdapter
* 1. CreateVerificationToken with IP tracking, rate limit
* 2. Custom user creation logic with default name
*/
const adapter = {
...PrismaAdapter(db),
/**
* Creates a verification token with IP tracking
* Used when sending magic links
*
* @note If it fails, the email will still be sent, a bug, or intended? Did not bother much.
* @note Remove id from the return object to match PrismaAdapter original patterns, we do not have id tho, currently.
*/
async createVerificationToken(data: VerificationToken): Promise<VerificationToken & { hashedIp: string }> {
const hashedIp = await getHashedUserIpFromHeaders();
const token = await db.verificationToken.create({
data: {
identifier: data.identifier,
token: data.token,
expires: data.expires,
hashedIp: hashedIp ?? 'nobueno',
},
});
if ('id' in token) {
delete (token as any).id;
}
return token;
},
// Follow PrismaAdapter pattern of removing id
createUser: (data: AdapterUser) => {
const userData = {
...data,
name: data.name || 'your pretty fake name',
};
if ('id' in userData) {
delete (userData as any).id;
}
return db.user.create({
data: userData,
});
},
};
/**
* Auth.js (NextAuth.js) Configuration
*
* @description Defines authentication providers and their configurations.
* This setup includes OAuth providers (Google, Github, magic-link with Resend) and credentials-based authentication.
*
* Credentials Provider Authorization
*
* @description all validation logic is done on login server action.
*/
export default {
adapter,
session: {
strategy: 'jwt',
maxAge: 2592000,
updateAge: 86400,
},
secret: process.env.AUTH_SECRET,
providers: [
Google({
clientId: process.env.AUTH_GOOGLE_CLIENT_ID,
clientSecret: process.env.AUTH_GOOGLE_CLIENT_SECRET,
allowDangerousEmailAccountLinking: true,
}),
Github({
clientId: process.env.AUTH_GITHUB_CLIENT_ID,
clientSecret: process.env.AUTH_GITHUB_CLIENT_SECRET,
}),
Resend({
apiKey: process.env.RESEND_API_KEY,
from: '[email protected]',
}),
Credentials({
credentials: {
user: {},
callbackUrl: {},
},
async authorize(credentials) {
try {
const userStr = credentials?.user;
if (typeof userStr !== 'string') return null;
const user = JSON.parse(userStr);
const validatedFields = VerifiedCredentialsUserSchema.safeParse(user);
return validatedFields.success ? validatedFields.data : null;
} catch (error) {
console.error('Error parsing credentials:', error);
return null;
}
},
}),
],
debug: false,
trustHost: true,
} satisfies NextAuthConfig;