@monocloud/auth-nextjs 0.1.1 → 0.1.2
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/dist/client/index.cjs +1 -1
- package/dist/client/index.d.mts +136 -3
- package/dist/client/index.mjs +1 -1
- package/dist/{client-BjnSJS59.cjs → client-Be6A2vEn.cjs} +149 -10
- package/dist/client-Be6A2vEn.cjs.map +1 -0
- package/dist/client-CnvBgZM-.mjs +244 -0
- package/dist/client-CnvBgZM-.mjs.map +1 -0
- package/dist/components/client/index.cjs +156 -3
- package/dist/components/client/index.cjs.map +1 -1
- package/dist/components/client/index.d.mts +156 -3
- package/dist/components/client/index.mjs +156 -3
- package/dist/components/client/index.mjs.map +1 -1
- package/dist/components/index.cjs +84 -1
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.d.mts +86 -1
- package/dist/components/index.mjs +84 -1
- package/dist/components/index.mjs.map +1 -1
- package/dist/index.cjs +716 -333
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +1890 -56
- package/dist/index.mjs +691 -308
- package/dist/index.mjs.map +1 -1
- package/dist/{types-BleaXQUP.d.mts → types-DOfZTKa6.d.mts} +90 -141
- package/package.json +2 -2
- package/dist/client-0gaUvMR7.mjs +0 -105
- package/dist/client-0gaUvMR7.mjs.map +0 -1
- package/dist/client-BjnSJS59.cjs.map +0 -1
package/dist/client/index.cjs
CHANGED
package/dist/client/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as GroupOptions, i as ExtraAuthParams } from "../types-DOfZTKa6.mjs";
|
|
2
2
|
import { MonoCloudUser } from "@monocloud/auth-node-core";
|
|
3
3
|
import React, { ComponentType, JSX } from "react";
|
|
4
4
|
|
|
@@ -25,11 +25,88 @@ interface AuthState {
|
|
|
25
25
|
user?: MonoCloudUser;
|
|
26
26
|
/**
|
|
27
27
|
* Function to refetch the authentication state.
|
|
28
|
+
*
|
|
28
29
|
*/
|
|
29
|
-
refetch?:
|
|
30
|
+
refetch: (refresh?: boolean) => void;
|
|
30
31
|
}
|
|
31
32
|
/**
|
|
33
|
+
*
|
|
34
|
+
* Hook for getting the user's profile on client components
|
|
35
|
+
*
|
|
32
36
|
* @returns Authentication State
|
|
37
|
+
*
|
|
38
|
+
* @example App Router
|
|
39
|
+
*
|
|
40
|
+
* ```tsx
|
|
41
|
+
* "use client";
|
|
42
|
+
*
|
|
43
|
+
* import { useAuth } from "@monocloud/auth-nextjs/client";
|
|
44
|
+
*
|
|
45
|
+
* export default function Home() {
|
|
46
|
+
* const { user } = useAuth();
|
|
47
|
+
*
|
|
48
|
+
* return <>User Id: {user?.sub}</>;
|
|
49
|
+
* }
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
* @example App Router - Refetch user from Userinfo endpoint
|
|
53
|
+
*
|
|
54
|
+
* Calling `refetch(true)` will force refresh the user's profile from the userinfo endpoint.
|
|
55
|
+
* If you do not intent to refersh from your tenants userinfo endpoint, use just `refetch()`
|
|
56
|
+
*
|
|
57
|
+
* **Note⚠️: You need to set the env `MONOCLOUD_AUTH_ALLOW_QUERY_PARAM_OVERRIDES=true` or `allowQueryParamOverrides` should be `true` in the client initialization for force refresh to work**
|
|
58
|
+
*
|
|
59
|
+
* ```tsx
|
|
60
|
+
* "use client";
|
|
61
|
+
*
|
|
62
|
+
* import { useAuth } from "@monocloud/auth-nextjs/client";
|
|
63
|
+
*
|
|
64
|
+
* export default function Home() {
|
|
65
|
+
* const { user, refetch } = useAuth();
|
|
66
|
+
*
|
|
67
|
+
* return (
|
|
68
|
+
* <>
|
|
69
|
+
* <pre>{JSON.stringify(user)}</pre>
|
|
70
|
+
* <button onClick={() => refetch(true)}>Refresh</button>
|
|
71
|
+
* </>
|
|
72
|
+
* );
|
|
73
|
+
* }
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* @example Pages Router
|
|
77
|
+
*
|
|
78
|
+
* ```tsx
|
|
79
|
+
* import { useAuth } from "@monocloud/auth-nextjs/client";
|
|
80
|
+
*
|
|
81
|
+
* export default function Home() {
|
|
82
|
+
* const { user } = useAuth();
|
|
83
|
+
*
|
|
84
|
+
* return <>User Id: {user?.sub}</>;
|
|
85
|
+
* }
|
|
86
|
+
* ```
|
|
87
|
+
*
|
|
88
|
+
* @example Pages Router - Refetch user from Userinfo endpoint
|
|
89
|
+
*
|
|
90
|
+
* Calling `refetch(true)` will force refresh the user's profile from the userinfo endpoint.
|
|
91
|
+
* If you do not intent to refersh from your tenants userinfo endpoint, use just `refetch()`
|
|
92
|
+
*
|
|
93
|
+
* **Note⚠️: You need to set the env `MONOCLOUD_AUTH_ALLOW_QUERY_PARAM_OVERRIDES=true` or `allowQueryParamOverrides` should be `true` in the client initialization for force refresh to work**
|
|
94
|
+
*
|
|
95
|
+
* ```tsx
|
|
96
|
+
* import { useAuth } from "@monocloud/auth-nextjs/client";
|
|
97
|
+
*
|
|
98
|
+
* export default function Home() {
|
|
99
|
+
* const { user, refetch } = useAuth();
|
|
100
|
+
*
|
|
101
|
+
* return (
|
|
102
|
+
* <>
|
|
103
|
+
* <pre>{JSON.stringify(user)}</pre>
|
|
104
|
+
* <button onClick={() => refetch(true)}>Refresh</button>
|
|
105
|
+
* </>
|
|
106
|
+
* );
|
|
107
|
+
* }
|
|
108
|
+
* ```
|
|
109
|
+
*
|
|
33
110
|
*/
|
|
34
111
|
declare const useAuth: () => AuthState;
|
|
35
112
|
//#endregion
|
|
@@ -63,10 +140,66 @@ type ProtectPageOptions = {
|
|
|
63
140
|
* Function to protect a client rendered page component.
|
|
64
141
|
* Ensures that only authenticated users can access the component.
|
|
65
142
|
*
|
|
143
|
+
* **Note⚠️: Since `window.location` is set as `returnUrl` query param by default, you need to set the env `MONOCLOUD_AUTH_ALLOW_QUERY_PARAM_OVERRIDES=true` or `allowQueryParamOverrides` should be `true` in the client initialization for returning to the same page.**
|
|
144
|
+
*
|
|
66
145
|
* @param Component - The component to protect.
|
|
67
146
|
* @param options - The options.
|
|
68
147
|
*
|
|
69
|
-
* @returns Protected
|
|
148
|
+
* @returns Protected client rendered page component.
|
|
149
|
+
*
|
|
150
|
+
* @example App Router
|
|
151
|
+
*
|
|
152
|
+
* ```tsx
|
|
153
|
+
* "use client";
|
|
154
|
+
*
|
|
155
|
+
* import { protectPage } from "@monocloud/auth-nextjs/client";
|
|
156
|
+
*
|
|
157
|
+
* export default protectPage(function Home() {
|
|
158
|
+
* return <>You are signed in</>;
|
|
159
|
+
* });
|
|
160
|
+
* ```
|
|
161
|
+
*
|
|
162
|
+
* @example App Router with options
|
|
163
|
+
*
|
|
164
|
+
* See {@link ProtectPageOptions} for more options.
|
|
165
|
+
*
|
|
166
|
+
* ```tsx
|
|
167
|
+
* "use client";
|
|
168
|
+
*
|
|
169
|
+
* import { protectPage } from "@monocloud/auth-nextjs/client";
|
|
170
|
+
*
|
|
171
|
+
* export default protectPage(
|
|
172
|
+
* function Home() {
|
|
173
|
+
* return <>You are signed in</>;
|
|
174
|
+
* },
|
|
175
|
+
* { returnUrl: "/dashboard", authParams: { loginHint: "username" } }
|
|
176
|
+
* );
|
|
177
|
+
* ```
|
|
178
|
+
|
|
179
|
+
* @example Pages Router
|
|
180
|
+
*
|
|
181
|
+
* ```tsx
|
|
182
|
+
* import { protectPage } from "@monocloud/auth-nextjs/client";
|
|
183
|
+
*
|
|
184
|
+
* export default protectPage(function Home() {
|
|
185
|
+
* return <>You are signed in</>;
|
|
186
|
+
* });
|
|
187
|
+
* ```
|
|
188
|
+
*
|
|
189
|
+
* @example Pages Router with options
|
|
190
|
+
*
|
|
191
|
+
* See {@link ProtectPageOptions} for more options.
|
|
192
|
+
*
|
|
193
|
+
* ```tsx
|
|
194
|
+
* import { protectPage } from "@monocloud/auth-nextjs/client";
|
|
195
|
+
*
|
|
196
|
+
* export default protectPage(
|
|
197
|
+
* function Home() {
|
|
198
|
+
* return <>You are signed in</>;
|
|
199
|
+
* },
|
|
200
|
+
* { returnUrl: "/dashboard", authParams: { loginHint: "username" } }
|
|
201
|
+
* );
|
|
202
|
+
* ```
|
|
70
203
|
*/
|
|
71
204
|
declare const protectPage: <P extends object>(Component: ComponentType<P & {
|
|
72
205
|
user: MonoCloudUser;
|
package/dist/client/index.mjs
CHANGED
|
@@ -6,29 +6,112 @@ let react = require("react");
|
|
|
6
6
|
react = require_chunk.__toESM(react);
|
|
7
7
|
|
|
8
8
|
//#region src/client/use-auth.tsx
|
|
9
|
+
const fetchUser = async (url) => {
|
|
10
|
+
const res = await fetch(url, { credentials: "include" });
|
|
11
|
+
if (res.status === 204) return;
|
|
12
|
+
if (res.ok) return res.json();
|
|
13
|
+
throw new Error("Failed to fetch user");
|
|
14
|
+
};
|
|
9
15
|
/**
|
|
16
|
+
*
|
|
17
|
+
* Hook for getting the user's profile on client components
|
|
18
|
+
*
|
|
10
19
|
* @returns Authentication State
|
|
20
|
+
*
|
|
21
|
+
* @example App Router
|
|
22
|
+
*
|
|
23
|
+
* ```tsx
|
|
24
|
+
* "use client";
|
|
25
|
+
*
|
|
26
|
+
* import { useAuth } from "@monocloud/auth-nextjs/client";
|
|
27
|
+
*
|
|
28
|
+
* export default function Home() {
|
|
29
|
+
* const { user } = useAuth();
|
|
30
|
+
*
|
|
31
|
+
* return <>User Id: {user?.sub}</>;
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* @example App Router - Refetch user from Userinfo endpoint
|
|
36
|
+
*
|
|
37
|
+
* Calling `refetch(true)` will force refresh the user's profile from the userinfo endpoint.
|
|
38
|
+
* If you do not intent to refersh from your tenants userinfo endpoint, use just `refetch()`
|
|
39
|
+
*
|
|
40
|
+
* **Note⚠️: You need to set the env `MONOCLOUD_AUTH_ALLOW_QUERY_PARAM_OVERRIDES=true` or `allowQueryParamOverrides` should be `true` in the client initialization for force refresh to work**
|
|
41
|
+
*
|
|
42
|
+
* ```tsx
|
|
43
|
+
* "use client";
|
|
44
|
+
*
|
|
45
|
+
* import { useAuth } from "@monocloud/auth-nextjs/client";
|
|
46
|
+
*
|
|
47
|
+
* export default function Home() {
|
|
48
|
+
* const { user, refetch } = useAuth();
|
|
49
|
+
*
|
|
50
|
+
* return (
|
|
51
|
+
* <>
|
|
52
|
+
* <pre>{JSON.stringify(user)}</pre>
|
|
53
|
+
* <button onClick={() => refetch(true)}>Refresh</button>
|
|
54
|
+
* </>
|
|
55
|
+
* );
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* @example Pages Router
|
|
60
|
+
*
|
|
61
|
+
* ```tsx
|
|
62
|
+
* import { useAuth } from "@monocloud/auth-nextjs/client";
|
|
63
|
+
*
|
|
64
|
+
* export default function Home() {
|
|
65
|
+
* const { user } = useAuth();
|
|
66
|
+
*
|
|
67
|
+
* return <>User Id: {user?.sub}</>;
|
|
68
|
+
* }
|
|
69
|
+
* ```
|
|
70
|
+
*
|
|
71
|
+
* @example Pages Router - Refetch user from Userinfo endpoint
|
|
72
|
+
*
|
|
73
|
+
* Calling `refetch(true)` will force refresh the user's profile from the userinfo endpoint.
|
|
74
|
+
* If you do not intent to refersh from your tenants userinfo endpoint, use just `refetch()`
|
|
75
|
+
*
|
|
76
|
+
* **Note⚠️: You need to set the env `MONOCLOUD_AUTH_ALLOW_QUERY_PARAM_OVERRIDES=true` or `allowQueryParamOverrides` should be `true` in the client initialization for force refresh to work**
|
|
77
|
+
*
|
|
78
|
+
* ```tsx
|
|
79
|
+
* import { useAuth } from "@monocloud/auth-nextjs/client";
|
|
80
|
+
*
|
|
81
|
+
* export default function Home() {
|
|
82
|
+
* const { user, refetch } = useAuth();
|
|
83
|
+
*
|
|
84
|
+
* return (
|
|
85
|
+
* <>
|
|
86
|
+
* <pre>{JSON.stringify(user)}</pre>
|
|
87
|
+
* <button onClick={() => refetch(true)}>Refresh</button>
|
|
88
|
+
* </>
|
|
89
|
+
* );
|
|
90
|
+
* }
|
|
91
|
+
* ```
|
|
92
|
+
*
|
|
11
93
|
*/
|
|
12
94
|
const useAuth = () => {
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
95
|
+
const key = process.env.NEXT_PUBLIC_MONOCLOUD_AUTH_USER_INFO_URL ?? `${process.env.__NEXT_ROUTER_BASEPATH ?? ""}/api/auth/userinfo`;
|
|
96
|
+
const { data, error, isLoading, mutate } = (0, swr.default)(key, fetchUser);
|
|
97
|
+
const refetch = (refresh) => {
|
|
98
|
+
const url = new URL(key, "https://dummy");
|
|
99
|
+
if (refresh) url.searchParams.set("refresh", "true");
|
|
100
|
+
mutate(async () => await fetchUser(url.pathname + url.search), { revalidate: false });
|
|
101
|
+
};
|
|
19
102
|
if (error) return {
|
|
20
103
|
user: void 0,
|
|
21
104
|
isLoading: false,
|
|
22
105
|
isAuthenticated: false,
|
|
23
106
|
error,
|
|
24
|
-
refetch
|
|
107
|
+
refetch
|
|
25
108
|
};
|
|
26
109
|
if (data) return {
|
|
27
110
|
user: data,
|
|
28
111
|
isLoading,
|
|
29
112
|
isAuthenticated: !!data && Object.keys(data).length > 0,
|
|
30
113
|
error: void 0,
|
|
31
|
-
refetch
|
|
114
|
+
refetch
|
|
32
115
|
};
|
|
33
116
|
return {
|
|
34
117
|
user: void 0,
|
|
@@ -64,11 +147,67 @@ const handlePageError = (error, options) => {
|
|
|
64
147
|
/**
|
|
65
148
|
* Function to protect a client rendered page component.
|
|
66
149
|
* Ensures that only authenticated users can access the component.
|
|
150
|
+
*
|
|
151
|
+
* **Note⚠️: Since `window.location` is set as `returnUrl` query param by default, you need to set the env `MONOCLOUD_AUTH_ALLOW_QUERY_PARAM_OVERRIDES=true` or `allowQueryParamOverrides` should be `true` in the client initialization for returning to the same page.**
|
|
67
152
|
*
|
|
68
153
|
* @param Component - The component to protect.
|
|
69
154
|
* @param options - The options.
|
|
70
155
|
*
|
|
71
|
-
* @returns Protected
|
|
156
|
+
* @returns Protected client rendered page component.
|
|
157
|
+
*
|
|
158
|
+
* @example App Router
|
|
159
|
+
*
|
|
160
|
+
* ```tsx
|
|
161
|
+
* "use client";
|
|
162
|
+
*
|
|
163
|
+
* import { protectPage } from "@monocloud/auth-nextjs/client";
|
|
164
|
+
*
|
|
165
|
+
* export default protectPage(function Home() {
|
|
166
|
+
* return <>You are signed in</>;
|
|
167
|
+
* });
|
|
168
|
+
* ```
|
|
169
|
+
*
|
|
170
|
+
* @example App Router with options
|
|
171
|
+
*
|
|
172
|
+
* See {@link ProtectPageOptions} for more options.
|
|
173
|
+
*
|
|
174
|
+
* ```tsx
|
|
175
|
+
* "use client";
|
|
176
|
+
*
|
|
177
|
+
* import { protectPage } from "@monocloud/auth-nextjs/client";
|
|
178
|
+
*
|
|
179
|
+
* export default protectPage(
|
|
180
|
+
* function Home() {
|
|
181
|
+
* return <>You are signed in</>;
|
|
182
|
+
* },
|
|
183
|
+
* { returnUrl: "/dashboard", authParams: { loginHint: "username" } }
|
|
184
|
+
* );
|
|
185
|
+
* ```
|
|
186
|
+
|
|
187
|
+
* @example Pages Router
|
|
188
|
+
*
|
|
189
|
+
* ```tsx
|
|
190
|
+
* import { protectPage } from "@monocloud/auth-nextjs/client";
|
|
191
|
+
*
|
|
192
|
+
* export default protectPage(function Home() {
|
|
193
|
+
* return <>You are signed in</>;
|
|
194
|
+
* });
|
|
195
|
+
* ```
|
|
196
|
+
*
|
|
197
|
+
* @example Pages Router with options
|
|
198
|
+
*
|
|
199
|
+
* See {@link ProtectPageOptions} for more options.
|
|
200
|
+
*
|
|
201
|
+
* ```tsx
|
|
202
|
+
* import { protectPage } from "@monocloud/auth-nextjs/client";
|
|
203
|
+
*
|
|
204
|
+
* export default protectPage(
|
|
205
|
+
* function Home() {
|
|
206
|
+
* return <>You are signed in</>;
|
|
207
|
+
* },
|
|
208
|
+
* { returnUrl: "/dashboard", authParams: { loginHint: "username" } }
|
|
209
|
+
* );
|
|
210
|
+
* ```
|
|
72
211
|
*/
|
|
73
212
|
const protectPage = (Component, options) => {
|
|
74
213
|
return (props) => {
|
|
@@ -122,4 +261,4 @@ Object.defineProperty(exports, 'useAuth', {
|
|
|
122
261
|
return useAuth;
|
|
123
262
|
}
|
|
124
263
|
});
|
|
125
|
-
//# sourceMappingURL=client-
|
|
264
|
+
//# sourceMappingURL=client-Be6A2vEn.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-Be6A2vEn.cjs","names":[],"sources":["../src/client/use-auth.tsx","../src/client/protect.tsx"],"sourcesContent":["'use client';\n\nimport type { MonoCloudUser } from '@monocloud/auth-node-core';\nimport useSWR from 'swr';\n\n/**\n * Authentication State returned by `useAuth` hook.\n */\nexport interface AuthState {\n /**\n * Flag indicating if the authentication state is still loading.\n */\n isLoading: boolean;\n /**\n * Flag indicating if the user is authenticated.\n */\n isAuthenticated: boolean;\n /**\n * Error encountered during authentication, if any.\n */\n error?: Error;\n /**\n * The authenticated user's information, if available.\n */\n user?: MonoCloudUser;\n /**\n * Function to refetch the authentication state.\n *\n */\n refetch: (refresh?: boolean) => void;\n}\n\nconst fetchUser = async (url: string): Promise<MonoCloudUser | undefined> => {\n const res = await fetch(url, { credentials: 'include' });\n\n if (res.status === 204) {\n return undefined;\n }\n\n if (res.ok) {\n return res.json();\n }\n\n throw new Error('Failed to fetch user');\n};\n\n/**\n *\n * Hook for getting the user's profile on client components\n *\n * @returns Authentication State\n *\n * @example App Router\n *\n * ```tsx\n * \"use client\";\n *\n * import { useAuth } from \"@monocloud/auth-nextjs/client\";\n *\n * export default function Home() {\n * const { user } = useAuth();\n *\n * return <>User Id: {user?.sub}</>;\n * }\n * ```\n *\n * @example App Router - Refetch user from Userinfo endpoint\n *\n * Calling `refetch(true)` will force refresh the user's profile from the userinfo endpoint.\n * If you do not intent to refersh from your tenants userinfo endpoint, use just `refetch()`\n *\n * **Note⚠️: You need to set the env `MONOCLOUD_AUTH_ALLOW_QUERY_PARAM_OVERRIDES=true` or `allowQueryParamOverrides` should be `true` in the client initialization for force refresh to work**\n *\n * ```tsx\n * \"use client\";\n *\n * import { useAuth } from \"@monocloud/auth-nextjs/client\";\n *\n * export default function Home() {\n * const { user, refetch } = useAuth();\n *\n * return (\n * <>\n * <pre>{JSON.stringify(user)}</pre>\n * <button onClick={() => refetch(true)}>Refresh</button>\n * </>\n * );\n * }\n * ```\n *\n * @example Pages Router\n *\n * ```tsx\n * import { useAuth } from \"@monocloud/auth-nextjs/client\";\n *\n * export default function Home() {\n * const { user } = useAuth();\n *\n * return <>User Id: {user?.sub}</>;\n * }\n * ```\n *\n * @example Pages Router - Refetch user from Userinfo endpoint\n *\n * Calling `refetch(true)` will force refresh the user's profile from the userinfo endpoint.\n * If you do not intent to refersh from your tenants userinfo endpoint, use just `refetch()`\n *\n * **Note⚠️: You need to set the env `MONOCLOUD_AUTH_ALLOW_QUERY_PARAM_OVERRIDES=true` or `allowQueryParamOverrides` should be `true` in the client initialization for force refresh to work**\n *\n * ```tsx\n * import { useAuth } from \"@monocloud/auth-nextjs/client\";\n *\n * export default function Home() {\n * const { user, refetch } = useAuth();\n *\n * return (\n * <>\n * <pre>{JSON.stringify(user)}</pre>\n * <button onClick={() => refetch(true)}>Refresh</button>\n * </>\n * );\n * }\n * ```\n *\n */\nexport const useAuth = (): AuthState => {\n const key =\n process.env.NEXT_PUBLIC_MONOCLOUD_AUTH_USER_INFO_URL ??\n // eslint-disable-next-line no-underscore-dangle\n `${process.env.__NEXT_ROUTER_BASEPATH ?? ''}/api/auth/userinfo`;\n\n const { data, error, isLoading, mutate } = useSWR<MonoCloudUser | undefined>(\n key,\n fetchUser\n );\n\n const refetch = (refresh?: boolean): void => {\n const url = new URL(key, 'https://dummy');\n if (refresh) {\n url.searchParams.set('refresh', 'true');\n }\n\n void mutate(async () => await fetchUser(url.pathname + url.search), {\n revalidate: false,\n });\n };\n\n if (error) {\n return {\n user: undefined,\n isLoading: false,\n isAuthenticated: false,\n error: error as Error,\n refetch,\n };\n }\n\n if (data) {\n return {\n user: data,\n isLoading,\n isAuthenticated: !!data && Object.keys(data).length > 0,\n error: undefined,\n refetch,\n };\n }\n\n return {\n user: undefined,\n isLoading,\n isAuthenticated: false,\n error: undefined,\n /* v8 ignore next -- @preserve */\n refetch: (): void => {},\n };\n};\n","/* eslint-disable react/display-name */\n'use client';\n\nimport React, { ComponentType, JSX, useEffect } from 'react';\nimport type { MonoCloudUser } from '@monocloud/auth-node-core';\nimport { isUserInGroup } from '@monocloud/auth-node-core/utils';\nimport { useAuth } from './use-auth';\nimport { ExtraAuthParams, GroupOptions } from '../types';\n\n/**\n * Options for configuring page protection.\n */\nexport type ProtectPageOptions = {\n /**\n *The url where the user will be redirected to after sign in\n */\n returnUrl?: string;\n\n /**\n * A custom react element to render when the user is not authenticated or is not a member of the specified groups.\n */\n onAccessDenied?: (user?: MonoCloudUser) => JSX.Element;\n\n /**\n * Authorization parameters to be used during authentication.\n */\n authParams?: ExtraAuthParams;\n\n /**\n * Callback function to handle errors.\n * If not provided, errors will be thrown.\n *\n * @param error - The error object.\n * @returns JSX element to handle the error.\n */\n onError?: (error: Error) => JSX.Element;\n} & GroupOptions;\n\nexport const redirectToSignIn = (\n options: { returnUrl?: string } & ExtraAuthParams\n): void => {\n const searchParams = new URLSearchParams(window.location.search);\n searchParams.set(\n 'return_url',\n options.returnUrl ?? window.location.toString()\n );\n\n if (options?.scopes) {\n searchParams.set('scope', options.scopes);\n }\n if (options?.resource) {\n searchParams.set('resource', options.resource);\n }\n\n if (options?.acrValues) {\n searchParams.set('acr_values', options.acrValues.join(' '));\n }\n\n if (options?.display) {\n searchParams.set('display', options.display);\n }\n\n if (options?.prompt) {\n searchParams.set('prompt', options.prompt);\n }\n\n if (options?.authenticatorHint) {\n searchParams.set('authenticator_hint', options.authenticatorHint);\n }\n\n if (options?.uiLocales) {\n searchParams.set('ui_locales', options.uiLocales);\n }\n\n if (options?.maxAge) {\n searchParams.set('max_age', options.maxAge.toString());\n }\n\n if (options?.loginHint) {\n searchParams.set('login_hint', options.loginHint);\n }\n\n window.location.assign(\n // eslint-disable-next-line no-underscore-dangle\n `${process.env.NEXT_PUBLIC_MONOCLOUD_AUTH_SIGNIN_URL ?? `${process.env.__NEXT_ROUTER_BASEPATH ?? ''}/api/auth/signin`}?${searchParams.toString()}`\n );\n};\n\nconst handlePageError = (\n error: Error,\n options?: ProtectPageOptions\n): JSX.Element => {\n /* v8 ignore else -- @preserve */\n if (options?.onError) {\n return options.onError(error);\n }\n\n /* v8 ignore next -- @preserve */\n throw error;\n};\n\n/**\n * Function to protect a client rendered page component.\n * Ensures that only authenticated users can access the component.\n * \n * **Note⚠️: Since `window.location` is set as `returnUrl` query param by default, you need to set the env `MONOCLOUD_AUTH_ALLOW_QUERY_PARAM_OVERRIDES=true` or `allowQueryParamOverrides` should be `true` in the client initialization for returning to the same page.**\n *\n * @param Component - The component to protect.\n * @param options - The options.\n *\n * @returns Protected client rendered page component.\n *\n * @example App Router\n *\n * ```tsx\n * \"use client\";\n *\n * import { protectPage } from \"@monocloud/auth-nextjs/client\";\n *\n * export default protectPage(function Home() {\n * return <>You are signed in</>;\n * });\n * ```\n *\n * @example App Router with options\n * \n * See {@link ProtectPageOptions} for more options.\n *\n * ```tsx\n * \"use client\";\n *\n * import { protectPage } from \"@monocloud/auth-nextjs/client\";\n *\n * export default protectPage(\n * function Home() {\n * return <>You are signed in</>;\n * },\n * { returnUrl: \"/dashboard\", authParams: { loginHint: \"username\" } }\n * );\n * ```\n\n* @example Pages Router\n *\n * ```tsx\n * import { protectPage } from \"@monocloud/auth-nextjs/client\";\n *\n * export default protectPage(function Home() {\n * return <>You are signed in</>;\n * });\n * ```\n *\n * @example Pages Router with options\n * \n * See {@link ProtectPageOptions} for more options.\n *\n * ```tsx\n * import { protectPage } from \"@monocloud/auth-nextjs/client\";\n *\n * export default protectPage(\n * function Home() {\n * return <>You are signed in</>;\n * },\n * { returnUrl: \"/dashboard\", authParams: { loginHint: \"username\" } }\n * );\n * ```\n */\nexport const protectPage = <P extends object>(\n Component: ComponentType<P & { user: MonoCloudUser }>,\n options?: ProtectPageOptions\n): React.FC<P> => {\n return props => {\n const { user, error, isLoading } = useAuth();\n\n useEffect(() => {\n if (!user && !isLoading && !error) {\n if (options?.onAccessDenied) {\n return;\n }\n\n const authParams = options?.authParams ?? {};\n redirectToSignIn({\n returnUrl: options?.returnUrl,\n ...authParams,\n });\n }\n }, [user, isLoading, error]);\n\n if (error) {\n return handlePageError(error, options);\n }\n\n if (!user && !isLoading && options?.onAccessDenied) {\n return options.onAccessDenied();\n }\n\n if (user) {\n if (\n options?.groups &&\n !isUserInGroup(\n user,\n options.groups,\n options.groupsClaim ??\n process.env.NEXT_PUBLIC_MONOCLOUD_AUTH_GROUPS_CLAIM,\n options.matchAll\n )\n ) {\n const { onAccessDenied = (): JSX.Element => <div>Access Denied</div> } =\n options;\n return onAccessDenied(user);\n }\n\n return <Component user={user} {...props} />;\n }\n\n return null;\n };\n};\n"],"mappings":";;;;;;;;AAgCA,MAAM,YAAY,OAAO,QAAoD;CAC3E,MAAM,MAAM,MAAM,MAAM,KAAK,EAAE,aAAa,WAAW,CAAC;AAExD,KAAI,IAAI,WAAW,IACjB;AAGF,KAAI,IAAI,GACN,QAAO,IAAI,MAAM;AAGnB,OAAM,IAAI,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkFzC,MAAa,gBAA2B;CACtC,MAAM,MACJ,QAAQ,IAAI,4CAEZ,GAAG,QAAQ,IAAI,0BAA0B,GAAG;CAE9C,MAAM,EAAE,MAAM,OAAO,WAAW,4BAC9B,KACA,UACD;CAED,MAAM,WAAW,YAA4B;EAC3C,MAAM,MAAM,IAAI,IAAI,KAAK,gBAAgB;AACzC,MAAI,QACF,KAAI,aAAa,IAAI,WAAW,OAAO;AAGzC,EAAK,OAAO,YAAY,MAAM,UAAU,IAAI,WAAW,IAAI,OAAO,EAAE,EAClE,YAAY,OACb,CAAC;;AAGJ,KAAI,MACF,QAAO;EACL,MAAM;EACN,WAAW;EACX,iBAAiB;EACV;EACP;EACD;AAGH,KAAI,KACF,QAAO;EACL,MAAM;EACN;EACA,iBAAiB,CAAC,CAAC,QAAQ,OAAO,KAAK,KAAK,CAAC,SAAS;EACtD,OAAO;EACP;EACD;AAGH,QAAO;EACL,MAAM;EACN;EACA,iBAAiB;EACjB,OAAO;EAEP,eAAqB;EACtB;;;;;ACxIH,MAAa,oBACX,YACS;CACT,MAAM,eAAe,IAAI,gBAAgB,OAAO,SAAS,OAAO;AAChE,cAAa,IACX,cACA,QAAQ,aAAa,OAAO,SAAS,UAAU,CAChD;AAED,uDAAI,QAAS,OACX,cAAa,IAAI,SAAS,QAAQ,OAAO;AAE3C,uDAAI,QAAS,SACX,cAAa,IAAI,YAAY,QAAQ,SAAS;AAGhD,uDAAI,QAAS,UACX,cAAa,IAAI,cAAc,QAAQ,UAAU,KAAK,IAAI,CAAC;AAG7D,uDAAI,QAAS,QACX,cAAa,IAAI,WAAW,QAAQ,QAAQ;AAG9C,uDAAI,QAAS,OACX,cAAa,IAAI,UAAU,QAAQ,OAAO;AAG5C,uDAAI,QAAS,kBACX,cAAa,IAAI,sBAAsB,QAAQ,kBAAkB;AAGnE,uDAAI,QAAS,UACX,cAAa,IAAI,cAAc,QAAQ,UAAU;AAGnD,uDAAI,QAAS,OACX,cAAa,IAAI,WAAW,QAAQ,OAAO,UAAU,CAAC;AAGxD,uDAAI,QAAS,UACX,cAAa,IAAI,cAAc,QAAQ,UAAU;AAGnD,QAAO,SAAS,OAEd,GAAG,QAAQ,IAAI,yCAAyC,GAAG,QAAQ,IAAI,0BAA0B,GAAG,kBAAkB,GAAG,aAAa,UAAU,GACjJ;;AAGH,MAAM,mBACJ,OACA,YACgB;;AAEhB,uDAAI,QAAS,QACX,QAAO,QAAQ,QAAQ,MAAM;;AAI/B,OAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoER,MAAa,eACX,WACA,YACgB;AAChB,SAAO,UAAS;EACd,MAAM,EAAE,MAAM,OAAO,cAAc,SAAS;AAE5C,6BAAgB;AACd,OAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO;AACjC,0DAAI,QAAS,eACX;IAGF,MAAM,gEAAa,QAAS,eAAc,EAAE;AAC5C,qBAAiB;KACf,6DAAW,QAAS;KACpB,GAAG;KACJ,CAAC;;KAEH;GAAC;GAAM;GAAW;GAAM,CAAC;AAE5B,MAAI,MACF,QAAO,gBAAgB,OAAO,QAAQ;AAGxC,MAAI,CAAC,QAAQ,CAAC,gEAAa,QAAS,gBAClC,QAAO,QAAQ,gBAAgB;AAGjC,MAAI,MAAM;AACR,0DACE,QAAS,WACT,oDACE,MACA,QAAQ,QACR,QAAQ,eACN,QAAQ,IAAI,yCACd,QAAQ,SACT,EACD;IACA,MAAM,EAAE,uBAAoC,4CAAC,aAAI,gBAAmB,KAClE;AACF,WAAO,eAAe,KAAK;;AAG7B,UAAO,4CAAC;IAAgB;IAAM,GAAI;KAAS;;AAG7C,SAAO"}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { isUserInGroup } from "@monocloud/auth-node-core/utils";
|
|
2
|
+
import useSWR from "swr";
|
|
3
|
+
import React, { useEffect } from "react";
|
|
4
|
+
|
|
5
|
+
//#region src/client/use-auth.tsx
|
|
6
|
+
const fetchUser = async (url) => {
|
|
7
|
+
const res = await fetch(url, { credentials: "include" });
|
|
8
|
+
if (res.status === 204) return;
|
|
9
|
+
if (res.ok) return res.json();
|
|
10
|
+
throw new Error("Failed to fetch user");
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
* Hook for getting the user's profile on client components
|
|
15
|
+
*
|
|
16
|
+
* @returns Authentication State
|
|
17
|
+
*
|
|
18
|
+
* @example App Router
|
|
19
|
+
*
|
|
20
|
+
* ```tsx
|
|
21
|
+
* "use client";
|
|
22
|
+
*
|
|
23
|
+
* import { useAuth } from "@monocloud/auth-nextjs/client";
|
|
24
|
+
*
|
|
25
|
+
* export default function Home() {
|
|
26
|
+
* const { user } = useAuth();
|
|
27
|
+
*
|
|
28
|
+
* return <>User Id: {user?.sub}</>;
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @example App Router - Refetch user from Userinfo endpoint
|
|
33
|
+
*
|
|
34
|
+
* Calling `refetch(true)` will force refresh the user's profile from the userinfo endpoint.
|
|
35
|
+
* If you do not intent to refersh from your tenants userinfo endpoint, use just `refetch()`
|
|
36
|
+
*
|
|
37
|
+
* **Note⚠️: You need to set the env `MONOCLOUD_AUTH_ALLOW_QUERY_PARAM_OVERRIDES=true` or `allowQueryParamOverrides` should be `true` in the client initialization for force refresh to work**
|
|
38
|
+
*
|
|
39
|
+
* ```tsx
|
|
40
|
+
* "use client";
|
|
41
|
+
*
|
|
42
|
+
* import { useAuth } from "@monocloud/auth-nextjs/client";
|
|
43
|
+
*
|
|
44
|
+
* export default function Home() {
|
|
45
|
+
* const { user, refetch } = useAuth();
|
|
46
|
+
*
|
|
47
|
+
* return (
|
|
48
|
+
* <>
|
|
49
|
+
* <pre>{JSON.stringify(user)}</pre>
|
|
50
|
+
* <button onClick={() => refetch(true)}>Refresh</button>
|
|
51
|
+
* </>
|
|
52
|
+
* );
|
|
53
|
+
* }
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* @example Pages Router
|
|
57
|
+
*
|
|
58
|
+
* ```tsx
|
|
59
|
+
* import { useAuth } from "@monocloud/auth-nextjs/client";
|
|
60
|
+
*
|
|
61
|
+
* export default function Home() {
|
|
62
|
+
* const { user } = useAuth();
|
|
63
|
+
*
|
|
64
|
+
* return <>User Id: {user?.sub}</>;
|
|
65
|
+
* }
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* @example Pages Router - Refetch user from Userinfo endpoint
|
|
69
|
+
*
|
|
70
|
+
* Calling `refetch(true)` will force refresh the user's profile from the userinfo endpoint.
|
|
71
|
+
* If you do not intent to refersh from your tenants userinfo endpoint, use just `refetch()`
|
|
72
|
+
*
|
|
73
|
+
* **Note⚠️: You need to set the env `MONOCLOUD_AUTH_ALLOW_QUERY_PARAM_OVERRIDES=true` or `allowQueryParamOverrides` should be `true` in the client initialization for force refresh to work**
|
|
74
|
+
*
|
|
75
|
+
* ```tsx
|
|
76
|
+
* import { useAuth } from "@monocloud/auth-nextjs/client";
|
|
77
|
+
*
|
|
78
|
+
* export default function Home() {
|
|
79
|
+
* const { user, refetch } = useAuth();
|
|
80
|
+
*
|
|
81
|
+
* return (
|
|
82
|
+
* <>
|
|
83
|
+
* <pre>{JSON.stringify(user)}</pre>
|
|
84
|
+
* <button onClick={() => refetch(true)}>Refresh</button>
|
|
85
|
+
* </>
|
|
86
|
+
* );
|
|
87
|
+
* }
|
|
88
|
+
* ```
|
|
89
|
+
*
|
|
90
|
+
*/
|
|
91
|
+
const useAuth = () => {
|
|
92
|
+
const key = process.env.NEXT_PUBLIC_MONOCLOUD_AUTH_USER_INFO_URL ?? `${process.env.__NEXT_ROUTER_BASEPATH ?? ""}/api/auth/userinfo`;
|
|
93
|
+
const { data, error, isLoading, mutate } = useSWR(key, fetchUser);
|
|
94
|
+
const refetch = (refresh) => {
|
|
95
|
+
const url = new URL(key, "https://dummy");
|
|
96
|
+
if (refresh) url.searchParams.set("refresh", "true");
|
|
97
|
+
mutate(async () => await fetchUser(url.pathname + url.search), { revalidate: false });
|
|
98
|
+
};
|
|
99
|
+
if (error) return {
|
|
100
|
+
user: void 0,
|
|
101
|
+
isLoading: false,
|
|
102
|
+
isAuthenticated: false,
|
|
103
|
+
error,
|
|
104
|
+
refetch
|
|
105
|
+
};
|
|
106
|
+
if (data) return {
|
|
107
|
+
user: data,
|
|
108
|
+
isLoading,
|
|
109
|
+
isAuthenticated: !!data && Object.keys(data).length > 0,
|
|
110
|
+
error: void 0,
|
|
111
|
+
refetch
|
|
112
|
+
};
|
|
113
|
+
return {
|
|
114
|
+
user: void 0,
|
|
115
|
+
isLoading,
|
|
116
|
+
isAuthenticated: false,
|
|
117
|
+
error: void 0,
|
|
118
|
+
refetch: () => {}
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
//#endregion
|
|
123
|
+
//#region src/client/protect.tsx
|
|
124
|
+
const redirectToSignIn = (options) => {
|
|
125
|
+
const searchParams = new URLSearchParams(window.location.search);
|
|
126
|
+
searchParams.set("return_url", options.returnUrl ?? window.location.toString());
|
|
127
|
+
if (options === null || options === void 0 ? void 0 : options.scopes) searchParams.set("scope", options.scopes);
|
|
128
|
+
if (options === null || options === void 0 ? void 0 : options.resource) searchParams.set("resource", options.resource);
|
|
129
|
+
if (options === null || options === void 0 ? void 0 : options.acrValues) searchParams.set("acr_values", options.acrValues.join(" "));
|
|
130
|
+
if (options === null || options === void 0 ? void 0 : options.display) searchParams.set("display", options.display);
|
|
131
|
+
if (options === null || options === void 0 ? void 0 : options.prompt) searchParams.set("prompt", options.prompt);
|
|
132
|
+
if (options === null || options === void 0 ? void 0 : options.authenticatorHint) searchParams.set("authenticator_hint", options.authenticatorHint);
|
|
133
|
+
if (options === null || options === void 0 ? void 0 : options.uiLocales) searchParams.set("ui_locales", options.uiLocales);
|
|
134
|
+
if (options === null || options === void 0 ? void 0 : options.maxAge) searchParams.set("max_age", options.maxAge.toString());
|
|
135
|
+
if (options === null || options === void 0 ? void 0 : options.loginHint) searchParams.set("login_hint", options.loginHint);
|
|
136
|
+
window.location.assign(`${process.env.NEXT_PUBLIC_MONOCLOUD_AUTH_SIGNIN_URL ?? `${process.env.__NEXT_ROUTER_BASEPATH ?? ""}/api/auth/signin`}?${searchParams.toString()}`);
|
|
137
|
+
};
|
|
138
|
+
const handlePageError = (error, options) => {
|
|
139
|
+
/* v8 ignore else -- @preserve */
|
|
140
|
+
if (options === null || options === void 0 ? void 0 : options.onError) return options.onError(error);
|
|
141
|
+
/* v8 ignore next -- @preserve */
|
|
142
|
+
throw error;
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* Function to protect a client rendered page component.
|
|
146
|
+
* Ensures that only authenticated users can access the component.
|
|
147
|
+
*
|
|
148
|
+
* **Note⚠️: Since `window.location` is set as `returnUrl` query param by default, you need to set the env `MONOCLOUD_AUTH_ALLOW_QUERY_PARAM_OVERRIDES=true` or `allowQueryParamOverrides` should be `true` in the client initialization for returning to the same page.**
|
|
149
|
+
*
|
|
150
|
+
* @param Component - The component to protect.
|
|
151
|
+
* @param options - The options.
|
|
152
|
+
*
|
|
153
|
+
* @returns Protected client rendered page component.
|
|
154
|
+
*
|
|
155
|
+
* @example App Router
|
|
156
|
+
*
|
|
157
|
+
* ```tsx
|
|
158
|
+
* "use client";
|
|
159
|
+
*
|
|
160
|
+
* import { protectPage } from "@monocloud/auth-nextjs/client";
|
|
161
|
+
*
|
|
162
|
+
* export default protectPage(function Home() {
|
|
163
|
+
* return <>You are signed in</>;
|
|
164
|
+
* });
|
|
165
|
+
* ```
|
|
166
|
+
*
|
|
167
|
+
* @example App Router with options
|
|
168
|
+
*
|
|
169
|
+
* See {@link ProtectPageOptions} for more options.
|
|
170
|
+
*
|
|
171
|
+
* ```tsx
|
|
172
|
+
* "use client";
|
|
173
|
+
*
|
|
174
|
+
* import { protectPage } from "@monocloud/auth-nextjs/client";
|
|
175
|
+
*
|
|
176
|
+
* export default protectPage(
|
|
177
|
+
* function Home() {
|
|
178
|
+
* return <>You are signed in</>;
|
|
179
|
+
* },
|
|
180
|
+
* { returnUrl: "/dashboard", authParams: { loginHint: "username" } }
|
|
181
|
+
* );
|
|
182
|
+
* ```
|
|
183
|
+
|
|
184
|
+
* @example Pages Router
|
|
185
|
+
*
|
|
186
|
+
* ```tsx
|
|
187
|
+
* import { protectPage } from "@monocloud/auth-nextjs/client";
|
|
188
|
+
*
|
|
189
|
+
* export default protectPage(function Home() {
|
|
190
|
+
* return <>You are signed in</>;
|
|
191
|
+
* });
|
|
192
|
+
* ```
|
|
193
|
+
*
|
|
194
|
+
* @example Pages Router with options
|
|
195
|
+
*
|
|
196
|
+
* See {@link ProtectPageOptions} for more options.
|
|
197
|
+
*
|
|
198
|
+
* ```tsx
|
|
199
|
+
* import { protectPage } from "@monocloud/auth-nextjs/client";
|
|
200
|
+
*
|
|
201
|
+
* export default protectPage(
|
|
202
|
+
* function Home() {
|
|
203
|
+
* return <>You are signed in</>;
|
|
204
|
+
* },
|
|
205
|
+
* { returnUrl: "/dashboard", authParams: { loginHint: "username" } }
|
|
206
|
+
* );
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
const protectPage = (Component, options) => {
|
|
210
|
+
return (props) => {
|
|
211
|
+
const { user, error, isLoading } = useAuth();
|
|
212
|
+
useEffect(() => {
|
|
213
|
+
if (!user && !isLoading && !error) {
|
|
214
|
+
if (options === null || options === void 0 ? void 0 : options.onAccessDenied) return;
|
|
215
|
+
const authParams = (options === null || options === void 0 ? void 0 : options.authParams) ?? {};
|
|
216
|
+
redirectToSignIn({
|
|
217
|
+
returnUrl: options === null || options === void 0 ? void 0 : options.returnUrl,
|
|
218
|
+
...authParams
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}, [
|
|
222
|
+
user,
|
|
223
|
+
isLoading,
|
|
224
|
+
error
|
|
225
|
+
]);
|
|
226
|
+
if (error) return handlePageError(error, options);
|
|
227
|
+
if (!user && !isLoading && (options === null || options === void 0 ? void 0 : options.onAccessDenied)) return options.onAccessDenied();
|
|
228
|
+
if (user) {
|
|
229
|
+
if ((options === null || options === void 0 ? void 0 : options.groups) && !isUserInGroup(user, options.groups, options.groupsClaim ?? process.env.NEXT_PUBLIC_MONOCLOUD_AUTH_GROUPS_CLAIM, options.matchAll)) {
|
|
230
|
+
const { onAccessDenied = () => /* @__PURE__ */ React.createElement("div", null, "Access Denied") } = options;
|
|
231
|
+
return onAccessDenied(user);
|
|
232
|
+
}
|
|
233
|
+
return /* @__PURE__ */ React.createElement(Component, {
|
|
234
|
+
user,
|
|
235
|
+
...props
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
return null;
|
|
239
|
+
};
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
//#endregion
|
|
243
|
+
export { redirectToSignIn as n, useAuth as r, protectPage as t };
|
|
244
|
+
//# sourceMappingURL=client-CnvBgZM-.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-CnvBgZM-.mjs","names":[],"sources":["../src/client/use-auth.tsx","../src/client/protect.tsx"],"sourcesContent":["'use client';\n\nimport type { MonoCloudUser } from '@monocloud/auth-node-core';\nimport useSWR from 'swr';\n\n/**\n * Authentication State returned by `useAuth` hook.\n */\nexport interface AuthState {\n /**\n * Flag indicating if the authentication state is still loading.\n */\n isLoading: boolean;\n /**\n * Flag indicating if the user is authenticated.\n */\n isAuthenticated: boolean;\n /**\n * Error encountered during authentication, if any.\n */\n error?: Error;\n /**\n * The authenticated user's information, if available.\n */\n user?: MonoCloudUser;\n /**\n * Function to refetch the authentication state.\n *\n */\n refetch: (refresh?: boolean) => void;\n}\n\nconst fetchUser = async (url: string): Promise<MonoCloudUser | undefined> => {\n const res = await fetch(url, { credentials: 'include' });\n\n if (res.status === 204) {\n return undefined;\n }\n\n if (res.ok) {\n return res.json();\n }\n\n throw new Error('Failed to fetch user');\n};\n\n/**\n *\n * Hook for getting the user's profile on client components\n *\n * @returns Authentication State\n *\n * @example App Router\n *\n * ```tsx\n * \"use client\";\n *\n * import { useAuth } from \"@monocloud/auth-nextjs/client\";\n *\n * export default function Home() {\n * const { user } = useAuth();\n *\n * return <>User Id: {user?.sub}</>;\n * }\n * ```\n *\n * @example App Router - Refetch user from Userinfo endpoint\n *\n * Calling `refetch(true)` will force refresh the user's profile from the userinfo endpoint.\n * If you do not intent to refersh from your tenants userinfo endpoint, use just `refetch()`\n *\n * **Note⚠️: You need to set the env `MONOCLOUD_AUTH_ALLOW_QUERY_PARAM_OVERRIDES=true` or `allowQueryParamOverrides` should be `true` in the client initialization for force refresh to work**\n *\n * ```tsx\n * \"use client\";\n *\n * import { useAuth } from \"@monocloud/auth-nextjs/client\";\n *\n * export default function Home() {\n * const { user, refetch } = useAuth();\n *\n * return (\n * <>\n * <pre>{JSON.stringify(user)}</pre>\n * <button onClick={() => refetch(true)}>Refresh</button>\n * </>\n * );\n * }\n * ```\n *\n * @example Pages Router\n *\n * ```tsx\n * import { useAuth } from \"@monocloud/auth-nextjs/client\";\n *\n * export default function Home() {\n * const { user } = useAuth();\n *\n * return <>User Id: {user?.sub}</>;\n * }\n * ```\n *\n * @example Pages Router - Refetch user from Userinfo endpoint\n *\n * Calling `refetch(true)` will force refresh the user's profile from the userinfo endpoint.\n * If you do not intent to refersh from your tenants userinfo endpoint, use just `refetch()`\n *\n * **Note⚠️: You need to set the env `MONOCLOUD_AUTH_ALLOW_QUERY_PARAM_OVERRIDES=true` or `allowQueryParamOverrides` should be `true` in the client initialization for force refresh to work**\n *\n * ```tsx\n * import { useAuth } from \"@monocloud/auth-nextjs/client\";\n *\n * export default function Home() {\n * const { user, refetch } = useAuth();\n *\n * return (\n * <>\n * <pre>{JSON.stringify(user)}</pre>\n * <button onClick={() => refetch(true)}>Refresh</button>\n * </>\n * );\n * }\n * ```\n *\n */\nexport const useAuth = (): AuthState => {\n const key =\n process.env.NEXT_PUBLIC_MONOCLOUD_AUTH_USER_INFO_URL ??\n // eslint-disable-next-line no-underscore-dangle\n `${process.env.__NEXT_ROUTER_BASEPATH ?? ''}/api/auth/userinfo`;\n\n const { data, error, isLoading, mutate } = useSWR<MonoCloudUser | undefined>(\n key,\n fetchUser\n );\n\n const refetch = (refresh?: boolean): void => {\n const url = new URL(key, 'https://dummy');\n if (refresh) {\n url.searchParams.set('refresh', 'true');\n }\n\n void mutate(async () => await fetchUser(url.pathname + url.search), {\n revalidate: false,\n });\n };\n\n if (error) {\n return {\n user: undefined,\n isLoading: false,\n isAuthenticated: false,\n error: error as Error,\n refetch,\n };\n }\n\n if (data) {\n return {\n user: data,\n isLoading,\n isAuthenticated: !!data && Object.keys(data).length > 0,\n error: undefined,\n refetch,\n };\n }\n\n return {\n user: undefined,\n isLoading,\n isAuthenticated: false,\n error: undefined,\n /* v8 ignore next -- @preserve */\n refetch: (): void => {},\n };\n};\n","/* eslint-disable react/display-name */\n'use client';\n\nimport React, { ComponentType, JSX, useEffect } from 'react';\nimport type { MonoCloudUser } from '@monocloud/auth-node-core';\nimport { isUserInGroup } from '@monocloud/auth-node-core/utils';\nimport { useAuth } from './use-auth';\nimport { ExtraAuthParams, GroupOptions } from '../types';\n\n/**\n * Options for configuring page protection.\n */\nexport type ProtectPageOptions = {\n /**\n *The url where the user will be redirected to after sign in\n */\n returnUrl?: string;\n\n /**\n * A custom react element to render when the user is not authenticated or is not a member of the specified groups.\n */\n onAccessDenied?: (user?: MonoCloudUser) => JSX.Element;\n\n /**\n * Authorization parameters to be used during authentication.\n */\n authParams?: ExtraAuthParams;\n\n /**\n * Callback function to handle errors.\n * If not provided, errors will be thrown.\n *\n * @param error - The error object.\n * @returns JSX element to handle the error.\n */\n onError?: (error: Error) => JSX.Element;\n} & GroupOptions;\n\nexport const redirectToSignIn = (\n options: { returnUrl?: string } & ExtraAuthParams\n): void => {\n const searchParams = new URLSearchParams(window.location.search);\n searchParams.set(\n 'return_url',\n options.returnUrl ?? window.location.toString()\n );\n\n if (options?.scopes) {\n searchParams.set('scope', options.scopes);\n }\n if (options?.resource) {\n searchParams.set('resource', options.resource);\n }\n\n if (options?.acrValues) {\n searchParams.set('acr_values', options.acrValues.join(' '));\n }\n\n if (options?.display) {\n searchParams.set('display', options.display);\n }\n\n if (options?.prompt) {\n searchParams.set('prompt', options.prompt);\n }\n\n if (options?.authenticatorHint) {\n searchParams.set('authenticator_hint', options.authenticatorHint);\n }\n\n if (options?.uiLocales) {\n searchParams.set('ui_locales', options.uiLocales);\n }\n\n if (options?.maxAge) {\n searchParams.set('max_age', options.maxAge.toString());\n }\n\n if (options?.loginHint) {\n searchParams.set('login_hint', options.loginHint);\n }\n\n window.location.assign(\n // eslint-disable-next-line no-underscore-dangle\n `${process.env.NEXT_PUBLIC_MONOCLOUD_AUTH_SIGNIN_URL ?? `${process.env.__NEXT_ROUTER_BASEPATH ?? ''}/api/auth/signin`}?${searchParams.toString()}`\n );\n};\n\nconst handlePageError = (\n error: Error,\n options?: ProtectPageOptions\n): JSX.Element => {\n /* v8 ignore else -- @preserve */\n if (options?.onError) {\n return options.onError(error);\n }\n\n /* v8 ignore next -- @preserve */\n throw error;\n};\n\n/**\n * Function to protect a client rendered page component.\n * Ensures that only authenticated users can access the component.\n * \n * **Note⚠️: Since `window.location` is set as `returnUrl` query param by default, you need to set the env `MONOCLOUD_AUTH_ALLOW_QUERY_PARAM_OVERRIDES=true` or `allowQueryParamOverrides` should be `true` in the client initialization for returning to the same page.**\n *\n * @param Component - The component to protect.\n * @param options - The options.\n *\n * @returns Protected client rendered page component.\n *\n * @example App Router\n *\n * ```tsx\n * \"use client\";\n *\n * import { protectPage } from \"@monocloud/auth-nextjs/client\";\n *\n * export default protectPage(function Home() {\n * return <>You are signed in</>;\n * });\n * ```\n *\n * @example App Router with options\n * \n * See {@link ProtectPageOptions} for more options.\n *\n * ```tsx\n * \"use client\";\n *\n * import { protectPage } from \"@monocloud/auth-nextjs/client\";\n *\n * export default protectPage(\n * function Home() {\n * return <>You are signed in</>;\n * },\n * { returnUrl: \"/dashboard\", authParams: { loginHint: \"username\" } }\n * );\n * ```\n\n* @example Pages Router\n *\n * ```tsx\n * import { protectPage } from \"@monocloud/auth-nextjs/client\";\n *\n * export default protectPage(function Home() {\n * return <>You are signed in</>;\n * });\n * ```\n *\n * @example Pages Router with options\n * \n * See {@link ProtectPageOptions} for more options.\n *\n * ```tsx\n * import { protectPage } from \"@monocloud/auth-nextjs/client\";\n *\n * export default protectPage(\n * function Home() {\n * return <>You are signed in</>;\n * },\n * { returnUrl: \"/dashboard\", authParams: { loginHint: \"username\" } }\n * );\n * ```\n */\nexport const protectPage = <P extends object>(\n Component: ComponentType<P & { user: MonoCloudUser }>,\n options?: ProtectPageOptions\n): React.FC<P> => {\n return props => {\n const { user, error, isLoading } = useAuth();\n\n useEffect(() => {\n if (!user && !isLoading && !error) {\n if (options?.onAccessDenied) {\n return;\n }\n\n const authParams = options?.authParams ?? {};\n redirectToSignIn({\n returnUrl: options?.returnUrl,\n ...authParams,\n });\n }\n }, [user, isLoading, error]);\n\n if (error) {\n return handlePageError(error, options);\n }\n\n if (!user && !isLoading && options?.onAccessDenied) {\n return options.onAccessDenied();\n }\n\n if (user) {\n if (\n options?.groups &&\n !isUserInGroup(\n user,\n options.groups,\n options.groupsClaim ??\n process.env.NEXT_PUBLIC_MONOCLOUD_AUTH_GROUPS_CLAIM,\n options.matchAll\n )\n ) {\n const { onAccessDenied = (): JSX.Element => <div>Access Denied</div> } =\n options;\n return onAccessDenied(user);\n }\n\n return <Component user={user} {...props} />;\n }\n\n return null;\n };\n};\n"],"mappings":"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"}
|