hazo_auth 5.1.13 → 5.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli-src/cli/generate.ts +5 -0
- package/dist/cli/generate.d.ts.map +1 -1
- package/dist/cli/generate.js +5 -0
- package/dist/server/routes/index.d.ts +3 -0
- package/dist/server/routes/index.d.ts.map +1 -1
- package/dist/server/routes/index.js +4 -0
- package/dist/server/routes/nextauth.d.ts +9 -0
- package/dist/server/routes/nextauth.d.ts.map +1 -0
- package/dist/server/routes/nextauth.js +36 -0
- package/dist/server/routes/oauth_google_callback.d.ts +8 -0
- package/dist/server/routes/oauth_google_callback.d.ts.map +1 -0
- package/dist/server/routes/oauth_google_callback.js +122 -0
- package/dist/server/routes/set_password.d.ts +13 -0
- package/dist/server/routes/set_password.d.ts.map +1 -0
- package/dist/server/routes/set_password.js +88 -0
- package/package.json +1 -1
package/cli-src/cli/generate.ts
CHANGED
|
@@ -59,6 +59,11 @@ const ROUTES: RouteDefinition[] = [
|
|
|
59
59
|
{ name: "user_management_users_roles", path: "api/hazo_auth/user_management/users/roles", method: "GET", export_name: "userManagementUsersRolesGET" },
|
|
60
60
|
{ name: "user_management_users_roles_post", path: "api/hazo_auth/user_management/users/roles", method: "POST", export_name: "userManagementUsersRolesPOST" },
|
|
61
61
|
{ name: "user_management_users_roles_put", path: "api/hazo_auth/user_management/users/roles", method: "PUT", export_name: "userManagementUsersRolesPUT" },
|
|
62
|
+
// OAuth routes
|
|
63
|
+
{ name: "nextauth", path: "api/auth/[...nextauth]", method: "GET", export_name: "nextauthGET" },
|
|
64
|
+
{ name: "nextauth_post", path: "api/auth/[...nextauth]", method: "POST", export_name: "nextauthPOST" },
|
|
65
|
+
{ name: "oauth_google_callback", path: "api/hazo_auth/oauth/google/callback", method: "GET", export_name: "oauthGoogleCallbackGET" },
|
|
66
|
+
{ name: "set_password", path: "api/hazo_auth/set_password", method: "POST", export_name: "setPasswordPOST" },
|
|
62
67
|
];
|
|
63
68
|
|
|
64
69
|
const PAGES: PageDefinition[] = [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/cli/generate.ts"],"names":[],"mappings":"AAqBA,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,CAAC;
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/cli/generate.ts"],"names":[],"mappings":"AAqBA,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,CAAC;AAiMF,wBAAgB,eAAe,CAAC,OAAO,GAAE,eAAoB,GAAG,IAAI,CA8DnE"}
|
package/dist/cli/generate.js
CHANGED
|
@@ -36,6 +36,11 @@ const ROUTES = [
|
|
|
36
36
|
{ name: "user_management_users_roles", path: "api/hazo_auth/user_management/users/roles", method: "GET", export_name: "userManagementUsersRolesGET" },
|
|
37
37
|
{ name: "user_management_users_roles_post", path: "api/hazo_auth/user_management/users/roles", method: "POST", export_name: "userManagementUsersRolesPOST" },
|
|
38
38
|
{ name: "user_management_users_roles_put", path: "api/hazo_auth/user_management/users/roles", method: "PUT", export_name: "userManagementUsersRolesPUT" },
|
|
39
|
+
// OAuth routes
|
|
40
|
+
{ name: "nextauth", path: "api/auth/[...nextauth]", method: "GET", export_name: "nextauthGET" },
|
|
41
|
+
{ name: "nextauth_post", path: "api/auth/[...nextauth]", method: "POST", export_name: "nextauthPOST" },
|
|
42
|
+
{ name: "oauth_google_callback", path: "api/hazo_auth/oauth/google/callback", method: "GET", export_name: "oauthGoogleCallbackGET" },
|
|
43
|
+
{ name: "set_password", path: "api/hazo_auth/set_password", method: "POST", export_name: "setPasswordPOST" },
|
|
39
44
|
];
|
|
40
45
|
const PAGES = [
|
|
41
46
|
{ name: "login", path: "hazo_auth/login", component_name: "LoginPage", import_path: "hazo_auth/pages/login" },
|
|
@@ -24,4 +24,7 @@ export { GET as appUserDataGET, PATCH as appUserDataPATCH, PUT as appUserDataPUT
|
|
|
24
24
|
export { GET as appUserDataSchemaGET } from "./app_user_data_schema.js";
|
|
25
25
|
export { GET as invitationsGET, POST as invitationsPOST, PATCH as invitationsPATCH, DELETE as invitationsDELETE } from "./invitations.js";
|
|
26
26
|
export { POST as createFirmPOST } from "./create_firm.js";
|
|
27
|
+
export { GET as nextauthGET, POST as nextauthPOST } from "./nextauth.js";
|
|
28
|
+
export { GET as oauthGoogleCallbackGET } from "./oauth_google_callback.js";
|
|
29
|
+
export { POST as setPasswordPOST } from "./set_password.js";
|
|
27
30
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/routes/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,IAAI,IAAI,YAAY,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,IAAI,IAAI,UAAU,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,GAAG,IAAI,KAAK,EAAE,MAAM,SAAS,CAAC;AAGvC,OAAO,EAAE,IAAI,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,IAAI,IAAI,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,IAAI,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,GAAG,IAAI,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAGzE,OAAO,EAAE,GAAG,IAAI,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,IAAI,IAAI,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAG1E,OAAO,EAAE,KAAK,IAAI,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,IAAI,IAAI,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAC/E,OAAO,EAAE,MAAM,IAAI,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,GAAG,IAAI,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,EAAE,GAAG,IAAI,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,GAAG,IAAI,yBAAyB,EAAE,MAAM,+BAA+B,CAAC;AAGjF,OAAO,EAAE,IAAI,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,IAAI,IAAI,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAGpE,OAAO,EAAE,GAAG,IAAI,sBAAsB,EAAE,KAAK,IAAI,wBAAwB,EAAE,IAAI,IAAI,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAC/I,OAAO,EAAE,GAAG,IAAI,4BAA4B,EAAE,IAAI,IAAI,6BAA6B,EAAE,GAAG,IAAI,4BAA4B,EAAE,MAAM,IAAI,+BAA+B,EAAE,MAAM,kCAAkC,CAAC;AAC9M,OAAO,EAAE,GAAG,IAAI,sBAAsB,EAAE,IAAI,IAAI,uBAAuB,EAAE,GAAG,IAAI,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAC3I,OAAO,EAAE,GAAG,IAAI,2BAA2B,EAAE,IAAI,IAAI,4BAA4B,EAAE,GAAG,IAAI,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAGhK,OAAO,EAAE,GAAG,IAAI,cAAc,EAAE,KAAK,IAAI,gBAAgB,EAAE,GAAG,IAAI,cAAc,EAAE,MAAM,IAAI,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC1I,OAAO,EAAE,GAAG,IAAI,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAGxE,OAAO,EAAE,GAAG,IAAI,cAAc,EAAE,IAAI,IAAI,eAAe,EAAE,KAAK,IAAI,gBAAgB,EAAE,MAAM,IAAI,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAG1I,OAAO,EAAE,IAAI,IAAI,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/routes/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,IAAI,IAAI,YAAY,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,IAAI,IAAI,UAAU,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,GAAG,IAAI,KAAK,EAAE,MAAM,SAAS,CAAC;AAGvC,OAAO,EAAE,IAAI,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,IAAI,IAAI,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,IAAI,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,GAAG,IAAI,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAGzE,OAAO,EAAE,GAAG,IAAI,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,IAAI,IAAI,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAG1E,OAAO,EAAE,KAAK,IAAI,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,IAAI,IAAI,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAC/E,OAAO,EAAE,MAAM,IAAI,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,GAAG,IAAI,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,EAAE,GAAG,IAAI,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,GAAG,IAAI,yBAAyB,EAAE,MAAM,+BAA+B,CAAC;AAGjF,OAAO,EAAE,IAAI,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,IAAI,IAAI,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAGpE,OAAO,EAAE,GAAG,IAAI,sBAAsB,EAAE,KAAK,IAAI,wBAAwB,EAAE,IAAI,IAAI,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAC/I,OAAO,EAAE,GAAG,IAAI,4BAA4B,EAAE,IAAI,IAAI,6BAA6B,EAAE,GAAG,IAAI,4BAA4B,EAAE,MAAM,IAAI,+BAA+B,EAAE,MAAM,kCAAkC,CAAC;AAC9M,OAAO,EAAE,GAAG,IAAI,sBAAsB,EAAE,IAAI,IAAI,uBAAuB,EAAE,GAAG,IAAI,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAC3I,OAAO,EAAE,GAAG,IAAI,2BAA2B,EAAE,IAAI,IAAI,4BAA4B,EAAE,GAAG,IAAI,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAGhK,OAAO,EAAE,GAAG,IAAI,cAAc,EAAE,KAAK,IAAI,gBAAgB,EAAE,GAAG,IAAI,cAAc,EAAE,MAAM,IAAI,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC1I,OAAO,EAAE,GAAG,IAAI,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAGxE,OAAO,EAAE,GAAG,IAAI,cAAc,EAAE,IAAI,IAAI,eAAe,EAAE,KAAK,IAAI,gBAAgB,EAAE,MAAM,IAAI,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAG1I,OAAO,EAAE,IAAI,IAAI,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAG1D,OAAO,EAAE,GAAG,IAAI,WAAW,EAAE,IAAI,IAAI,YAAY,EAAE,MAAM,eAAe,CAAC;AACzE,OAAO,EAAE,GAAG,IAAI,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAC3E,OAAO,EAAE,IAAI,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -35,3 +35,7 @@ export { GET as appUserDataSchemaGET } from "./app_user_data_schema.js";
|
|
|
35
35
|
export { GET as invitationsGET, POST as invitationsPOST, PATCH as invitationsPATCH, DELETE as invitationsDELETE } from "./invitations.js";
|
|
36
36
|
// Create firm routes (for new users creating their firm)
|
|
37
37
|
export { POST as createFirmPOST } from "./create_firm.js";
|
|
38
|
+
// OAuth routes
|
|
39
|
+
export { GET as nextauthGET, POST as nextauthPOST } from "./nextauth.js";
|
|
40
|
+
export { GET as oauthGoogleCallbackGET } from "./oauth_google_callback.js";
|
|
41
|
+
export { POST as setPasswordPOST } from "./set_password.js";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type NextAuthContext = {
|
|
2
|
+
params: Promise<{
|
|
3
|
+
nextauth: string[];
|
|
4
|
+
}>;
|
|
5
|
+
};
|
|
6
|
+
export declare function GET(request: Request, context: NextAuthContext): Promise<any>;
|
|
7
|
+
export declare function POST(request: Request, context: NextAuthContext): Promise<any>;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=nextauth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nextauth.d.ts","sourceRoot":"","sources":["../../../src/server/routes/nextauth.ts"],"names":[],"mappings":"AAMA,KAAK,eAAe,GAAG;IACrB,MAAM,EAAE,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;CACzC,CAAC;AA8BF,wBAAsB,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,gBAGnE;AAED,wBAAsB,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,gBAGpE"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// file_description: NextAuth.js route handler for OAuth authentication (for re-export by consuming apps)
|
|
2
|
+
// section: imports
|
|
3
|
+
import NextAuth from "next-auth";
|
|
4
|
+
import { get_nextauth_config } from "../../lib/auth/nextauth_config.js";
|
|
5
|
+
// section: handler
|
|
6
|
+
// Get config lazily to ensure environment variables are available
|
|
7
|
+
function getHandler() {
|
|
8
|
+
var _a;
|
|
9
|
+
const config = get_nextauth_config();
|
|
10
|
+
// Debug logging (remove in production)
|
|
11
|
+
if (process.env.NODE_ENV === "development") {
|
|
12
|
+
console.log("[NextAuth] Creating handler with providers:", ((_a = config.providers) === null || _a === void 0 ? void 0 : _a.length) || 0);
|
|
13
|
+
console.log("[NextAuth] Google Client ID set:", !!process.env.HAZO_AUTH_GOOGLE_CLIENT_ID);
|
|
14
|
+
console.log("[NextAuth] Google Client Secret set:", !!process.env.HAZO_AUTH_GOOGLE_CLIENT_SECRET);
|
|
15
|
+
console.log("[NextAuth] NEXTAUTH_SECRET set:", !!process.env.NEXTAUTH_SECRET);
|
|
16
|
+
console.log("[NextAuth] NEXTAUTH_URL:", process.env.NEXTAUTH_URL);
|
|
17
|
+
}
|
|
18
|
+
return NextAuth(config);
|
|
19
|
+
}
|
|
20
|
+
// Create handler lazily
|
|
21
|
+
let cachedHandler = null;
|
|
22
|
+
function getOrCreateHandler() {
|
|
23
|
+
if (!cachedHandler) {
|
|
24
|
+
cachedHandler = getHandler();
|
|
25
|
+
}
|
|
26
|
+
return cachedHandler;
|
|
27
|
+
}
|
|
28
|
+
// section: exports
|
|
29
|
+
export async function GET(request, context) {
|
|
30
|
+
const handler = getOrCreateHandler();
|
|
31
|
+
return handler(request, context);
|
|
32
|
+
}
|
|
33
|
+
export async function POST(request, context) {
|
|
34
|
+
const handler = getOrCreateHandler();
|
|
35
|
+
return handler(request, context);
|
|
36
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
2
|
+
/**
|
|
3
|
+
* Handles the OAuth callback after Google sign-in
|
|
4
|
+
* The user creation/linking is done in NextAuth signIn callback
|
|
5
|
+
* This route just sets the hazo_auth session cookies
|
|
6
|
+
*/
|
|
7
|
+
export declare function GET(request: NextRequest): Promise<NextResponse<unknown>>;
|
|
8
|
+
//# sourceMappingURL=oauth_google_callback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth_google_callback.d.ts","sourceRoot":"","sources":["../../../src/server/routes/oauth_google_callback.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAsBxD;;;;GAIG;AACH,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW,kCA8H7C"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// file_description: Custom OAuth callback handler that creates hazo_auth session after Google sign-in
|
|
2
|
+
// section: imports
|
|
3
|
+
import { NextResponse } from "next/server";
|
|
4
|
+
import { getToken } from "next-auth/jwt";
|
|
5
|
+
import { create_app_logger } from "../../lib/app_logger.js";
|
|
6
|
+
import { create_session_token } from "../../lib/services/session_token_service.js";
|
|
7
|
+
import { get_filename, get_line_number } from "../../lib/utils/api_route_helpers.js";
|
|
8
|
+
import { get_login_config } from "../../lib/login_config.server.js";
|
|
9
|
+
import { get_cookie_name, get_cookie_options, BASE_COOKIE_NAMES } from "../../lib/cookies_config.server.js";
|
|
10
|
+
import { get_hazo_connect_instance } from "../../lib/hazo_connect_instance.server.js";
|
|
11
|
+
import { get_post_login_redirect } from "../../lib/services/post_verification_service.js";
|
|
12
|
+
// section: api_handler
|
|
13
|
+
/**
|
|
14
|
+
* Handles the OAuth callback after Google sign-in
|
|
15
|
+
* The user creation/linking is done in NextAuth signIn callback
|
|
16
|
+
* This route just sets the hazo_auth session cookies
|
|
17
|
+
*/
|
|
18
|
+
export async function GET(request) {
|
|
19
|
+
const logger = create_app_logger();
|
|
20
|
+
try {
|
|
21
|
+
// Get the NextAuth token from the session
|
|
22
|
+
const token = (await getToken({ req: request }));
|
|
23
|
+
logger.debug("google_callback_token_received", {
|
|
24
|
+
filename: get_filename(),
|
|
25
|
+
line_number: get_line_number(),
|
|
26
|
+
has_token: !!token,
|
|
27
|
+
has_email: !!(token === null || token === void 0 ? void 0 : token.email),
|
|
28
|
+
has_hazo_user_id: !!(token === null || token === void 0 ? void 0 : token.hazo_user_id),
|
|
29
|
+
has_google_id: !!(token === null || token === void 0 ? void 0 : token.google_id),
|
|
30
|
+
});
|
|
31
|
+
if (!token) {
|
|
32
|
+
logger.warn("google_callback_no_token", {
|
|
33
|
+
filename: get_filename(),
|
|
34
|
+
line_number: get_line_number(),
|
|
35
|
+
note: "No NextAuth token found - user may not have completed Google sign-in",
|
|
36
|
+
});
|
|
37
|
+
// Redirect to login with error
|
|
38
|
+
const login_url = new URL("/hazo_auth/login", request.url);
|
|
39
|
+
login_url.searchParams.set("error", "oauth_failed");
|
|
40
|
+
return NextResponse.redirect(login_url);
|
|
41
|
+
}
|
|
42
|
+
// Validate we have the required data
|
|
43
|
+
if (!token.email || !token.hazo_user_id) {
|
|
44
|
+
logger.warn("google_callback_missing_data", {
|
|
45
|
+
filename: get_filename(),
|
|
46
|
+
line_number: get_line_number(),
|
|
47
|
+
has_email: !!token.email,
|
|
48
|
+
has_hazo_user_id: !!token.hazo_user_id,
|
|
49
|
+
has_google_id: !!token.google_id,
|
|
50
|
+
});
|
|
51
|
+
const login_url = new URL("/hazo_auth/login", request.url);
|
|
52
|
+
login_url.searchParams.set("error", "oauth_incomplete");
|
|
53
|
+
return NextResponse.redirect(login_url);
|
|
54
|
+
}
|
|
55
|
+
const user_id = token.hazo_user_id;
|
|
56
|
+
const email = token.email;
|
|
57
|
+
logger.info("google_callback_success", {
|
|
58
|
+
filename: get_filename(),
|
|
59
|
+
line_number: get_line_number(),
|
|
60
|
+
user_id,
|
|
61
|
+
email,
|
|
62
|
+
});
|
|
63
|
+
// Get redirect URL based on user's scope/invitation status
|
|
64
|
+
const loginConfig = get_login_config();
|
|
65
|
+
const default_redirect = loginConfig.redirectRoute || "/";
|
|
66
|
+
// Check if user needs onboarding (no scope, no invitation = create firm)
|
|
67
|
+
const hazoConnect = get_hazo_connect_instance();
|
|
68
|
+
const { redirect_url: determined_redirect, needs_onboarding } = await get_post_login_redirect(hazoConnect, user_id, email, default_redirect);
|
|
69
|
+
logger.info("google_callback_post_login_redirect", {
|
|
70
|
+
filename: get_filename(),
|
|
71
|
+
line_number: get_line_number(),
|
|
72
|
+
user_id,
|
|
73
|
+
email,
|
|
74
|
+
redirect_url: determined_redirect,
|
|
75
|
+
needs_onboarding,
|
|
76
|
+
});
|
|
77
|
+
// Create redirect response
|
|
78
|
+
const redirect_url = new URL(determined_redirect, request.url);
|
|
79
|
+
const response = NextResponse.redirect(redirect_url);
|
|
80
|
+
// Set authentication cookies (same as login route, with configurable prefix and domain)
|
|
81
|
+
const base_cookie_options = {
|
|
82
|
+
httpOnly: true,
|
|
83
|
+
secure: process.env.NODE_ENV === "production",
|
|
84
|
+
sameSite: "lax",
|
|
85
|
+
path: "/",
|
|
86
|
+
maxAge: 60 * 60 * 24 * 30, // 30 days
|
|
87
|
+
};
|
|
88
|
+
const cookie_options = get_cookie_options(base_cookie_options);
|
|
89
|
+
response.cookies.set(get_cookie_name(BASE_COOKIE_NAMES.USER_ID), user_id, cookie_options);
|
|
90
|
+
response.cookies.set(get_cookie_name(BASE_COOKIE_NAMES.USER_EMAIL), email, cookie_options);
|
|
91
|
+
// Create and set JWT session token
|
|
92
|
+
try {
|
|
93
|
+
const session_token = await create_session_token(user_id, email);
|
|
94
|
+
response.cookies.set(get_cookie_name(BASE_COOKIE_NAMES.SESSION), session_token, cookie_options);
|
|
95
|
+
}
|
|
96
|
+
catch (token_error) {
|
|
97
|
+
const token_error_message = token_error instanceof Error ? token_error.message : "Unknown error";
|
|
98
|
+
logger.warn("google_callback_session_token_creation_failed", {
|
|
99
|
+
filename: get_filename(),
|
|
100
|
+
line_number: get_line_number(),
|
|
101
|
+
user_id,
|
|
102
|
+
email,
|
|
103
|
+
error: token_error_message,
|
|
104
|
+
note: "OAuth login succeeded but session token creation failed - using legacy cookies",
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return response;
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
const error_message = error instanceof Error ? error.message : "Unknown error";
|
|
111
|
+
const error_stack = error instanceof Error ? error.stack : undefined;
|
|
112
|
+
logger.error("google_callback_error", {
|
|
113
|
+
filename: get_filename(),
|
|
114
|
+
line_number: get_line_number(),
|
|
115
|
+
error_message,
|
|
116
|
+
error_stack,
|
|
117
|
+
});
|
|
118
|
+
const login_url = new URL("/hazo_auth/login", request.url);
|
|
119
|
+
login_url.searchParams.set("error", "oauth_error");
|
|
120
|
+
return NextResponse.redirect(login_url);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
2
|
+
/**
|
|
3
|
+
* POST /api/hazo_auth/set_password
|
|
4
|
+
* Allows OAuth-only users (e.g., Google sign-in users) to set a password
|
|
5
|
+
* This enables them to use email/password login in addition to OAuth
|
|
6
|
+
*/
|
|
7
|
+
export declare function POST(request: NextRequest): Promise<NextResponse<{
|
|
8
|
+
error: string;
|
|
9
|
+
}> | NextResponse<{
|
|
10
|
+
success: boolean;
|
|
11
|
+
message: string;
|
|
12
|
+
}>>;
|
|
13
|
+
//# sourceMappingURL=set_password.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"set_password.d.ts","sourceRoot":"","sources":["../../../src/server/routes/set_password.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAYxD;;;;GAIG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;;IA4G9C"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// file_description: API route for setting password for OAuth-only users
|
|
2
|
+
// section: imports
|
|
3
|
+
import { NextResponse } from "next/server";
|
|
4
|
+
import argon2 from "argon2";
|
|
5
|
+
import { get_hazo_connect_instance } from "../../lib/hazo_connect_instance.server.js";
|
|
6
|
+
import { create_app_logger } from "../../lib/app_logger.js";
|
|
7
|
+
import { hazo_get_auth } from "../../lib/auth/hazo_get_auth.server.js";
|
|
8
|
+
import { user_has_password, set_user_password } from "../../lib/services/oauth_service.js";
|
|
9
|
+
import { get_password_requirements_config } from "../../lib/password_requirements_config.server.js";
|
|
10
|
+
import { validate_password } from "../../lib/utils/password_validator.js";
|
|
11
|
+
import { get_filename, get_line_number } from "../../lib/utils/api_route_helpers.js";
|
|
12
|
+
import { get_auth_cache } from "../../lib/auth/auth_cache.js";
|
|
13
|
+
// section: api_handler
|
|
14
|
+
/**
|
|
15
|
+
* POST /api/hazo_auth/set_password
|
|
16
|
+
* Allows OAuth-only users (e.g., Google sign-in users) to set a password
|
|
17
|
+
* This enables them to use email/password login in addition to OAuth
|
|
18
|
+
*/
|
|
19
|
+
export async function POST(request) {
|
|
20
|
+
const logger = create_app_logger();
|
|
21
|
+
try {
|
|
22
|
+
// Require authentication using hazo_get_auth
|
|
23
|
+
const auth_result = await hazo_get_auth(request);
|
|
24
|
+
if (!auth_result.authenticated) {
|
|
25
|
+
return NextResponse.json({ error: "Authentication required" }, { status: 401 });
|
|
26
|
+
}
|
|
27
|
+
const user_id = auth_result.user.id;
|
|
28
|
+
// Parse request body
|
|
29
|
+
const body = await request.json();
|
|
30
|
+
const { new_password } = body;
|
|
31
|
+
// Validate input
|
|
32
|
+
if (!new_password) {
|
|
33
|
+
return NextResponse.json({ error: "New password is required" }, { status: 400 });
|
|
34
|
+
}
|
|
35
|
+
// Get hazo_connect instance
|
|
36
|
+
const hazoConnect = get_hazo_connect_instance();
|
|
37
|
+
// Check if user already has a password set
|
|
38
|
+
const has_password = await user_has_password(hazoConnect, user_id);
|
|
39
|
+
if (has_password) {
|
|
40
|
+
return NextResponse.json({
|
|
41
|
+
error: "Password already set. Use Change Password instead.",
|
|
42
|
+
has_password: true,
|
|
43
|
+
}, { status: 400 });
|
|
44
|
+
}
|
|
45
|
+
// Validate password against requirements
|
|
46
|
+
const password_config = get_password_requirements_config();
|
|
47
|
+
const validation_result = validate_password(new_password, password_config);
|
|
48
|
+
if (!validation_result.valid) {
|
|
49
|
+
return NextResponse.json({ error: validation_result.errors.join(". ") }, { status: 400 });
|
|
50
|
+
}
|
|
51
|
+
// Hash the new password
|
|
52
|
+
const password_hash = await argon2.hash(new_password);
|
|
53
|
+
// Set the password
|
|
54
|
+
const result = await set_user_password(hazoConnect, user_id, password_hash);
|
|
55
|
+
if (!result.success) {
|
|
56
|
+
logger.error("set_password_failed", {
|
|
57
|
+
filename: get_filename(),
|
|
58
|
+
line_number: get_line_number(),
|
|
59
|
+
user_id,
|
|
60
|
+
error: result.error,
|
|
61
|
+
});
|
|
62
|
+
return NextResponse.json({ error: result.error || "Failed to set password" }, { status: 500 });
|
|
63
|
+
}
|
|
64
|
+
// Invalidate auth cache for this user
|
|
65
|
+
const auth_cache = get_auth_cache();
|
|
66
|
+
auth_cache.invalidate_user(user_id);
|
|
67
|
+
logger.info("set_password_success", {
|
|
68
|
+
filename: get_filename(),
|
|
69
|
+
line_number: get_line_number(),
|
|
70
|
+
user_id,
|
|
71
|
+
});
|
|
72
|
+
return NextResponse.json({
|
|
73
|
+
success: true,
|
|
74
|
+
message: "Password set successfully. You can now sign in with email and password.",
|
|
75
|
+
}, { status: 200 });
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
const error_message = error instanceof Error ? error.message : "Unknown error";
|
|
79
|
+
const error_stack = error instanceof Error ? error.stack : undefined;
|
|
80
|
+
logger.error("set_password_error", {
|
|
81
|
+
filename: get_filename(),
|
|
82
|
+
line_number: get_line_number(),
|
|
83
|
+
error_message,
|
|
84
|
+
error_stack,
|
|
85
|
+
});
|
|
86
|
+
return NextResponse.json({ error: "Failed to set password. Please try again." }, { status: 500 });
|
|
87
|
+
}
|
|
88
|
+
}
|
package/package.json
CHANGED