import NextAuth, { NextAuthConfig } from 'next-auth'; import GoogleProvider from 'next-auth/providers/google'; // import LinkedinProvider from 'next-auth/providers/linkedin'; import { Session } from 'next-auth'; import { AuthenticatedUser } from './types/next-auth'; import { defaultLocale } from '../i18n'; export const myAuth = () => { // Use mock authentication in development when enabled via environment variable if (process.env.NODE_ENV === 'development' && process.env.USE_MOCK_AUTH === 'true') { const session: Session = { user: { id: process.env.MOCK_USER_ID || "109754742613069927799", name: process.env.MOCK_USER_NAME || "Nikola Derežić", }, expires: "123", }; return Promise.resolve(session); } return auth(); } export const authConfig: NextAuthConfig = { callbacks: { // method verifies if the user is logged in or not // -> is called by Next-Auth when the midleware calls the `auth` method (exported below) authorized({ auth, request: { nextUrl } }) { const isLoggedIn = !!auth?.user; return (isLoggedIn); }, // method is called when the user is not logged in // this is a hack which takes user ID and assigns it temporaty to the token, which is then used to extend Session.user // see: https://stackoverflow.com/questions/70409219/get-user-id-from-session-in-next-auth-client jwt({ token, account, user }) { if (account) { // console.log("(JWT) account:", account); // console.log("(JWT) user:", user); token.accessToken = account.access_token; // attach Google account ID to the token token.piggyback_providerAccountId = account.providerAccountId; } return token }, // method is called after the JWT token is created // this is a hack which takes user ID temporaty assigned to the token and assigns it to the Session.user // see: https://stackoverflow.com/questions/70409219/get-user-id-from-session-in-next-auth-client async session({ session, token }:{ session:Session, token:any }) { if(session.user && token) { // assign Google account ID from the token to the Session user ID session.user.id = token.piggyback_providerAccountId; // console.log("(SESSION) token:", token); } return session; }, }, providers: [ GoogleProvider({ clientId: process.env.GOOGLE_ID, clientSecret: process.env.GOOGLE_SECRET, }), // // config based on https://github.com/nextauthjs/next-auth/issues/8831 // LinkedinProvider({ // clientId: process.env.LINKEDIN_ID, // clientSecret: process.env.LINKEDIN_SECRET, // authorization: { params: { scope: 'email openid' } }, // issuer: 'https://www.linkedin.com', // jwks_endpoint: "https://www.linkedin.com/oauth/openid/jwks", // async profile(profile) { // return { // id: profile.sub, // name: profile.name, // firstname: profile.given_name, // lastname: profile.family_name, // email: profile.email // } // }, // }) ], secret: process.env.AUTH_SECRET, trustHost: true, // needs to be set to false for the NextJS to work behing Traefik session: { // Use JSON Web Tokens for session instead of database sessions. // This option can be used with or without a database for users/accounts. // Note: `jwt` is automatically set to `true` if no database is specified. strategy: 'jwt' }, pages: { signIn: `/${defaultLocale}`, }, }; export const { auth, handlers: { GET, POST } } = NextAuth(authConfig); export type AuthErrorMessage = { message: string, errors: { message: string, } } export const isAuthErrorMessage = (obj: any): obj is AuthErrorMessage => { return (obj.message && obj.errors && obj.errors.message); } export const withUser = (fn: (user: AuthenticatedUser, ...args:A) => Promise) => async (...args:A) => { const session = await myAuth(); if(!session) { throw new Error("Not authenticated") } const { user } = session; return(fn(user, ...args)); }