next-auth-heksso 1.0.7 → 1.0.9

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.
@@ -2,4 +2,4 @@ import { NextAuthOptions } from "next-auth";
2
2
  /**
3
3
  * Provides authOptions for next-auth that configures it for use with the typical HEKsso setup
4
4
  */
5
- export declare const authOptions: NextAuthOptions;
5
+ export declare function configureAuthOptions(options?: NextAuthOptions): NextAuthOptions;
@@ -12,61 +12,59 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.authOptions = void 0;
15
+ exports.configureAuthOptions = void 0;
16
16
  const keycloak_1 = __importDefault(require("next-auth/providers/keycloak"));
17
17
  const refreshAccessToken_1 = require("./refreshAccessToken");
18
18
  /**
19
19
  * Provides authOptions for next-auth that configures it for use with the typical HEKsso setup
20
20
  */
21
- exports.authOptions = {
22
- secret: process.env.NEXTAUTH_SECRET,
23
- providers: [
24
- (0, keycloak_1.default)({
25
- clientId: process.env.KEYCLOAK_CLIENT_ID || "",
26
- clientSecret: process.env.KEYCLOAK_CLIENT_SECRET || "",
27
- issuer: process.env.KEYCLOAK_ISSUER,
28
- authorization: { params: { scope: "openid email profile roles" } }
29
- })
30
- ],
31
- pages: {
32
- signIn: "/",
33
- },
34
- callbacks: {
35
- jwt(data) {
36
- var _a, _b;
37
- return __awaiter(this, void 0, void 0, function* () {
38
- const hekGroups = (_a = data.profile) === null || _a === void 0 ? void 0 : _a.hekGroups;
39
- // Persist the OAuth access_token to the token right after signin
40
- if (data.account && data.user) {
41
- data.token.idToken = (_b = data.account) === null || _b === void 0 ? void 0 : _b.id_token;
42
- data.token.accessToken = data.account.access_token;
43
- data.token.hekGroups = hekGroups;
44
- data.token.username = data.profile.preferred_username;
45
- if (data.account.expires_at)
46
- data.token.accessTokenExpires = data.account.expires_at * 1000;
47
- data.token.refreshToken = data.account.refresh_token;
48
- return data.token;
49
- }
50
- // Return previous token if the access token has not expired yet
51
- if (Date.now() < data.token.accessTokenExpires) {
52
- return data.token;
53
- }
54
- // Access token has expired, try to update it
55
- return (0, refreshAccessToken_1.refreshAccessToken)(data.token);
56
- });
57
- },
58
- session({ session, token }) {
59
- return __awaiter(this, void 0, void 0, function* () {
60
- // Send properties to the client, like an access_token from a provider.
61
- const _session = session;
62
- _session.accessToken = token.accessToken;
63
- _session.accessTokenExpires = token.accessTokenExpires;
64
- _session.hekGroups = token.hekGroups || [];
65
- _session.username = token.username;
66
- if (token.error)
67
- _session.error = token.error;
68
- return _session;
69
- });
70
- }
21
+ function configureAuthOptions(options) {
22
+ let callbacks = undefined;
23
+ if (options && "callbacks" in options) {
24
+ callbacks = options.callbacks;
71
25
  }
72
- };
26
+ return Object.assign(Object.assign({}, options), { secret: process.env.NEXTAUTH_SECRET, providers: [
27
+ (0, keycloak_1.default)({
28
+ clientId: process.env.KEYCLOAK_CLIENT_ID || "",
29
+ clientSecret: process.env.KEYCLOAK_CLIENT_SECRET || "",
30
+ issuer: process.env.KEYCLOAK_ISSUER,
31
+ authorization: { params: { scope: "openid email profile roles" } }
32
+ })
33
+ ], callbacks: Object.assign({ jwt(data) {
34
+ var _a, _b;
35
+ return __awaiter(this, void 0, void 0, function* () {
36
+ const hekGroups = (_a = data.profile) === null || _a === void 0 ? void 0 : _a.hekGroups;
37
+ // Persist the OAuth access_token to the token right after signin
38
+ if (data.account && data.user) {
39
+ data.token.idToken = (_b = data.account) === null || _b === void 0 ? void 0 : _b.id_token;
40
+ data.token.accessToken = data.account.access_token;
41
+ data.token.hekGroups = hekGroups;
42
+ data.token.username = data.profile.preferred_username;
43
+ if (data.account.expires_at)
44
+ data.token.accessTokenExpires = data.account.expires_at * 1000;
45
+ data.token.refreshToken = data.account.refresh_token;
46
+ return data.token;
47
+ }
48
+ // Return previous token if the access token has not expired yet
49
+ if (Date.now() < data.token.accessTokenExpires) {
50
+ return data.token;
51
+ }
52
+ // Access token has expired, try to update it
53
+ return (0, refreshAccessToken_1.refreshAccessToken)(data.token);
54
+ });
55
+ },
56
+ session({ session, token }) {
57
+ return __awaiter(this, void 0, void 0, function* () {
58
+ // Send properties to the client, like an access_token from a provider.
59
+ const _session = session;
60
+ _session.accessToken = token.accessToken;
61
+ _session.accessTokenExpires = token.accessTokenExpires;
62
+ _session.hekGroups = token.hekGroups || [];
63
+ _session.username = token.username;
64
+ if (token.error)
65
+ _session.error = token.error;
66
+ return _session;
67
+ });
68
+ } }, callbacks) });
69
+ }
70
+ exports.configureAuthOptions = configureAuthOptions;
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "email": "contact@voakie.com"
6
6
  },
