feat / AEB-26 login page
This commit is contained in:
156
frontend/lib/auth.ts
Normal file
156
frontend/lib/auth.ts
Normal file
@@ -0,0 +1,156 @@
|
||||
import { NextAuthOptions } from 'next-auth'
|
||||
import CredentialsProvider from 'next-auth/providers/credentials'
|
||||
import { JWT } from 'next-auth/jwt'
|
||||
|
||||
declare module 'next-auth' {
|
||||
interface Session {
|
||||
user: {
|
||||
name?: string | null
|
||||
surname?: string | null
|
||||
email?: string | null
|
||||
phone_number?: string | null
|
||||
image?: string | null
|
||||
}
|
||||
accessToken?: string
|
||||
refreshToken?: string
|
||||
expiresAt?: number
|
||||
}
|
||||
|
||||
interface User {
|
||||
id: string
|
||||
email: string
|
||||
name?: string
|
||||
accessToken?: string
|
||||
refreshToken?: string
|
||||
}
|
||||
|
||||
interface JWT {
|
||||
accessToken?: string
|
||||
refreshToken?: string
|
||||
expiresAt?: number
|
||||
error?: string
|
||||
}
|
||||
}
|
||||
|
||||
interface GoogleToken extends JWT {
|
||||
accessToken?: string
|
||||
refreshToken?: string
|
||||
expiresAt?: number | undefined
|
||||
error?: string
|
||||
}
|
||||
|
||||
async function refreshAccessToken(token: GoogleToken): Promise<GoogleToken> {
|
||||
try {
|
||||
const response = await fetch(`${process.env.BACKEND_URL}/auth/refresh/`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
refresh: token.refreshToken,
|
||||
}),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json()
|
||||
throw errorData
|
||||
}
|
||||
|
||||
const refreshedTokens = await response.json()
|
||||
|
||||
return {
|
||||
...token,
|
||||
accessToken: refreshedTokens.access,
|
||||
refreshToken: refreshedTokens.refresh ?? token.refreshToken,
|
||||
expiresAt: refreshedTokens.expires_at,
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Refresh error:', error)
|
||||
return {
|
||||
...token,
|
||||
error: 'RefreshAccessTokenError',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const authOptions: NextAuthOptions = {
|
||||
providers: [
|
||||
//логин
|
||||
CredentialsProvider({
|
||||
id: 'credentials',
|
||||
name: 'Credentials',
|
||||
credentials: {
|
||||
login: { label: 'Login', type: 'text' },
|
||||
password: { label: 'Password', type: 'password' },
|
||||
},
|
||||
async authorize(credentials) {
|
||||
try {
|
||||
const res = await fetch(`${process.env.BACKEND_URL}/auth/login/`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
login: credentials?.login,
|
||||
password: credentials?.password,
|
||||
}),
|
||||
})
|
||||
|
||||
const data = await res.json()
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(data.error || 'Authentication failed')
|
||||
}
|
||||
|
||||
return {
|
||||
id: data.user.id.toString(),
|
||||
email: data.user.email,
|
||||
name: data.user.firstName,
|
||||
accessToken: data.access,
|
||||
refreshToken: data.refresh,
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Login error:', error)
|
||||
return null
|
||||
}
|
||||
},
|
||||
}),
|
||||
],
|
||||
callbacks: {
|
||||
async jwt({ token, user, account }) {
|
||||
if (user && account) {
|
||||
if (account.type === 'credentials') {
|
||||
return {
|
||||
...token,
|
||||
accessToken: user.accessToken,
|
||||
refreshToken: user.refreshToken,
|
||||
expiresAt: Math.floor(Date.now() / 1000) + 15 * 60, // 15 минут
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
...token,
|
||||
accessToken: account.access_token,
|
||||
refreshToken: account.refresh_token,
|
||||
expiresAt: account.expires_at,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// проверяем не истекает ли токен в ближайшие 5 минут
|
||||
const expiresAt = token.expiresAt as number | undefined
|
||||
if (
|
||||
typeof expiresAt === 'number' &&
|
||||
Date.now() < (expiresAt - 5 * 60) * 1000 // обновляем за 5 минут до истечения
|
||||
) {
|
||||
return token
|
||||
}
|
||||
|
||||
return refreshAccessToken(token as GoogleToken)
|
||||
},
|
||||
async session({ session, token }) {
|
||||
if (token) {
|
||||
session.accessToken = token.accessToken as string
|
||||
session.refreshToken = token.refreshToken as string
|
||||
}
|
||||
return session
|
||||
},
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user