@cas-system/nextjs-cas-client 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +148 -0
  3. package/dist/CasProvider.d.ts +63 -0
  4. package/dist/CasProvider.d.ts.map +1 -0
  5. package/dist/CasProvider.js +150 -0
  6. package/dist/CasProvider.js.map +1 -0
  7. package/dist/components/CasLoginButton.d.ts +36 -0
  8. package/dist/components/CasLoginButton.d.ts.map +1 -0
  9. package/dist/components/CasLoginButton.js +23 -0
  10. package/dist/components/CasLoginButton.js.map +1 -0
  11. package/dist/components/CasProtectedRoute.d.ts +51 -0
  12. package/dist/components/CasProtectedRoute.d.ts.map +1 -0
  13. package/dist/components/CasProtectedRoute.js +58 -0
  14. package/dist/components/CasProtectedRoute.js.map +1 -0
  15. package/dist/handlers/callback.d.ts +39 -0
  16. package/dist/handlers/callback.d.ts.map +1 -0
  17. package/dist/handlers/callback.js +65 -0
  18. package/dist/handlers/callback.js.map +1 -0
  19. package/dist/handlers/index.d.ts +8 -0
  20. package/dist/handlers/index.d.ts.map +1 -0
  21. package/dist/handlers/index.js +8 -0
  22. package/dist/handlers/index.js.map +1 -0
  23. package/dist/handlers/logout.d.ts +36 -0
  24. package/dist/handlers/logout.d.ts.map +1 -0
  25. package/dist/handlers/logout.js +61 -0
  26. package/dist/handlers/logout.js.map +1 -0
  27. package/dist/handlers/user.d.ts +27 -0
  28. package/dist/handlers/user.d.ts.map +1 -0
  29. package/dist/handlers/user.js +44 -0
  30. package/dist/handlers/user.js.map +1 -0
  31. package/dist/hooks/useCasAuth.d.ts +32 -0
  32. package/dist/hooks/useCasAuth.d.ts.map +1 -0
  33. package/dist/hooks/useCasAuth.js +14 -0
  34. package/dist/hooks/useCasAuth.js.map +1 -0
  35. package/dist/hooks/useCasUser.d.ts +33 -0
  36. package/dist/hooks/useCasUser.d.ts.map +1 -0
  37. package/dist/hooks/useCasUser.js +45 -0
  38. package/dist/hooks/useCasUser.js.map +1 -0
  39. package/dist/index.d.ts +19 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +17 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/middleware.d.ts +40 -0
  44. package/dist/middleware.d.ts.map +1 -0
  45. package/dist/middleware.js +111 -0
  46. package/dist/middleware.js.map +1 -0
  47. package/dist/server/auth.d.ts +111 -0
  48. package/dist/server/auth.d.ts.map +1 -0
  49. package/dist/server/auth.js +215 -0
  50. package/dist/server/auth.js.map +1 -0
  51. package/dist/server/cas-client.d.ts +93 -0
  52. package/dist/server/cas-client.d.ts.map +1 -0
  53. package/dist/server/cas-client.js +222 -0
  54. package/dist/server/cas-client.js.map +1 -0
  55. package/dist/server/index.d.ts +12 -0
  56. package/dist/server/index.d.ts.map +1 -0
  57. package/dist/server/index.js +11 -0
  58. package/dist/server/index.js.map +1 -0
  59. package/dist/types.d.ts +170 -0
  60. package/dist/types.d.ts.map +1 -0
  61. package/dist/types.js +6 -0
  62. package/dist/types.js.map +1 -0
  63. package/package.json +73 -0
