refactor: convert repository to monorepo with npm workspaces
Restructured the repository into a monorepo to better organize application code and maintenance scripts. ## Workspace Structure - web-app: Next.js application (all app code moved from root) - housekeeping: Database backup and maintenance scripts ## Key Changes - Moved all application code to web-app/ using git mv - Moved database scripts to housekeeping/ workspace - Updated Dockerfile for monorepo build process - Updated docker-compose files (volume paths: ./web-app/etc/hosts/) - Updated .gitignore for workspace-level node_modules - Updated documentation (README.md, CLAUDE.md, CHANGELOG.md) ## Migration Impact - Root package.json now manages workspaces - Build commands delegate to web-app workspace - All file history preserved via git mv - Docker build process updated for workspace structure 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
117
web-app/app/lib/auth.ts
Normal file
117
web-app/app/lib/auth.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
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 = <T, A extends any[]>(fn: (user: AuthenticatedUser, ...args:A) => Promise<T>) => async (...args:A) => {
|
||||
const session = await myAuth();
|
||||
|
||||
if(!session) {
|
||||
throw new Error("Not authenticated")
|
||||
}
|
||||
const { user } = session;
|
||||
|
||||
return(fn(user, ...args));
|
||||
}
|
||||
Reference in New Issue
Block a user