@monocloud/auth-nextjs 0.1.5 → 0.1.7
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/README.md +21 -4
- package/dist/{chunk-CbDLau6x.cjs → chunk-C0xms8kb.cjs} +1 -1
- package/dist/client/index.cjs +4 -3
- package/dist/client/index.d.mts +73 -118
- package/dist/client/index.mjs +2 -2
- package/dist/components/client/index.cjs +46 -88
- package/dist/components/client/index.cjs.map +1 -1
- package/dist/components/client/index.d.mts +59 -93
- package/dist/components/client/index.mjs +42 -85
- package/dist/components/client/index.mjs.map +1 -1
- package/dist/components/index.cjs +46 -42
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.d.mts +72 -49
- package/dist/components/index.mjs +44 -41
- package/dist/components/index.mjs.map +1 -1
- package/dist/index.cjs +399 -374
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +1546 -1835
- package/dist/index.mjs +393 -380
- package/dist/index.mjs.map +1 -1
- package/dist/{client-xfBYYato.cjs → protect-client-page-B1fOU4Zl.cjs} +65 -114
- package/dist/protect-client-page-B1fOU4Zl.cjs.map +1 -0
- package/dist/{client-D-3RMRNY.mjs → protect-client-page-BFlGkK8F.mjs} +63 -112
- package/dist/protect-client-page-BFlGkK8F.mjs.map +1 -0
- package/dist/types-xS_Me3Qg.d.mts +563 -0
- package/package.json +8 -7
- package/dist/client-D-3RMRNY.mjs.map +0 -1
- package/dist/client-xfBYYato.cjs.map +0 -1
- package/dist/types-CsBjAJce.d.mts +0 -410
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
import { Authenticators, AuthorizationParams, DisplayOptions, MonoCloudUser, Prompt } from "@monocloud/auth-node-core";
|
|
2
|
+
import { JSX } from "react";
|
|
3
|
+
import { NextFetchEvent, NextRequest, NextResponse } from "next/server";
|
|
4
|
+
import { GetServerSideProps, GetServerSidePropsContext, GetServerSidePropsResult, NextApiRequest, NextApiResponse } from "next/types";
|
|
5
|
+
import { ParsedUrlQuery } from "node:querystring";
|
|
6
|
+
|
|
7
|
+
//#region src/types.d.ts
|
|
8
|
+
/**
|
|
9
|
+
* Context object provided to App Router route handlers.
|
|
10
|
+
*
|
|
11
|
+
* Contains dynamic route parameters resolved from the matched route segment (for example, `[id]` or `[...slug]`).
|
|
12
|
+
*
|
|
13
|
+
* In streaming or async environments, `params` may be provided as a Promise.
|
|
14
|
+
*
|
|
15
|
+
* @category Types
|
|
16
|
+
*/
|
|
17
|
+
interface AppRouterContext {
|
|
18
|
+
/**
|
|
19
|
+
* Dynamic route parameters extracted from the request URL.
|
|
20
|
+
*/
|
|
21
|
+
params: Record<string, string | string[]> | Promise<Record<string, string | string[]>>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Handler function returned by `monoCloudAuth()`.
|
|
25
|
+
*
|
|
26
|
+
* This handler processes authentication routes such as sign-in, callback, sign-out, and userinfo across supported Next.js runtimes (App Router, Pages Router, and API routes).
|
|
27
|
+
*
|
|
28
|
+
* @category Types (Handler)
|
|
29
|
+
*/
|
|
30
|
+
type MonoCloudAuthHandler = (
|
|
31
|
+
/**
|
|
32
|
+
* Incoming request object.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
req: Request | NextRequest | NextApiRequest,
|
|
36
|
+
/**
|
|
37
|
+
* Response object or App Router context.
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
resOrCtx?: Response | NextResponse<any> | NextApiResponse<any> | AppRouterContext) => Promise<Response | NextResponse | void | any>;
|
|
41
|
+
/**
|
|
42
|
+
* Possible return values from a Next.js middleware or proxy handler.
|
|
43
|
+
*
|
|
44
|
+
* @category Types
|
|
45
|
+
*/
|
|
46
|
+
type NextMiddlewareResult = NextResponse | Response | null | undefined | void;
|
|
47
|
+
/**
|
|
48
|
+
* Handler invoked when access is denied during Next.js middleware execution.
|
|
49
|
+
*
|
|
50
|
+
* This callback allows you to customize how unauthenticated or unauthorized requests are handled, for example by redirecting, rewriting, or returning a custom response.
|
|
51
|
+
*
|
|
52
|
+
* @category Types (Handler)
|
|
53
|
+
*
|
|
54
|
+
* @param request The incoming Next.js request.
|
|
55
|
+
* @param event The associated Next.js fetch event.
|
|
56
|
+
* @returns A middleware result that determines how the request should proceed.
|
|
57
|
+
*/
|
|
58
|
+
type NextMiddlewareOnAccessDenied = (request: NextRequest, event: NextFetchEvent) => NextMiddlewareResult | Promise<NextMiddlewareResult>;
|
|
59
|
+
/**
|
|
60
|
+
* Handler invoked when an authenticated user is denied access during Next.js middleware execution due to group authorization rules.
|
|
61
|
+
*
|
|
62
|
+
* This callback allows you to customize how authorization failures are handled, for example by redirecting, rewriting, or returning a custom response.
|
|
63
|
+
*
|
|
64
|
+
* @category Types (Handler)
|
|
65
|
+
*
|
|
66
|
+
* @param request The incoming Next.js request.
|
|
67
|
+
* @param event The associated Next.js fetch event.
|
|
68
|
+
* @param user The authenticated user who failed the group authorization check.
|
|
69
|
+
* @returns A middleware result that determines how the request should proceed.
|
|
70
|
+
*/
|
|
71
|
+
type NextMiddlewareOnGroupAccessDenied = (request: NextRequest, event: NextFetchEvent, user: MonoCloudUser) => NextMiddlewareResult | Promise<NextMiddlewareResult>;
|
|
72
|
+
/**
|
|
73
|
+
*
|
|
74
|
+
* Defines how routes are matched and protected by authentication and optional group-based authorization.
|
|
75
|
+
*
|
|
76
|
+
* @category Types
|
|
77
|
+
*
|
|
78
|
+
*/
|
|
79
|
+
type ProtectedRouteMatcher = string | RegExp | {
|
|
80
|
+
/**
|
|
81
|
+
* Route patterns that should be protected.
|
|
82
|
+
*
|
|
83
|
+
* Each entry may be:
|
|
84
|
+
* - A relative route path
|
|
85
|
+
* - A regular expression used to match routes
|
|
86
|
+
*/
|
|
87
|
+
routes: (string | RegExp)[];
|
|
88
|
+
/**
|
|
89
|
+
* Optional group-based access control.
|
|
90
|
+
*
|
|
91
|
+
* When provided, only users belonging to **at least one** of the specified group IDs or names are allowed access.
|
|
92
|
+
*/
|
|
93
|
+
groups: string[];
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Function used to dynamically determine whether a request should be treated as a protected route.
|
|
97
|
+
*
|
|
98
|
+
* @category Types (Handler)
|
|
99
|
+
*
|
|
100
|
+
* @param req The incoming Next.js request.
|
|
101
|
+
* @returns Return `true` to require authentication for the request, or `false` to allow it to continue without protection.
|
|
102
|
+
*/
|
|
103
|
+
type CustomProtectedRouteMatcher = (req: NextRequest) => Promise<boolean> | boolean;
|
|
104
|
+
/**
|
|
105
|
+
* Handler invoked when an error occurs during execution of an App Router endpoint.
|
|
106
|
+
*
|
|
107
|
+
* Allows custom error handling such as logging, transforming the response, or returning a custom `NextResponse`
|
|
108
|
+
*
|
|
109
|
+
* @category Types (Handler)
|
|
110
|
+
*
|
|
111
|
+
* @param req The incoming Next.js request.
|
|
112
|
+
* @param ctx The App Router context containing dynamic route parameters.
|
|
113
|
+
* @param error The error thrown during endpoint execution.
|
|
114
|
+
* @returns Returns a `NextResponse` or `void`.
|
|
115
|
+
*/
|
|
116
|
+
type AppOnError<T = any> = (req: NextRequest, ctx: T, error: Error) => Promise<NextResponse | void> | NextResponse | void;
|
|
117
|
+
/**
|
|
118
|
+
* Handler invoked when an error occurs during execution of a Pages Router API endpoint.
|
|
119
|
+
*
|
|
120
|
+
* Allows custom error handling such as logging, modifying the response, or sending a custom error payload.
|
|
121
|
+
*
|
|
122
|
+
* @category Types (Handler)
|
|
123
|
+
*
|
|
124
|
+
* @param req The incoming Next.js API request.
|
|
125
|
+
* @param res The outgoing Next.js API response.
|
|
126
|
+
* @param error The error thrown during endpoint execution.
|
|
127
|
+
* @returns Returns `void` or a Promise that resolves when error handling is complete.
|
|
128
|
+
*/
|
|
129
|
+
type PageOnError = (req: NextApiRequest, res: NextApiResponse, error: Error) => Promise<void> | void;
|
|
130
|
+
/**
|
|
131
|
+
* Error handler invoked when an exception occurs during execution of the sign-in, callback, sign-out, or userinfo endpoints.
|
|
132
|
+
*
|
|
133
|
+
* > - In the **App Router**, you must either return a `NextResponse` or throw an error. Otherwise, the request will remain unresolved.
|
|
134
|
+
* > - In the **Pages Router**, you must send a response (for example, `res.send()` or `res.json()`) after handling the error, or the request will hang.
|
|
135
|
+
*
|
|
136
|
+
* @category Types (Handler)
|
|
137
|
+
*/
|
|
138
|
+
type OnError = AppOnError | PageOnError;
|
|
139
|
+
/**
|
|
140
|
+
* Options for `monoCloudAuth()`.
|
|
141
|
+
*
|
|
142
|
+
* @category Types
|
|
143
|
+
*/
|
|
144
|
+
interface MonoCloudAuthOptions {
|
|
145
|
+
/**
|
|
146
|
+
* Optional error handler invoked when an exception occurs during execution of the sign-in, callback, sign-out, or userinfo endpoints.
|
|
147
|
+
*/
|
|
148
|
+
onError?: OnError;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Configuration used to determine which routes require authentication.
|
|
152
|
+
*
|
|
153
|
+
* You can provide:
|
|
154
|
+
*
|
|
155
|
+
* - An array of {@link ProtectedRouteMatcher} values to declaratively define protected routes.
|
|
156
|
+
* - A {@link CustomProtectedRouteMatcher} function for fully dynamic protection logic.
|
|
157
|
+
*
|
|
158
|
+
* @category Types
|
|
159
|
+
*/
|
|
160
|
+
type ProtectedRoutes = ProtectedRouteMatcher[] | CustomProtectedRouteMatcher;
|
|
161
|
+
/**
|
|
162
|
+
* Options for configuring the MonoCloud authentication middleware.
|
|
163
|
+
*
|
|
164
|
+
* These options control which routes are protected and how authentication and authorization failures are handled during request processing.
|
|
165
|
+
*
|
|
166
|
+
* @category Types
|
|
167
|
+
*/
|
|
168
|
+
interface MonoCloudMiddlewareOptions {
|
|
169
|
+
/**
|
|
170
|
+
* Error handler invoked when an error occurs during execution of authentication endpoints handled by the middleware.
|
|
171
|
+
*
|
|
172
|
+
* @param req The incoming Next.js request.
|
|
173
|
+
* @param evt The associated Next.js fetch event.
|
|
174
|
+
* @param error The error thrown during execution.
|
|
175
|
+
* @returns Returns a response to continue the middleware chain, or `void`.
|
|
176
|
+
*/
|
|
177
|
+
onError?: (req: NextRequest, evt: NextFetchEvent, error: Error) => Promise<NextResponse | void> | NextResponse | void;
|
|
178
|
+
/**
|
|
179
|
+
* Defines which routes require authentication.
|
|
180
|
+
*
|
|
181
|
+
* Accepts either an array of {@link ProtectedRouteMatcher} or a {@link CustomProtectedRouteMatcher}.
|
|
182
|
+
*
|
|
183
|
+
* - If omitted, all routes matched by the middleware config are protected.
|
|
184
|
+
* - If an empty array is provided, no routes are protected.
|
|
185
|
+
*/
|
|
186
|
+
protectedRoutes?: ProtectedRoutes;
|
|
187
|
+
/**
|
|
188
|
+
* Name of the claim in the user profile that contains group memberships.
|
|
189
|
+
*
|
|
190
|
+
* @defaultValue 'groups'
|
|
191
|
+
*/
|
|
192
|
+
groupsClaim?: string;
|
|
193
|
+
/**
|
|
194
|
+
* When `true`, the user must belong to **all** specified groups for authorization to succeed. Otherwise, membership in any one group is sufficient.
|
|
195
|
+
*
|
|
196
|
+
* @defaultValue false
|
|
197
|
+
*/
|
|
198
|
+
matchAll?: boolean;
|
|
199
|
+
/**
|
|
200
|
+
* Middleware handler invoked when the user is not authenticated.
|
|
201
|
+
*/
|
|
202
|
+
onAccessDenied?: NextMiddlewareOnAccessDenied;
|
|
203
|
+
/**
|
|
204
|
+
* Middleware handler invoked when the user is authenticated but does not satisfy group authorization requirements.
|
|
205
|
+
*/
|
|
206
|
+
onGroupAccessDenied?: NextMiddlewareOnGroupAccessDenied;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* A subset of authorization parameters supported by client-side helpers.
|
|
210
|
+
*
|
|
211
|
+
* @category Types
|
|
212
|
+
*/
|
|
213
|
+
interface ExtraAuthParams extends Pick<AuthorizationParams, 'scopes' | 'resource' | 'prompt' | 'display' | 'uiLocales' | 'acrValues' | 'authenticatorHint' | 'maxAge' | 'loginHint'> {}
|
|
214
|
+
/**
|
|
215
|
+
* Represents a Next.js App Router page component (Server Component).
|
|
216
|
+
*
|
|
217
|
+
* @category Types (Handler)
|
|
218
|
+
*
|
|
219
|
+
* @param props Page props provided by Next.js, including dynamic route parameters and URL search parameters.
|
|
220
|
+
* @returns A JSX element, or a Promise resolving to one.
|
|
221
|
+
*/
|
|
222
|
+
type AppRouterPageHandler = (props: {
|
|
223
|
+
/**
|
|
224
|
+
* Dynamic route parameters extracted from the URL.
|
|
225
|
+
*/
|
|
226
|
+
params?: Record<string, string | string[]>;
|
|
227
|
+
/**
|
|
228
|
+
* URL search parameters (`?key=value`) parsed by Next.js.
|
|
229
|
+
*/
|
|
230
|
+
searchParams?: Record<string, string | string[] | undefined>;
|
|
231
|
+
}) => Promise<JSX.Element> | JSX.Element;
|
|
232
|
+
/**
|
|
233
|
+
* Represents a Next.js App Router Route Handler function.
|
|
234
|
+
*
|
|
235
|
+
* @category Types (Handler)
|
|
236
|
+
*
|
|
237
|
+
* @param req The incoming request object.
|
|
238
|
+
* @param ctx Route context containing dynamic route parameters.
|
|
239
|
+
* @returns A `Response` or `NextResponse`, or a Promise resolving to one.
|
|
240
|
+
*/
|
|
241
|
+
type AppRouterApiHandlerFn = (req: NextRequest | Request, ctx: AppRouterContext) => Promise<Response | NextResponse> | Response | NextResponse;
|
|
242
|
+
/**
|
|
243
|
+
* Options for configuring `protectPage()` in the App Router.
|
|
244
|
+
*
|
|
245
|
+
* @category Types
|
|
246
|
+
*/
|
|
247
|
+
interface ProtectAppPageOptions extends GroupOptions {
|
|
248
|
+
/**
|
|
249
|
+
* The URL the user should be returned to after successful authentication.
|
|
250
|
+
*
|
|
251
|
+
* Defaults to the current request URL.
|
|
252
|
+
*/
|
|
253
|
+
returnUrl?: string;
|
|
254
|
+
/**
|
|
255
|
+
* Alternate Server Component rendered when the user is **not authenticated**.
|
|
256
|
+
*
|
|
257
|
+
* If not provided, the default behavior redirects the user to the sign-in flow.
|
|
258
|
+
*/
|
|
259
|
+
onAccessDenied?: (props: {
|
|
260
|
+
params?: Record<string, string | string[]>;
|
|
261
|
+
searchParams?: Record<string, string | string[] | undefined>;
|
|
262
|
+
}) => Promise<JSX.Element> | JSX.Element;
|
|
263
|
+
/**
|
|
264
|
+
* Alternate Server Component rendered when the user is authenticated but does **not** belong to the required groups.
|
|
265
|
+
*
|
|
266
|
+
* Receives the resolved authenticated user.
|
|
267
|
+
*/
|
|
268
|
+
onGroupAccessDenied?: (props: {
|
|
269
|
+
user: MonoCloudUser;
|
|
270
|
+
params?: Record<string, string | string[]>;
|
|
271
|
+
searchParams?: Record<string, string | string[] | undefined>;
|
|
272
|
+
}) => Promise<JSX.Element> | JSX.Element;
|
|
273
|
+
/**
|
|
274
|
+
* Additional authorization parameters applied when redirecting the user to authenticate.
|
|
275
|
+
*/
|
|
276
|
+
authParams?: ExtraAuthParams;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Options for configuring `protectPage()` in the Pages Router.
|
|
280
|
+
*
|
|
281
|
+
* @category Types
|
|
282
|
+
*
|
|
283
|
+
* @typeParam P Props returned from `getServerSideProps`.
|
|
284
|
+
* @typeParam Q Query parameters parsed from the URL.
|
|
285
|
+
*/
|
|
286
|
+
interface ProtectPagePageOptions<P extends Record<string, any> = Record<string, any>, Q extends ParsedUrlQuery = ParsedUrlQuery> extends GroupOptions {
|
|
287
|
+
/**
|
|
288
|
+
* An optional `getServerSideProps` implementation that runs after authentication (and group checks, if configured). Use this to compute additional props for the page.
|
|
289
|
+
*/
|
|
290
|
+
getServerSideProps?: GetServerSideProps<P, Q>;
|
|
291
|
+
/**
|
|
292
|
+
* The URL the user should be returned to after successful authentication.
|
|
293
|
+
*
|
|
294
|
+
* Defaults to the current request URL.
|
|
295
|
+
*/
|
|
296
|
+
returnUrl?: string;
|
|
297
|
+
/**
|
|
298
|
+
* Called when no valid session exists.
|
|
299
|
+
*
|
|
300
|
+
* If not provided, the default behavior redirects the user to the sign-in flow.
|
|
301
|
+
*/
|
|
302
|
+
onAccessDenied?: ProtectPagePageOnAccessDeniedType<P, Q>;
|
|
303
|
+
/**
|
|
304
|
+
* Called when the user is authenticated but does not satisfy the group requirements.
|
|
305
|
+
*
|
|
306
|
+
* If not provided, the default behavior continues rendering and sets `groupAccessDenied` in the returned props, or applies the SDK’s default access-denied behavior.
|
|
307
|
+
*/
|
|
308
|
+
onGroupAccessDenied?: ProtectPagePageOnGroupAccessDeniedType<P, Q>;
|
|
309
|
+
/**
|
|
310
|
+
* Additional authorization parameters applied when redirecting the user to authenticate.
|
|
311
|
+
*/
|
|
312
|
+
authParams?: ExtraAuthParams;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Handler invoked when no valid session exists while running a Pages Router `getServerSideProps` protected by `protectPage()`.
|
|
316
|
+
*
|
|
317
|
+
* @category Types (Handler)
|
|
318
|
+
*
|
|
319
|
+
* @typeParam P Props returned from `getServerSideProps`.
|
|
320
|
+
* @typeParam Q Query parameters parsed from the URL.
|
|
321
|
+
* @param context The Next.js `getServerSideProps` context.
|
|
322
|
+
* @returns A `getServerSideProps` result.
|
|
323
|
+
*/
|
|
324
|
+
type ProtectPagePageOnAccessDeniedType<P, Q extends ParsedUrlQuery = ParsedUrlQuery> = (context: GetServerSidePropsContext<Q>) => Promise<GetServerSidePropsResult<P>> | GetServerSidePropsResult<P>;
|
|
325
|
+
/**
|
|
326
|
+
* Handler invoked when an authenticated user does not satisfy the required group restrictions while running a Pages Router `getServerSideProps` protected by `protectPage()`.
|
|
327
|
+
*
|
|
328
|
+
* @category Types (Handler)
|
|
329
|
+
*
|
|
330
|
+
* @typeParam P Props returned from `getServerSideProps`.
|
|
331
|
+
* @typeParam Q Query parameters parsed from the URL.
|
|
332
|
+
* @param context The Next.js `getServerSideProps` context.
|
|
333
|
+
* @returns A `getServerSideProps` result.
|
|
334
|
+
*/
|
|
335
|
+
type ProtectPagePageOnGroupAccessDeniedType<P, Q extends ParsedUrlQuery = ParsedUrlQuery> = (context: GetServerSidePropsContext<Q> & {
|
|
336
|
+
user: MonoCloudUser;
|
|
337
|
+
}) => Promise<GetServerSidePropsResult<P>> | GetServerSidePropsResult<P>;
|
|
338
|
+
/**
|
|
339
|
+
* Return type produced by the `protectPage()` wrapper for the Pages Router.
|
|
340
|
+
*
|
|
341
|
+
* Represents a `getServerSideProps` compatible function that resolves authentication before executing page logic and injects the authenticated `user` into the returned props.
|
|
342
|
+
*
|
|
343
|
+
* @category Types (Handler)
|
|
344
|
+
*
|
|
345
|
+
* @typeParam P Props returned from `getServerSideProps`.
|
|
346
|
+
* @typeParam Q Query parameters parsed from the URL.
|
|
347
|
+
*/
|
|
348
|
+
type ProtectPagePageReturnType<P, Q extends ParsedUrlQuery = ParsedUrlQuery> = (context: GetServerSidePropsContext<Q>) => Promise<GetServerSidePropsResult<P & {
|
|
349
|
+
user: MonoCloudUser;
|
|
350
|
+
accessDenied?: boolean;
|
|
351
|
+
}>>;
|
|
352
|
+
/**
|
|
353
|
+
* App Router Server Component wrapped by `protectPage()`.
|
|
354
|
+
*
|
|
355
|
+
* This component is only executed after authentication (and optional authorization) succeeds. The authenticated `user` is injected into the component props automatically.
|
|
356
|
+
*
|
|
357
|
+
* @category Types (Handler)
|
|
358
|
+
*/
|
|
359
|
+
type ProtectedAppServerComponent = (props: {
|
|
360
|
+
/**
|
|
361
|
+
* The authenticated user resolved from the current session.
|
|
362
|
+
*/
|
|
363
|
+
user: MonoCloudUser;
|
|
364
|
+
/**
|
|
365
|
+
* Dynamic route parameters provided by the App Router.
|
|
366
|
+
*/
|
|
367
|
+
params?: Record<string, string | string[]>;
|
|
368
|
+
/**
|
|
369
|
+
* URL search parameters provided by the App Router.
|
|
370
|
+
*/
|
|
371
|
+
searchParams?: Record<string, string | string[] | undefined>;
|
|
372
|
+
}) => Promise<JSX.Element> | JSX.Element;
|
|
373
|
+
/**
|
|
374
|
+
* Handler invoked when a request is denied because the user is not authenticated in an App Router API route.
|
|
375
|
+
*
|
|
376
|
+
* @category Types (Handler)
|
|
377
|
+
*
|
|
378
|
+
* @param req The incoming Next.js request.
|
|
379
|
+
* @param ctx The App Router context containing dynamic route parameters.
|
|
380
|
+
*
|
|
381
|
+
* @returns Returns a `Response` (or `NextResponse`) or a Promise resolving to one.
|
|
382
|
+
*/
|
|
383
|
+
type AppRouterApiOnAccessDeniedHandler = (req: NextRequest, ctx: AppRouterContext) => Promise<Response> | Response;
|
|
384
|
+
/**
|
|
385
|
+
* Handler invoked when a request is denied because the authenticated user does not satisfy the required group restrictions in an App Router API route.
|
|
386
|
+
*
|
|
387
|
+
* @category Types (Handler)
|
|
388
|
+
*
|
|
389
|
+
* @param req The incoming Next.js request.
|
|
390
|
+
* @param ctx The App Router context containing dynamic route parameters.
|
|
391
|
+
* @param user The authenticated user associated with the request.
|
|
392
|
+
*
|
|
393
|
+
* @returns Returns a `Response` (or `NextResponse`) or a Promise resolving to one.
|
|
394
|
+
*/
|
|
395
|
+
type AppRouterApiOnGroupAccessDeniedHandler = (req: NextRequest, ctx: AppRouterContext, user: MonoCloudUser) => Promise<Response> | Response;
|
|
396
|
+
/**
|
|
397
|
+
* Options for configuring `protectApi()` in the App Router.
|
|
398
|
+
*
|
|
399
|
+
* @category Types
|
|
400
|
+
*/
|
|
401
|
+
interface ProtectApiAppOptions extends GroupOptions {
|
|
402
|
+
/**
|
|
403
|
+
* Alternate API route handler invoked when the request is not authenticated.
|
|
404
|
+
*/
|
|
405
|
+
onAccessDenied?: AppRouterApiOnAccessDeniedHandler;
|
|
406
|
+
/**
|
|
407
|
+
* Alternate API route handler invoked when the request is authenticated but the user does not satisfy the required group restrictions.
|
|
408
|
+
*/
|
|
409
|
+
onGroupAccessDenied?: AppRouterApiOnGroupAccessDeniedHandler;
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Handler function invoked when a request is not authenticated in a Pages Router API route.
|
|
413
|
+
*
|
|
414
|
+
* @category Types (Handler)
|
|
415
|
+
*
|
|
416
|
+
* @param req The incoming Next.js API request.
|
|
417
|
+
* @param res The Next.js API response object used to send the custom response.
|
|
418
|
+
* @returns The handler should send a response using `res` (for example, `res.status(...).json(...)`). Returning a value does not automatically end the request.
|
|
419
|
+
*/
|
|
420
|
+
type PageRouterApiOnAccessDeniedHandler = (req: NextApiRequest, res: NextApiResponse<any>) => Promise<unknown> | unknown;
|
|
421
|
+
/**
|
|
422
|
+
* Handler function invoked when an authenticated user is denied access in a Pages Router API route due to group authorization restrictions.
|
|
423
|
+
*
|
|
424
|
+
* @category Types (Handler)
|
|
425
|
+
*
|
|
426
|
+
* @param req The incoming Next.js API request.
|
|
427
|
+
* @param res The Next.js API response object used to send the custom response.
|
|
428
|
+
* @returns The handler should send a response using `res` (for example, `res.status(...).json(...)`). Returning a value does not automatically end the request.
|
|
429
|
+
*
|
|
430
|
+
* @returns
|
|
431
|
+
*/
|
|
432
|
+
type PageRouterApiOnGroupAccessDeniedHandler = (req: NextApiRequest, res: NextApiResponse<any>, user: MonoCloudUser) => Promise<unknown> | unknown;
|
|
433
|
+
/**
|
|
434
|
+
* Options for configuring `protectApi()` in the Pages Router.
|
|
435
|
+
*
|
|
436
|
+
* @category Types
|
|
437
|
+
*/
|
|
438
|
+
interface ProtectApiPageOptions extends GroupOptions {
|
|
439
|
+
/**
|
|
440
|
+
* Alternate API handler invoked when the request is unauthenticated.
|
|
441
|
+
*/
|
|
442
|
+
onAccessDenied?: PageRouterApiOnAccessDeniedHandler;
|
|
443
|
+
/**
|
|
444
|
+
* Alternate API handler invoked when the user is authenticated but does not satisfy the configured group authorization rules.
|
|
445
|
+
*/
|
|
446
|
+
onGroupAccessDenied?: PageRouterApiOnGroupAccessDeniedHandler;
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Options for configuring the `protect()` helper.
|
|
450
|
+
*
|
|
451
|
+
* @category Types
|
|
452
|
+
*/
|
|
453
|
+
interface ProtectOptions extends GroupOptions {
|
|
454
|
+
/**
|
|
455
|
+
* The URL to return to after successful authentication.
|
|
456
|
+
*
|
|
457
|
+
* If not provided, the current request URL is used.
|
|
458
|
+
*/
|
|
459
|
+
returnUrl?: string;
|
|
460
|
+
/**
|
|
461
|
+
* Additional authorization parameters to include when redirecting the user to the sign-in flow.
|
|
462
|
+
*/
|
|
463
|
+
authParams?: ExtraAuthParams;
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Configuration options for evaluating user group membership.
|
|
467
|
+
*
|
|
468
|
+
* @category Types
|
|
469
|
+
*/
|
|
470
|
+
interface IsUserInGroupOptions {
|
|
471
|
+
/**
|
|
472
|
+
* The name of the claim in the user profile that contains group information. This value is read from the authenticated user's session.
|
|
473
|
+
*
|
|
474
|
+
* @defaultValue 'groups'
|
|
475
|
+
*/
|
|
476
|
+
groupsClaim?: string;
|
|
477
|
+
/**
|
|
478
|
+
* Determines how multiple groups are evaluated. When `true`, the user must belong to **all** specified groups for authorization to succeed. Otherwise, membership in any one group is sufficient.
|
|
479
|
+
*
|
|
480
|
+
* @defaultValue false
|
|
481
|
+
*/
|
|
482
|
+
matchAll?: boolean;
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Configuration options that require the user to belong to specific groups.
|
|
486
|
+
*
|
|
487
|
+
* @category Types
|
|
488
|
+
*/
|
|
489
|
+
interface GroupOptions extends IsUserInGroupOptions {
|
|
490
|
+
/**
|
|
491
|
+
* A list of group IDs or group names the authenticated user must belong to.
|
|
492
|
+
*
|
|
493
|
+
* Group membership is evaluated using the configured `groupsClaim` from the user session.
|
|
494
|
+
*/
|
|
495
|
+
groups?: string[];
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Options for `redirectToSignIn()`
|
|
499
|
+
*
|
|
500
|
+
* @category Types
|
|
501
|
+
*/
|
|
502
|
+
interface RedirectToSignInOptions {
|
|
503
|
+
/**
|
|
504
|
+
* URL to return the user to after successful authentication. Must be a relative application URL.
|
|
505
|
+
*/
|
|
506
|
+
returnUrl?: string;
|
|
507
|
+
/**
|
|
508
|
+
* Maximum allowed time (in seconds) since the user's last authentication.
|
|
509
|
+
*/
|
|
510
|
+
maxAge?: number;
|
|
511
|
+
/**
|
|
512
|
+
* Hint to the authorization server indicating which authenticator should be used during sign-in.
|
|
513
|
+
*/
|
|
514
|
+
authenticatorHint?: Authenticators;
|
|
515
|
+
/**
|
|
516
|
+
* Scopes to request during authentication.
|
|
517
|
+
*/
|
|
518
|
+
scopes?: string[];
|
|
519
|
+
/**
|
|
520
|
+
* Resource indicators the access token should be issued for.
|
|
521
|
+
*/
|
|
522
|
+
resource?: string[];
|
|
523
|
+
/**
|
|
524
|
+
* Preferred UI language(s) for the authentication experience.
|
|
525
|
+
*/
|
|
526
|
+
uiLocales?: string;
|
|
527
|
+
/**
|
|
528
|
+
* Preferred display mode for the authentication UI.
|
|
529
|
+
*/
|
|
530
|
+
display?: DisplayOptions;
|
|
531
|
+
/**
|
|
532
|
+
* Authentication Context Class Reference (ACR) values requesting specific authentication methods or assurance levels.
|
|
533
|
+
*/
|
|
534
|
+
acrValues?: string[];
|
|
535
|
+
/**
|
|
536
|
+
* Hint about the user's identifier (for example, email or username).
|
|
537
|
+
*/
|
|
538
|
+
loginHint?: string;
|
|
539
|
+
/**
|
|
540
|
+
* Controls whether the authorization server should force specific user interactions during authentication
|
|
541
|
+
*/
|
|
542
|
+
prompt?: Prompt;
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* Options for `redirectToSignOut()`
|
|
546
|
+
*
|
|
547
|
+
* @category Types
|
|
548
|
+
*/
|
|
549
|
+
interface RedirectToSignOutOptions {
|
|
550
|
+
/**
|
|
551
|
+
* URL where the authorization server should redirect the user after a successful sign-out.
|
|
552
|
+
*
|
|
553
|
+
* This value must match one of the registered Sign-out Redirect URLs configured for the application.
|
|
554
|
+
*/
|
|
555
|
+
postLogoutRedirectUri?: string;
|
|
556
|
+
/**
|
|
557
|
+
* When enabled, the user is also signed out from MonoCloud (Single Sign-Out).
|
|
558
|
+
*/
|
|
559
|
+
federated?: boolean;
|
|
560
|
+
}
|
|
561
|
+
//#endregion
|
|
562
|
+
export { ProtectedRouteMatcher as A, ProtectAppPageOptions as C, ProtectPagePageOptions as D, ProtectPagePageOnGroupAccessDeniedType as E, RedirectToSignInOptions as M, RedirectToSignOutOptions as N, ProtectPagePageReturnType as O, ProtectApiPageOptions as S, ProtectPagePageOnAccessDeniedType as T, OnError as _, AppRouterContext as a, PageRouterApiOnGroupAccessDeniedHandler as b, ExtraAuthParams as c, MonoCloudAuthHandler as d, MonoCloudAuthOptions as f, NextMiddlewareResult as g, NextMiddlewareOnGroupAccessDenied as h, AppRouterApiOnGroupAccessDeniedHandler as i, ProtectedRoutes as j, ProtectedAppServerComponent as k, GroupOptions as l, NextMiddlewareOnAccessDenied as m, AppRouterApiHandlerFn as n, AppRouterPageHandler as o, MonoCloudMiddlewareOptions as p, AppRouterApiOnAccessDeniedHandler as r, CustomProtectedRouteMatcher as s, AppOnError as t, IsUserInGroupOptions as u, PageOnError as v, ProtectOptions as w, ProtectApiAppOptions as x, PageRouterApiOnAccessDeniedHandler as y };
|
|
563
|
+
//# sourceMappingURL=types-xS_Me3Qg.d.mts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@monocloud/auth-nextjs",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "MonoCloud Next.js Authentication SDK",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"monocloud",
|
|
@@ -56,18 +56,19 @@
|
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
58
|
"cookie": "1.1.1",
|
|
59
|
-
"swr": "2.
|
|
60
|
-
"@monocloud/auth-node-core": "0.1.
|
|
59
|
+
"swr": "2.4.0",
|
|
60
|
+
"@monocloud/auth-node-core": "0.1.6",
|
|
61
|
+
"@monocloud/auth-core": "0.1.5"
|
|
61
62
|
},
|
|
62
63
|
"devDependencies": {
|
|
63
64
|
"@edge-runtime/vm": "5.0.0",
|
|
64
65
|
"@testing-library/dom": "10.4.1",
|
|
65
|
-
"@testing-library/react": "16.3.
|
|
66
|
+
"@testing-library/react": "16.3.2",
|
|
66
67
|
"@types/body-parser": "1.19.6",
|
|
67
|
-
"@types/react": "19.2.
|
|
68
|
+
"@types/react": "19.2.13",
|
|
68
69
|
"@types/react-dom": "19.2.3",
|
|
69
|
-
"body-parser": "2.2.
|
|
70
|
-
"eslint": "
|
|
70
|
+
"body-parser": "2.2.2",
|
|
71
|
+
"eslint": "10.0.0",
|
|
71
72
|
"nock": "15.0.0",
|
|
72
73
|
"tough-cookie": "6.0.0",
|
|
73
74
|
"url-search-params-polyfill": "8.2.5",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client-D-3RMRNY.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.\n */\n fallback?: (user?: MonoCloudUser) => JSX.Element;\n\n /**\n * A custom react element to render when the user is authenticated but does not belong to the required groups.\n */\n groupFallback?: (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 * @example Custom Fallback\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 * {\n * fallback: () => <div>Please sign in to continue</div>\n * }\n * );\n * ```\n *\n * @example Group Protection with Group Fallback\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 <>Welcome Admin</>;\n * },\n * {\n * groups: [\"admin\"],\n * groupFallback: (user) => <div>User {user.email} is not an admin</div>\n * }\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?.fallback) {\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?.fallback) {\n return options.fallback();\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 { groupFallback = (): JSX.Element => <div>Access Denied</div> } =\n options;\n return groupFallback(user);\n }\n\n return <Component user={user} {...props} />;\n }\n\n return null;\n };\n};\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client-xfBYYato.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.\n */\n fallback?: (user?: MonoCloudUser) => JSX.Element;\n\n /**\n * A custom react element to render when the user is authenticated but does not belong to the required groups.\n */\n groupFallback?: (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 * @example Custom Fallback\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 * {\n * fallback: () => <div>Please sign in to continue</div>\n * }\n * );\n * ```\n *\n * @example Group Protection with Group Fallback\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 <>Welcome Admin</>;\n * },\n * {\n * groups: [\"admin\"],\n * groupFallback: (user) => <div>User {user.email} is not an admin</div>\n * }\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?.fallback) {\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?.fallback) {\n return options.fallback();\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 { groupFallback = (): JSX.Element => <div>Access Denied</div> } =\n options;\n return groupFallback(user);\n }\n\n return <Component user={user} {...props} />;\n }\n\n return null;\n };\n};\n"],"mappings":"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"}
|