7
7
  "license": "MIT",
8
- "version": "1.0.7",
8
+ "version": "1.0.9",
9
9
  "scripts": {
10
10
  "prepublish": "rm api/ -r && rm react/ -r && tsc",
11
11
  "build": "tsc",
@@ -5,6 +5,7 @@ export interface KeycloakSession {
5
5
  getAccessToken: () => Promise<string>;
6
6
  }
7
7
  export declare const KeycloakSessionContext: React.Context<KeycloakSession>;
8
+ export declare function useKeycloakSession(): KeycloakSession;
8
9
  export declare function KeycloakSessionProvider(props: {
9
10
  children: ReactNode | ReactNode[];
10
11
  signInPage?: string;
@@ -32,7 +32,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
32
32
  });
33
33
  };
34
34
  Object.defineProperty(exports, "__esModule", { value: true });
35
- exports.KeycloakSessionProvider = exports.KeycloakSessionContext = void 0;
35
+ exports.KeycloakSessionProvider = exports.useKeycloakSession = exports.KeycloakSessionContext = void 0;
36
36
  const react_1 = require("next-auth/react");
37
37
  const router_1 = require("next/router");
38
38
  const react_2 = __importStar(require("react"));
@@ -43,6 +43,10 @@ exports.KeycloakSessionContext = (0, react_2.createContext)({
43
43
  return "";
44
44
  })
45
45
  });
