FPSMS-frontend
Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 

111 righe
3.3 KiB

  1. // config/authConfig.ts (or wherever your authOptions live)
  2. import { AuthOptions } from "next-auth";
  3. import CredentialsProvider from "next-auth/providers/credentials";
  4. import { LOGIN_API_PATH } from "./api";
  5. import { Session } from "next-auth";
  6. // Extend the built-in types
  7. declare module "next-auth" {
  8. interface Session {
  9. accessToken: string | null;
  10. refreshToken?: string;
  11. abilities: string[];
  12. id?: string;
  13. /** JWT expiry (seconds since epoch); used to avoid redirecting to dashboard when token is expired */
  14. exp?: number;
  15. }
  16. interface User {
  17. id?: string;
  18. accessToken: string | null;
  19. refreshToken?: string;
  20. abilities: string[];
  21. }
  22. }
  23. declare module "next-auth/jwt" {
  24. interface JWT {
  25. id?: string;
  26. accessToken: string | null;
  27. refreshToken?: string;
  28. abilities: string[];
  29. }
  30. }
  31. export const authOptions: AuthOptions = {
  32. debug: process.env.NODE_ENV === "development",
  33. providers: [
  34. CredentialsProvider({
  35. id: "credentials",
  36. name: "Credentials",
  37. credentials: {
  38. username: { label: "Username", type: "text" },
  39. password: { label: "Password", type: "password" },
  40. },
  41. async authorize(credentials) {
  42. if (!credentials?.username || !credentials?.password) return null;
  43. const res = await fetch(LOGIN_API_PATH, {
  44. method: "POST",
  45. body: JSON.stringify(credentials),
  46. headers: { "Content-Type": "application/json" },
  47. });
  48. if (!res.ok) return null;
  49. const user = await res.json();
  50. // Important: next-auth expects the user object returned here
  51. // to be serializable and contain the fields you want in token/session
  52. // Ensure your backend returns: { id, accessToken, abilities, ...other fields }
  53. if (user && user.abilities) {
  54. return user; // this will be passed to jwt callback as `user`
  55. }
  56. return null;
  57. },
  58. }),
  59. ],
  60. pages: {
  61. signIn: "/login",
  62. },
  63. callbacks: {
  64. // Persist custom fields into the JWT token
  65. async jwt({ token, user }) {
  66. // First sign-in: `user` is available
  67. if (user) {
  68. token.id = user.id ?? token.sub; // fallback to sub if no id
  69. token.accessToken = user.accessToken;
  70. token.refreshToken = user.refreshToken;
  71. token.abilities = user.abilities ?? [];
  72. }
  73. // On subsequent calls (token refresh, session access), user is not present
  74. // so we just return the existing token with custom fields preserved
  75. return token;
  76. },
  77. // Expose custom fields to the client session
  78. async session({ session, token }) {
  79. session.id = token.id as string | undefined;
  80. session.accessToken = token.accessToken as string | null;
  81. session.refreshToken = token.refreshToken as string | undefined;
  82. session.abilities = token.abilities as string[];
  83. session.exp = token.exp as number | undefined;
  84. // Also add abilities to session.user for easier client-side access
  85. if (session.user) {
  86. session.user.abilities = token.abilities as string[];
  87. }
  88. return session;
  89. },
  90. },
  91. };
  92. export type SessionWithTokens = Session & {
  93. accessToken: string | null;
  94. refreshToken?: string;
  95. abilities: string[];
  96. /** Backend / JWT subject — often numeric string or number */
  97. id?: string | number;
  98. };
  99. export default authOptions;