@@ -0,0 +1,65 @@
1
+ /**
2
+ * @module @cas-system/nextjs-cas-client/handlers/callback
3
+ * @description API route handler for the CAS SSO callback endpoint.
4
+ *
5
+ * After the CAS server authenticates the user it redirects to
6
+ * `{callbackUrl}?token=JWT_TOKEN`. This handler:
7
+ *
8
+ * 1. Extracts the `token` query parameter.
9
+ * 2. Validates it server-side via the CAS `/api/validate-token` endpoint.
10
+ * 3. Sets an encrypted session cookie.
11
+ * 4. Redirects the user to the intended URL (or `/`).
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * // app/api/cas/callback/route.ts
16
+ * import { createCallbackHandler } from '@cas-system/nextjs-cas-client/handlers';
17
+ *
18
+ * const handler = createCallbackHandler({
19
+ * cas: {
20
+ * serverUrl: process.env.CAS_SERVER_URL!,
21
+ * clientId: process.env.CAS_CLIENT_ID!,
22
+ * clientSecret: process.env.CAS_CLIENT_SECRET!,
23
+ * },
24
+ * afterLoginUrl: '/dashboard',
25
+ * });
26
+ *
27
+ * export { handler as GET };
28
+ * ```
29
+ */
30
+ import { NextResponse } from 'next/server';
31
+ import { cookies } from 'next/headers';
32
+ import { CasClient } from '../server/cas-client';
33
+ import { setCasSession } from '../server/auth';
34
+ /**
35
+ * Create a GET handler for `/api/cas/callback`.
36
+ *
37
+ * @param config - Handler configuration including CAS server details.
38
+ * @returns A Next.js App Router GET handler.
39
+ */
40
+ export function createCallbackHandler(config) {
41
+ const cas = new CasClient(config.cas);
42
+ const afterLoginUrl = config.afterLoginUrl ?? '/';
43
+ return async function GET(request) {
44
+ const { searchParams } = request.nextUrl;
45
+ const token = searchParams.get('token');
46
+ const returnUrl = searchParams.get('returnUrl') ?? afterLoginUrl;
47
+ if (!token) {
48
+ console.error('[CasCallback] No token query parameter received.');
49
+ return NextResponse.redirect(new URL('/login?error=no_token', request.url));
50
+ }
51
+ // Validate the token server-side
52
+ const user = await cas.validateToken(token);
53
+ if (!user) {
54
+ console.error('[CasCallback] Token validation failed.');
55
+ return NextResponse.redirect(new URL('/login?error=invalid_token', request.url));
56
+ }
57
+ // Set session cookie
58
+ const cookieStore = await cookies();
59
+ await setCasSession(cookieStore, user, token);
60
+ // Redirect to the intended URL
61
+ const redirectUrl = new URL(returnUrl, request.url);
62
+ return NextResponse.redirect(redirectUrl);
63
+ };
64
+ }
65
+ //# sourceMappingURL=callback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callback.js","sourceRoot":"","sources":["../../src/handlers/callback.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAe,YAAY,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/C;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAwB;IAC5D,MAAM,GAAG,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACtC,MAAM,aAAa,GAAG,MAAM,CAAC,aAAa,IAAI,GAAG,CAAC;IAElD,OAAO,KAAK,UAAU,GAAG,CAAC,OAAoB;QAC5C,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;QACzC,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACxC,MAAM,SAAS,GAAG,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,aAAa,CAAC;QAEjE,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;YAClE,OAAO,YAAY,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,uBAAuB,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9E,CAAC;QAED,iCAAiC;QACjC,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAE5C,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;YACxD,OAAO,YAAY,CAAC,QAAQ,CAC1B,IAAI,GAAG,CAAC,4BAA4B,EAAE,OAAO,CAAC,GAAG,CAAC,CACnD,CAAC;QACJ,CAAC;QAED,qBAAqB;QACrB,MAAM,WAAW,GAAG,MAAM,OAAO,EAAE,CAAC;QACpC,MAAM,aAAa,CAAC,WAAW,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QAE9C,+BAA+B;QAC/B,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;QACpD,OAAO,YAAY,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IAC5C,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @module @cas-system/nextjs-cas-client/handlers
3
+ * @description Re-exports all API route handler factories.
4
+ */
5
+ export { createCallbackHandler } from './callback';
6
+ export { createLogoutHandler } from './logout';
7
+ export { createUserHandler } from './user';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/handlers/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @module @cas-system/nextjs-cas-client/handlers
3
+ * @description Re-exports all API route handler factories.
4
+ */
5
+ export { createCallbackHandler } from './callback';
6
+ export { createLogoutHandler } from './logout';
7
+ export { createUserHandler } from './user';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/handlers/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @module @cas-system/nextjs-cas-client/handlers/logout
3
+ * @description API route handler for the CAS logout endpoint.
4
+ *
5
+ * 1. Reads the session to obtain the JWT token.
6
+ * 2. Notifies the CAS server of the logout.
7
+ * 3. Clears the session cookies.
8
+ * 4. Redirects the user (or returns 200 for API calls).
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * // app/api/cas/logout/route.ts
13
+ * import { createLogoutHandler } from '@cas-system/nextjs-cas-client/handlers';
14
+ *
15
+ * const handler = createLogoutHandler({
16
+ * cas: {
17
+ * serverUrl: process.env.CAS_SERVER_URL!,
18
+ * clientId: process.env.CAS_CLIENT_ID!,
19
+ * clientSecret: process.env.CAS_CLIENT_SECRET!,
20
+ * },
21
+ * afterLogoutUrl: '/',
22
+ * });
23
+ *
24
+ * export { handler as POST };
25
+ * ```
26
+ */
27
+ import { NextRequest, NextResponse } from 'next/server';
28
+ import type { CasHandlerConfig } from '../types';
29
+ /**
30
+ * Create a POST handler for `/api/cas/logout`.
31
+ *
32
+ * @param config - Handler configuration.
33
+ * @returns A Next.js App Router POST handler.
34
+ */
35
+ export declare function createLogoutHandler(config: CasHandlerConfig): (request: NextRequest) => Promise<NextResponse>;
36
+ //# sourceMappingURL=logout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../src/handlers/logout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAExD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAIjD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,gBAAgB,IAI/B,SAAS,WAAW,KAAG,OAAO,CAAC,YAAY,CAAC,CAyBxE"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * @module @cas-system/nextjs-cas-client/handlers/logout
3
+ * @description API route handler for the CAS logout endpoint.
4
+ *
5
+ * 1. Reads the session to obtain the JWT token.
6
+ * 2. Notifies the CAS server of the logout.
7
+ * 3. Clears the session cookies.
8
+ * 4. Redirects the user (or returns 200 for API calls).
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * // app/api/cas/logout/route.ts
13
+ * import { createLogoutHandler } from '@cas-system/nextjs-cas-client/handlers';
14
+ *
15
+ * const handler = createLogoutHandler({
16
+ * cas: {
17
+ * serverUrl: process.env.CAS_SERVER_URL!,
18
+ * clientId: process.env.CAS_CLIENT_ID!,
19
+ * clientSecret: process.env.CAS_CLIENT_SECRET!,
20
+ * },
21
+ * afterLogoutUrl: '/',
22
+ * });
23
+ *
24
+ * export { handler as POST };
25
+ * ```
26
+ */
27
+ import { NextResponse } from 'next/server';
28
+ import { cookies } from 'next/headers';
29
+ import { CasClient } from '../server/cas-client';
30
+ import { getCasSession, clearCasSession } from '../server/auth';
31
+ /**
32
+ * Create a POST handler for `/api/cas/logout`.
33
+ *
34
+ * @param config - Handler configuration.
35
+ * @returns A Next.js App Router POST handler.
36
+ */
37
+ export function createLogoutHandler(config) {
38
+ const cas = new CasClient(config.cas);
39
+ const afterLogoutUrl = config.afterLogoutUrl ?? '/';
40
+ return async function POST(request) {
41
+ const cookieStore = await cookies();
42
+ // Attempt to read the current session for the token
43
+ const session = await getCasSession(cookieStore);
44
+ // Notify the CAS server (best-effort)
45
+ if (session?.token) {
46
+ await cas.logout(session.token).catch(() => {
47
+ // Swallow — the local session will be cleared regardless
48
+ });
49
+ }
50
+ // Clear local session cookies
51
+ clearCasSession(cookieStore);
52
+ // If the request expects JSON (e.g. fetch from client), return 200
53
+ const accept = request.headers.get('accept') ?? '';
54
+ if (accept.includes('application/json')) {
55
+ return NextResponse.json({ success: true });
56
+ }
57
+ // Otherwise redirect
58
+ return NextResponse.redirect(new URL(afterLogoutUrl, request.url));
59
+ };
60
+ }
61
+ //# sourceMappingURL=logout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/handlers/logout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAe,YAAY,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEhE;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAwB;IAC1D,MAAM,GAAG,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACtC,MAAM,cAAc,GAAG,MAAM,CAAC,cAAc,IAAI,GAAG,CAAC;IAEpD,OAAO,KAAK,UAAU,IAAI,CAAC,OAAoB;QAC7C,MAAM,WAAW,GAAG,MAAM,OAAO,EAAE,CAAC;QAEpC,oDAAoD;QACpD,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,WAAW,CAAC,CAAC;QAEjD,sCAAsC;QACtC,IAAI,OAAO,EAAE,KAAK,EAAE,CAAC;YACnB,MAAM,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;gBACzC,yDAAyD;YAC3D,CAAC,CAAC,CAAC;QACL,CAAC;QAED,8BAA8B;QAC9B,eAAe,CAAC,WAAW,CAAC,CAAC;QAE7B,mEAAmE;QACnE,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnD,IAAI,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;YACxC,OAAO,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,CAAC;QAED,qBAAqB;QACrB,OAAO,YAAY,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IACrE,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @module @cas-system/nextjs-cas-client/handlers/user
3
+ * @description API route handler that returns the current CAS user from
4
+ * the session cookie. This endpoint is called by the client-side
5
+ * `CasProvider` to hydrate the auth state.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * // app/api/cas/user/route.ts
10
+ * import { createUserHandler } from '@cas-system/nextjs-cas-client/handlers';
11
+ *
12
+ * const handler = createUserHandler();
13
+ * export { handler as GET };
14
+ * ```
15
+ */
16
+ import { NextResponse } from 'next/server';
17
+ /**
18
+ * Create a GET handler for `/api/cas/user`.
19
+ *
20
+ * Returns `{ user: CasUser }` when authenticated, or `401` otherwise.
21
+ * The response includes `Cache-Control: no-store` to prevent caching of
22
+ * auth state.
23
+ *
24
+ * @returns A Next.js App Router GET handler.
25
+ */
26
+ export declare function createUserHandler(): () => Promise<NextResponse>;
27
+ //# sourceMappingURL=user.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../src/handlers/user.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,UACF,OAAO,CAAC,YAAY,CAAC,CAsBnD"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @module @cas-system/nextjs-cas-client/handlers/user
3
+ * @description API route handler that returns the current CAS user from
4
+ * the session cookie. This endpoint is called by the client-side
5
+ * `CasProvider` to hydrate the auth state.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * // app/api/cas/user/route.ts
10
+ * import { createUserHandler } from '@cas-system/nextjs-cas-client/handlers';
11
+ *
12
+ * const handler = createUserHandler();
13
+ * export { handler as GET };
14
+ * ```
15
+ */
16
+ import { NextResponse } from 'next/server';
17
+ import { cookies } from 'next/headers';
18
+ import { getCasSession } from '../server/auth';
19
+ /**
20
+ * Create a GET handler for `/api/cas/user`.
21
+ *
22
+ * Returns `{ user: CasUser }` when authenticated, or `401` otherwise.
23
+ * The response includes `Cache-Control: no-store` to prevent caching of
24
+ * auth state.
25
+ *
26
+ * @returns A Next.js App Router GET handler.
27
+ */
28
+ export function createUserHandler() {
29
+ return async function GET() {
30
+ const cookieStore = await cookies();
31
+ const session = await getCasSession(cookieStore);
32
+ if (!session) {
33
+ return NextResponse.json({ user: null, error: 'Not authenticated' }, {
34
+ status: 401,
35
+ headers: { 'Cache-Control': 'no-store' },
36
+ });
37
+ }
38
+ return NextResponse.json({ user: session.user }, {
39
+ status: 200,
40
+ headers: { 'Cache-Control': 'no-store' },
41
+ });
42
+ };
43
+ }
44
+ //# sourceMappingURL=user.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user.js","sourceRoot":"","sources":["../../src/handlers/user.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/C;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,KAAK,UAAU,GAAG;QACvB,MAAM,WAAW,GAAG,MAAM,OAAO,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,WAAW,CAAC,CAAC;QAEjD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,YAAY,CAAC,IAAI,CACtB,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,mBAAmB,EAAE,EAC1C;gBACE,MAAM,EAAE,GAAG;gBACX,OAAO,EAAE,EAAE,eAAe,EAAE,UAAU,EAAE;aACzC,CACF,CAAC;QACJ,CAAC;QAED,OAAO,YAAY,CAAC,IAAI,CACtB,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,EACtB;YACE,MAAM,EAAE,GAAG;YACX,OAAO,EAAE,EAAE,eAAe,EAAE,UAAU,EAAE;SACzC,CACF,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @module @cas-system/nextjs-cas-client/hooks/useCasAuth
3
+ * @description Client-side hook for accessing CAS authentication state and
4
+ * actions (login, logout, refresh).
5
+ *
6
+ * @example
7
+ * ```tsx
8
+ * 'use client';
9
+ * import { useCasAuth } from '@cas-system/nextjs-cas-client';
10
+ *
11
+ * export function Navbar() {
12
+ * const { user, isAuthenticated, login, logout } = useCasAuth();
13
+ *
14
+ * return isAuthenticated ? (
15
+ * <button onClick={logout}>Sign out ({user?.username})</button>
16
+ * ) : (
17
+ * <button onClick={() => login()}>Sign in</button>
18
+ * );
19
+ * }
20
+ * ```
21
+ */
22
+ import type { CasAuthContext } from '../types';
23
+ /**
24
+ * Access CAS authentication state and actions.
25
+ *
26
+ * This is a convenience re-export of the context hook. Must be used inside
27
+ * a `<CasProvider>`.
28
+ *
29
+ * @returns The full {@link CasAuthContext}.
30
+ */
31
+ export declare function useCasAuth(): CasAuthContext;
32
+ //# sourceMappingURL=useCasAuth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCasAuth.d.ts","sourceRoot":"","sources":["../../src/hooks/useCasAuth.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAG/C;;;;;;;GAOG;AACH,wBAAgB,UAAU,IAAI,cAAc,CAE3C"}
@@ -0,0 +1,14 @@
1
+ 'use client';
2
+ import { useCasAuthContext } from '../CasProvider';
3
+ /**
4
+ * Access CAS authentication state and actions.
5
+ *
6
+ * This is a convenience re-export of the context hook. Must be used inside
7
+ * a `<CasProvider>`.
8
+ *
9
+ * @returns The full {@link CasAuthContext}.
10
+ */
11
+ export function useCasAuth() {
12
+ return useCasAuthContext();
13
+ }
14
+ //# sourceMappingURL=useCasAuth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCasAuth.js","sourceRoot":"","sources":["../../src/hooks/useCasAuth.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAyBb,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnD;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU;IACxB,OAAO,iBAAiB,EAAE,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,33 @@
1
+ import type { CasUser } from '../types';
2
+ /** Return type of {@link useCasUser}. */
3
+ export interface UseCasUserReturn {
4
+ /** The current user, or `null` when not authenticated. */
5
+ user: CasUser | null;
6
+ /** Whether the initial session fetch is still loading. */
7
+ isLoading: boolean;
8
+ /** Whether a valid session exists. */
9
+ isAuthenticated: boolean;
10
+ /**
11
+ * Check whether the current user has **all** of the specified roles.
12
+ *
13
+ * @param roles - Required roles.
14
+ * @returns `true` if the user possesses every role (or the list is empty).
15
+ */
16
+ hasRole: (...roles: string[]) => boolean;
17
+ /**
18
+ * Check whether the current user has **at least one** of the specified roles.
19
+ *
20
+ * @param roles - Roles to check.
21
+ * @returns `true` if the user possesses any one role.
22
+ */
23
+ hasAnyRole: (...roles: string[]) => boolean;
24
+ /** All roles assigned to the current user (empty array when unauthenticated). */
25
+ roles: string[];
26
+ }
27
+ /**
28
+ * Hook for accessing the current CAS user and performing role checks.
29
+ *
30
+ * Must be used inside a `<CasProvider>`.
31
+ */
32
+ export declare function useCasUser(): UseCasUserReturn;
33
+ //# sourceMappingURL=useCasUser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCasUser.d.ts","sourceRoot":"","sources":["../../src/hooks/useCasUser.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAGxC,yCAAyC;AACzC,MAAM,WAAW,gBAAgB;IAC/B,0DAA0D;IAC1D,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IAErB,0DAA0D;IAC1D,SAAS,EAAE,OAAO,CAAC;IAEnB,sCAAsC;IACtC,eAAe,EAAE,OAAO,CAAC;IAEzB;;;;;OAKG;IACH,OAAO,EAAE,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC;IAEzC;;;;;OAKG;IACH,UAAU,EAAE,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC;IAE5C,iFAAiF;IACjF,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,gBAAgB,CAsB7C"}
@@ -0,0 +1,45 @@
1
+ 'use client';
2
+ /**
3
+ * @module @cas-system/nextjs-cas-client/hooks/useCasUser
4
+ * @description Client-side hook focused on the current CAS user and
5
+ * role-based access control helpers.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * 'use client';
10
+ * import { useCasUser } from '@cas-system/nextjs-cas-client';
11
+ *
12
+ * export function AdminPanel() {
13
+ * const { user, hasRole, hasAnyRole } = useCasUser();
14
+ *
15
+ * if (!hasRole('admin')) {
16
+ * return <p>Access denied</p>;
17
+ * }
18
+ *
19
+ * return <h1>Welcome admin {user?.username}</h1>;
20
+ * }
21
+ * ```
22
+ */
23
+ import { useCallback, useMemo } from 'react';
24
+ import { useCasAuthContext } from '../CasProvider';
25
+ /**
26
+ * Hook for accessing the current CAS user and performing role checks.
27
+ *
28
+ * Must be used inside a `<CasProvider>`.
29
+ */
30
+ export function useCasUser() {
31
+ const { user, isLoading, isAuthenticated } = useCasAuthContext();
32
+ const roles = useMemo(() => user?.roles ?? [], [user]);
33
+ const hasRole = useCallback((...required) => {
34
+ if (!user?.roles)
35
+ return required.length === 0;
36
+ return required.every((r) => user.roles.includes(r));
37
+ }, [user]);
38
+ const hasAnyRole = useCallback((...candidates) => {
39
+ if (!user?.roles)
40
+ return false;
41
+ return candidates.some((r) => user.roles.includes(r));
42
+ }, [user]);
43
+ return { user, isLoading, isAuthenticated, hasRole, hasAnyRole, roles };
44
+ }
45
+ //# sourceMappingURL=useCasUser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCasUser.js","sourceRoot":"","sources":["../../src/hooks/useCasUser.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAE7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAiCnD;;;;GAIG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,eAAe,EAAE,GAAG,iBAAiB,EAAE,CAAC;IAEjE,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAEvD,MAAM,OAAO,GAAG,WAAW,CACzB,CAAC,GAAG,QAAkB,EAAE,EAAE;QACxB,IAAI,CAAC,IAAI,EAAE,KAAK;YAAE,OAAO,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC;QAC/C,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC,EACD,CAAC,IAAI,CAAC,CACP,CAAC;IAEF,MAAM,UAAU,GAAG,WAAW,CAC5B,CAAC,GAAG,UAAoB,EAAE,EAAE;QAC1B,IAAI,CAAC,IAAI,EAAE,KAAK;YAAE,OAAO,KAAK,CAAC;QAC/B,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACzD,CAAC,EACD,CAAC,IAAI,CAAC,CACP,CAAC;IAEF,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,eAAe,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;AAC1E,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @module @cas-system/nextjs-cas-client
3
+ * @description Public entry point for the Next.js CAS Client SDK.
4
+ *
5
+ * Re-exports the client-side provider, hooks, components, and shared types.
6
+ * Server-only helpers live under `@cas-system/nextjs-cas-client/server`,
7
+ * route handlers under `/handlers`, and middleware under `/middleware`.
8
+ */
9
+ export { CasProvider, useCasAuthContext } from './CasProvider';
10
+ export type { CasProviderProps } from './CasProvider';
11
+ export { useCasAuth } from './hooks/useCasAuth';
12
+ export { useCasUser } from './hooks/useCasUser';
13
+ export type { UseCasUserReturn } from './hooks/useCasUser';
14
+ export { CasLoginButton } from './components/CasLoginButton';
15
+ export type { CasLoginButtonProps } from './components/CasLoginButton';
16
+ export { CasProtectedRoute } from './components/CasProtectedRoute';
17
+ export type { CasProtectedRouteProps } from './components/CasProtectedRoute';
18
+ export type { CasConfig, CasServerConfig, CasUser, CasSessionData, CasMiddlewareConfig, CasAuthContext, CasHandlerConfig, } from './types';
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC/D,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGtD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG3D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,YAAY,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,YAAY,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAG7E,YAAY,EACV,SAAS,EACT,eAAe,EACf,OAAO,EACP,cAAc,EACd,mBAAmB,EACnB,cAAc,EACd,gBAAgB,GACjB,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @module @cas-system/nextjs-cas-client
3
+ * @description Public entry point for the Next.js CAS Client SDK.
4
+ *
5
+ * Re-exports the client-side provider, hooks, components, and shared types.
6
+ * Server-only helpers live under `@cas-system/nextjs-cas-client/server`,
7
+ * route handlers under `/handlers`, and middleware under `/middleware`.
8
+ */
9
+ // Provider + context hook
10
+ export { CasProvider, useCasAuthContext } from './CasProvider';
11
+ // Hooks
12
+ export { useCasAuth } from './hooks/useCasAuth';
13
+ export { useCasUser } from './hooks/useCasUser';
14
+ // Components
15
+ export { CasLoginButton } from './components/CasLoginButton';
16
+ export { CasProtectedRoute } from './components/CasProtectedRoute';
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,0BAA0B;AAC1B,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAG/D,QAAQ;AACR,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGhD,aAAa;AACb,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAE7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @module @cas-system/nextjs-cas-client/middleware
3
+ * @description Factory for creating a Next.js middleware that guards routes
4
+ * behind CAS authentication.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * // middleware.ts (project root)
9
+ * import { createCasMiddleware } from '@cas-system/nextjs-cas-client/middleware';
10
+ *
11
+ * export default createCasMiddleware({
12
+ * protectedPaths: ['/dashboard', '/admin', '/settings'],
13
+ * publicPaths: ['/api/health'],
14
+ * loginPath: '/login',
15
+ * });
16
+ *
17
+ * export const config = {
18
+ * matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
19
+ * };
20
+ * ```
21
+ */
22
+ import { NextRequest, NextResponse } from 'next/server';
23
+ import type { CasMiddlewareConfig } from './types';
24
+ /**
25
+ * Create a Next.js middleware function that enforces CAS authentication on
26
+ * the configured protected paths.
27
+ *
28
+ * @param config - Middleware configuration.
29
+ * @returns A Next.js-compatible middleware function.
30
+ *
31
+ * @remarks
32
+ * - If the request targets a **public path** it is always allowed through.
33
+ * - If the request targets a **protected path** and there is no valid CAS
34
+ * session cookie, the user is redirected to either the `loginPath` (if
35
+ * set) or the CAS server SSO login page.
36
+ * - The original URL is forwarded as a `?returnUrl=…` query parameter so
37
+ * the login page can redirect back after authentication.
38
+ */
39
+ export declare function createCasMiddleware(config: CasMiddlewareConfig): (request: NextRequest) => Promise<NextResponse>;
40
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAanD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,mBAAmB,IAQ3D,SAAS,WAAW,KACnB,OAAO,CAAC,YAAY,CAAC,CA+EzB"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * @module @cas-system/nextjs-cas-client/middleware
3
+ * @description Factory for creating a Next.js middleware that guards routes
4
+ * behind CAS authentication.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * // middleware.ts (project root)
9
+ * import { createCasMiddleware } from '@cas-system/nextjs-cas-client/middleware';
10
+ *
11
+ * export default createCasMiddleware({
12
+ * protectedPaths: ['/dashboard', '/admin', '/settings'],
13
+ * publicPaths: ['/api/health'],
14
+ * loginPath: '/login',
15
+ * });
16
+ *
17
+ * export const config = {
18
+ * matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
19
+ * };
20
+ * ```
21
+ */
22
+ import { NextResponse } from 'next/server';
23
+ import { getCasSessionFromRequest } from './server/auth';
24
+ /**
25
+ * Check whether `pathname` starts with any of the given prefixes.
26
+ * @internal
27
+ */
28
+ function matchesAny(pathname, prefixes) {
29
+ return prefixes.some((p) => pathname === p || pathname.startsWith(p.endsWith('/') ? p : `${p}/`));
30
+ }
31
+ /**
32
+ * Create a Next.js middleware function that enforces CAS authentication on
33
+ * the configured protected paths.
34
+ *
35
+ * @param config - Middleware configuration.
36
+ * @returns A Next.js-compatible middleware function.
37
+ *
38
+ * @remarks
39
+ * - If the request targets a **public path** it is always allowed through.
40
+ * - If the request targets a **protected path** and there is no valid CAS
41
+ * session cookie, the user is redirected to either the `loginPath` (if
42
+ * set) or the CAS server SSO login page.
43
+ * - The original URL is forwarded as a `?returnUrl=…` query parameter so
44
+ * the login page can redirect back after authentication.
45
+ */
46
+ export function createCasMiddleware(config) {
47
+ const { protectedPaths, publicPaths = [], loginPath, } = config;
48
+ return async function casMiddleware(request) {
49
+ const { pathname } = request.nextUrl;
50
+ // 1. Skip static assets and internal Next.js routes
51
+ if (pathname.startsWith('/_next') ||
52
+ pathname.startsWith('/favicon') ||
53
+ pathname.includes('.')) {
54
+ return NextResponse.next();
55
+ }
56
+ // 2. Always allow explicitly public paths
57
+ if (matchesAny(pathname, publicPaths)) {
58
+ return NextResponse.next();
59
+ }
60
+ // 3. Check whether this path requires authentication
61
+ const isProtected = matchesAny(pathname, protectedPaths);
62
+ if (!isProtected) {
63
+ return NextResponse.next();
64
+ }
65
+ // 4. Attempt to read the session from cookies
66
+ const session = await getCasSessionFromRequest(request);
67
+ if (session) {
68
+ // Authenticated — attach user info as request headers so downstream
69
+ // Server Components / Route Handlers can read them without re-parsing
70
+ // the cookie.
71
+ const requestHeaders = new Headers(request.headers);
72
+ requestHeaders.set('x-cas-user', JSON.stringify(session.user));
73
+ requestHeaders.set('x-cas-authenticated', 'true');
74
+ return NextResponse.next({
75
+ request: { headers: requestHeaders },
76
+ });
77
+ }
78
+ // 5. Not authenticated — redirect to login
79
+ const returnUrl = request.nextUrl.pathname + request.nextUrl.search;
80
+ if (loginPath) {
81
+ // Redirect to the app's own login page
82
+ const loginUrl = new URL(loginPath, request.url);
83
+ loginUrl.searchParams.set('returnUrl', returnUrl);
84
+ return NextResponse.redirect(loginUrl);
85
+ }
86
+ // Redirect directly to the CAS SSO login page.
87
+ // The browser must reach CAS at its PUBLIC base url, which may differ from
88
+ // the internal back-channel url used for server-to-server validation.
89
+ // Prefer CAS_PUBLIC_URL; fall back to CAS_SERVER_URL for single-url setups.
90
+ const casServerUrl = process.env.CAS_PUBLIC_URL || process.env.CAS_SERVER_URL;
91
+ const casClientId = process.env.CAS_CLIENT_ID;
92
+ const casCallbackUrl = process.env.CAS_CALLBACK_URL ??
93
+ `${request.nextUrl.origin}/api/cas/callback`;
94
+ if (!casServerUrl || !casClientId) {
95
+ console.error('[CasMiddleware] CAS_SERVER_URL and CAS_CLIENT_ID env vars are required ' +
96
+ 'when no loginPath is configured.');
97
+ return NextResponse.next();
98
+ }
99
+ // Encode the return URL into the callback so we can redirect after login
100
+ const callbackWithReturn = new URL(casCallbackUrl);
101
+ callbackWithReturn.searchParams.set('returnUrl', returnUrl);
102
+ const params = new URLSearchParams({
103
+ client_id: casClientId,
104
+ response_type: 'token',
105
+ redirect_uri: callbackWithReturn.toString(),
106
+ });
107
+ const casLoginUrl = `${casServerUrl.replace(/\/+$/, '')}/sso/login?${params.toString()}`;
108
+ return NextResponse.redirect(casLoginUrl);
109
+ };
110
+ }
111
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}