46
+ function useKeycloakSession() {
47
+ return (0, react_2.useContext)(exports.KeycloakSessionContext);
48
+ }
49
+ exports.useKeycloakSession = useKeycloakSession;
46
50
  function refreshAccessToken() {
47
51
  return __awaiter(this, void 0, void 0, function* () {
48
52
  try {
@@ -106,7 +110,7 @@ function KeycloakSessionProvider(props) {
106
110
  // we check for a valid refresh token here
107
111
  (0, react_2.useEffect)(() => {
108
112
  var _a, _b, _c, _d;
109
- if (!router.asPath.startsWith(props.signInPage || "/auth/signin") &&
113
+ if (!(router.asPath.split("?")[0] === (props.signInPage || "/auth/signin")) &&
110
114
  (session.status === "unauthenticated" || accessTokenError)) {
111
115
  router.push(props.signInPage || "/auth/signin");
112
116
  return;
@@ -1,58 +1,67 @@
1
- import NextAuth, { NextAuthOptions } from "next-auth"
1
+ import { NextAuthOptions } from "next-auth"
2
2
  import KeycloakProvider from "next-auth/providers/keycloak"
3
3
  import { refreshAccessToken } from "./refreshAccessToken"
4
4
 
5
5
  /**
6
6
  * Provides authOptions for next-auth that configures it for use with the typical HEKsso setup
7
7
  */
8
- export const authOptions: NextAuthOptions = {
9
- secret: process.env.NEXTAUTH_SECRET,
10
- providers: [
11
- KeycloakProvider({
12
- clientId: process.env.KEYCLOAK_CLIENT_ID || "",
13
- clientSecret: process.env.KEYCLOAK_CLIENT_SECRET || "",
14
- issuer: process.env.KEYCLOAK_ISSUER, // something like "http://localhost:8080/realms/master"
15
- authorization: { params: { scope: "openid email profile roles" } }
16
- })
17
- ],
18
- pages: {
19
- signIn: "/",
20
- },
21
- callbacks: {
22
- async jwt(data) {
23
- const hekGroups = (data.profile as any)?.hekGroups
24
-
25
- // Persist the OAuth access_token to the token right after signin
26
- if (data.account && data.user) {
27
- data.token.idToken = data.account?.id_token
28
- data.token.accessToken = data.account.access_token
29
- data.token.hekGroups = hekGroups
30
- data.token.username = (data.profile as { [key: string]: string }).preferred_username
31
-
32
- if (data.account.expires_at)
33
- data.token.accessTokenExpires = data.account.expires_at * 1000
34
-
35
- data.token.refreshToken = data.account.refresh_token
36
- return data.token
37
- }
38
-
39
- // Return previous token if the access token has not expired yet
40
- if (Date.now() < (data.token.accessTokenExpires as number)) {
41
- return data.token
42
- }
43
-
44
- // Access token has expired, try to update it
45
- return refreshAccessToken(data.token)
46
- },
47
- async session({ session, token }) {
48
- // Send properties to the client, like an access_token from a provider.
49
- const _session = session as any
50
- _session.accessToken = token.accessToken
51
- _session.accessTokenExpires = token.accessTokenExpires
52
- _session.hekGroups = token.hekGroups || []
53
- _session.username = token.username
54
- if (token.error) _session.error = token.error
55
- return _session
8
+ export function configureAuthOptions(options?: NextAuthOptions): NextAuthOptions {
9
+ let callbacks: NextAuthOptions["callbacks"] | undefined = undefined
10
+
11
+ if (options && "callbacks" in options) {
12
+ callbacks = options.callbacks
13
+ }
14
+
15
+ return {
16
+ ...options,
17
+ secret: process.env.NEXTAUTH_SECRET,
18
+ providers: [
19
+ KeycloakProvider({
20
+ clientId: process.env.KEYCLOAK_CLIENT_ID || "",
21
+ clientSecret: process.env.KEYCLOAK_CLIENT_SECRET || "",
22
+ issuer: process.env.KEYCLOAK_ISSUER, // something like "http://localhost:8080/realms/master"
23
+ authorization: { params: { scope: "openid email profile roles" } }
24
+ })
25
+ ],
26
+ callbacks: {
27
+ async jwt(data) {
28
+ const hekGroups = (data.profile as any)?.hekGroups
29
+
30
+ // Persist the OAuth access_token to the token right after signin
31
+ if (data.account && data.user) {
32
+ data.token.idToken = data.account?.id_token
33
+ data.token.accessToken = data.account.access_token
34
+ data.token.hekGroups = hekGroups
35
+ data.token.username = (
36
+ data.profile as { [key: string]: string }
37
+ ).preferred_username
38
+
39
+ if (data.account.expires_at)
40
+ data.token.accessTokenExpires = data.account.expires_at * 1000
41
+
42
+ data.token.refreshToken = data.account.refresh_token
43
+ return data.token
44
+ }
45
+
46
+ // Return previous token if the access token has not expired yet
47
+ if (Date.now() < (data.token.accessTokenExpires as number)) {
48
+ return data.token
49
+ }
50
+
51
+ // Access token has expired, try to update it
52
+ return refreshAccessToken(data.token)
53
+ },
54
+ async session({ session, token }) {
55
+ // Send properties to the client, like an access_token from a provider.
56
+ const _session = session as any
57
+ _session.accessToken = token.accessToken
58
+ _session.accessTokenExpires = token.accessTokenExpires
59
+ _session.hekGroups = token.hekGroups || []
60
+ _session.username = token.username
61
+ if (token.error) _session.error = token.error
62
+ return _session
63
+ },
64
+ ...callbacks
56
65
  }
57
66
  }
58
67
  }
@@ -1,6 +1,6 @@
1
1
  import { signOut, useSession } from "next-auth/react"
2
2
  import { useRouter } from "next/router"
3
- import React, { createContext, ReactNode, useCallback, useEffect, useMemo, useState } from "react"
3
+ import React, { createContext, ReactNode, useCallback, useContext, useEffect, useMemo, useState } from "react"
4
4
 
5
5
  export interface KeycloakSession {
6
6
  isAuthenticated: boolean
@@ -16,6 +16,10 @@ export const KeycloakSessionContext = createContext<KeycloakSession>({
16
16
  }
17
17
  })
18
18
 
19
+ export function useKeycloakSession() {
20
+ return useContext(KeycloakSessionContext)
21
+ }
22
+
19
23
  async function refreshAccessToken() {
20
24
  try {
21
25
  const response = await fetch("/api/auth/session", {
@@ -83,7 +87,7 @@ export function KeycloakSessionProvider(props: {
83
87
  // we check for a valid refresh token here
84
88
  useEffect(() => {
85
89
  if (
86
- !router.asPath.startsWith(props.signInPage || "/auth/signin") &&
90
+ !(router.asPath.split("?")[0] === (props.signInPage || "/auth/signin")) &&
87
91
  (session.status === "unauthenticated" || accessTokenError)
88
92
  ) {
89
93
  router.push(props.signInPage || "/auth/signin")
package/tsconfig.json CHANGED
@@ -100,5 +100,5 @@
100
100
  // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
101
101
  "skipLibCheck": true /* Skip type checking all .d.ts files. */
102
102
  },
103
- "exclude": ["lib", "node_modules"]
103
+ "exclude": ["api", "react", "node_modules"]
104
104
  }