first commit

This commit is contained in:
Beyhan Oğur
2026-04-26 22:15:25 +03:00
commit 9eb7aea821
56 changed files with 20630 additions and 0 deletions

146
lib/auth.ts Normal file
View File

@@ -0,0 +1,146 @@
import type { NextAuthOptions } from 'next-auth'
import type { JWT } from 'next-auth/jwt'
import CredentialsProvider from 'next-auth/providers/credentials'
import GitHubProvider from 'next-auth/providers/github'
import GoogleProvider from 'next-auth/providers/google'
import {
fetchRefreshedBackendJwt,
getJwtExpMs,
shouldRefreshBackendToken,
} from '@/lib/backend-jwt-refresh'
const API_BASE = process.env.API_BASE_URL ?? 'http://localhost:8080'
type AuthUser = {
id: string
email: string
username: string
accessToken: string
refreshToken: string
accessTokenExpires: number
}
async function refreshAccessToken(token: JWT): Promise<JWT> {
const next = await fetchRefreshedBackendJwt(token)
if (!next) {
return {
...token,
error: 'RefreshAccessTokenError',
}
}
return next
}
export const authOptions: NextAuthOptions = {
session: {
strategy: 'jwt',
/** NextAuth oturum çerezi ömrü (saniye) — backend refresh ile uyumlu uzun süre */
maxAge: 60 * 60 * 24 * 7,
},
secret: process.env.NEXTAUTH_SECRET ?? process.env.AUTH_SECRET,
providers: [
...(process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET
? [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
]
: []),
...(process.env.GITHUB_CLIENT_ID && process.env.GITHUB_CLIENT_SECRET
? [
GitHubProvider({
clientId: process.env.GITHUB_CLIENT_ID,
clientSecret: process.env.GITHUB_CLIENT_SECRET,
}),
]
: []),
CredentialsProvider({
name: 'Credentials',
credentials: {
email: { label: 'Email', type: 'email' },
password: { label: 'Password', type: 'password' },
},
async authorize(credentials) {
const email = credentials?.email
const password = credentials?.password
if (!email || !password) return null
const res = await fetch(`${API_BASE}/api/v1/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password }),
})
if (!res.ok) return null
const data = (await res.json()) as { access: string; refresh: string }
const accessToken = data.access
const refreshToken = data.refresh
return {
id: email,
email,
username: email,
accessToken,
refreshToken,
accessTokenExpires: getJwtExpMs(accessToken),
} satisfies AuthUser
},
}),
],
callbacks: {
async jwt({ token, user }) {
if (user) {
const authUser = user as AuthUser
// OAuth login akışında backend access/refresh token'ı yoksa refresh denemeyelim.
if (!authUser.accessToken || !authUser.refreshToken) {
return {
...token,
user: {
id: authUser.id,
email: authUser.email,
username: authUser.username ?? authUser.email,
},
}
}
return {
...token,
accessToken: authUser.accessToken,
refreshToken: authUser.refreshToken,
accessTokenExpires: authUser.accessTokenExpires,
user: {
id: authUser.id,
email: authUser.email,
username: authUser.username,
},
}
}
if (token.error === 'RefreshAccessTokenError') {
return token
}
if (!shouldRefreshBackendToken(token)) {
return token
}
return refreshAccessToken(token)
},
async session({ session, token }) {
session.user = {
...(session.user ?? {}),
...(token.user ?? {}),
}
session.accessToken = token.accessToken
session.refreshToken = token.refreshToken
session.error = token.error
return session
},
},
pages: {
signIn: '/auth/login',
},
}