@zauru-sdk/utils 6.23.0 → 6.24.0

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.
@@ -1,4 +1,5 @@
1
1
  import { redirect } from "@remix-run/node";
2
+ import { isOauthUserinfoUnauthorizedError } from "@zauru-sdk/common";
2
3
  import { config } from "@zauru-sdk/config";
3
4
  import { commitSession, destroySession, getHeaders, getRefreshSession, getSession, loginWebApp, } from "@zauru-sdk/services";
4
5
  const loginErrorPayload = (description, title) => ({
@@ -26,11 +27,22 @@ const evaluateLoginAccess = async (extras, session, headers) => {
26
27
  return Response.json(loginErrorPayload(description));
27
28
  }
28
29
  };
30
+ const OAUTH_REAUTH_COOKIE = "zauru_oauth_reauth";
29
31
  const authorizeUrl = (request) => {
30
32
  const url = new URL(request.url);
31
33
  const hostname = `${url.port ? "http://" : "https://"}${url.hostname}${url.port ? `:${url.port}` : ""}`;
32
34
  return `${config.oauthBaseURL}/dialog/authorize?client_id=${config.oauthClientID}&response_type=code&redirect_uri=${hostname}/login`;
33
35
  };
36
+ const hasOauthReauthCookie = (request) => (request.headers.get("Cookie") ?? "")
37
+ .split(";")
38
+ .some((part) => part.trim() === `${OAUTH_REAUTH_COOKIE}=1`);
39
+ const oauthReauthSetCookie = () => `${OAUTH_REAUTH_COOKIE}=1; Path=/; Max-Age=120; SameSite=Lax`;
40
+ const redirectOauthReauth = async (session) => {
41
+ const headers = new Headers();
42
+ headers.append("Set-Cookie", await destroySession(session));
43
+ headers.append("Set-Cookie", oauthReauthSetCookie());
44
+ return redirect("/logout?reauth=1", { headers });
45
+ };
34
46
  export function createLoginLoader() {
35
47
  return async () => Response.json({});
36
48
  }
@@ -38,6 +50,10 @@ export function createLoginLoader() {
38
50
  * Remix action for `/login`: OAuth authorize, `loginWebApp`, cookie commit.
39
51
  * `afterLogin` runs before `commitSession`. `requireAccess` can deny after
40
52
  * a successful OAuth exchange or when a session already has `code`.
53
+ *
54
+ * HTTP 401 on `/api/userinfo` (expired/stale `code`) clears the Remix session
55
+ * and redirects to `/logout?reauth=1` so `/login` can request a new code.
56
+ * A 120s `zauru_oauth_reauth` cookie prevents a loop if OAuth keeps failing.
41
57
  */
42
58
  export function createLoginAction(extras) {
43
59
  return async ({ request }) => {
@@ -74,7 +90,12 @@ export function createLoginAction(extras) {
74
90
  }
75
91
  const loginResponse = await loginWebApp(session, codeValue, cookie);
76
92
  if (loginResponse.error || !loginResponse.data) {
77
- return Response.json(loginErrorPayload(loginResponse.userMsg?.toString() ?? ""));
93
+ const userMsg = loginResponse.userMsg?.toString() ?? "";
94
+ if (isOauthUserinfoUnauthorizedError(userMsg) &&
95
+ !hasOauthReauthCookie(request)) {
96
+ return redirectOauthReauth(session);
97
+ }
98
+ return Response.json(loginErrorPayload(userMsg));
78
99
  }
79
100
  const denied = await evaluateLoginAccess(extras, session, loginResponse.data.headers);
80
101
  if (denied) {
@@ -113,7 +134,19 @@ export function createSessionGuardLoader(extras) {
113
134
  };
114
135
  }
115
136
  export function createLogoutLoader(extras) {
116
- return createSessionGuardLoader(extras);
137
+ const guard = createSessionGuardLoader(extras);
138
+ return async (args) => {
139
+ const url = new URL(args.request.url);
140
+ if (url.searchParams.get("reauth") === "1") {
141
+ const session = await getSession(args.request.headers.get("Cookie"));
142
+ return redirect("/login", {
143
+ headers: {
144
+ "Set-Cookie": await destroySession(session),
145
+ },
146
+ });
147
+ }
148
+ return guard(args);
149
+ };
117
150
  }
118
151
  export function createLogoutAction() {
119
152
  return async ({ request }) => {
@@ -26,6 +26,10 @@ export declare function createLoginLoader(): LoaderFunction;
26
26
  * Remix action for `/login`: OAuth authorize, `loginWebApp`, cookie commit.
27
27
  * `afterLogin` runs before `commitSession`. `requireAccess` can deny after
28
28
  * a successful OAuth exchange or when a session already has `code`.
29
+ *
30
+ * HTTP 401 on `/api/userinfo` (expired/stale `code`) clears the Remix session
31
+ * and redirects to `/logout?reauth=1` so `/login` can request a new code.
32
+ * A 120s `zauru_oauth_reauth` cookie prevents a loop if OAuth keeps failing.
29
33
  */
30
34
  export declare function createLoginAction(extras?: LoginActionExtras): ActionFunction;
31
35
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zauru-sdk/utils",
3
- "version": "6.23.0",
3
+ "version": "6.24.0",
4
4
  "description": "Utilidades, parseo de request y demás para desarrollo de webapps de Zauru",
5
5
  "main": "./dist/esm/index.js",
6
6
  "module": "./dist/esm/index.js",
@@ -71,12 +71,12 @@
71
71
  "dependencies": {
72
72
  "@aws-sdk/client-cloudwatch-logs": "^3.1123.0",
73
73
  "@remix-run/node": "^2.8.1",
74
- "@zauru-sdk/common": "^6.8.6",
74
+ "@zauru-sdk/common": "^6.9.0",
75
75
  "@zauru-sdk/config": "^6.0.0",
76
76
  "@zauru-sdk/graphql": "^6.8.0",
77
- "@zauru-sdk/services": "^6.11.9",
77
+ "@zauru-sdk/services": "^6.11.10",
78
78
  "@zauru-sdk/types": "^6.24.0",
79
79
  "moment": "^2.30.1"
80
80
  },
81
- "gitHead": "7020f7ea3b89b2c07998a5f7eb8586452c0cdc28"
81
+ "gitHead": "a46ebe234551d76d6a0ea9095be6e55540006ab3"
82
82
  }