next-auth-heksso 1.1.11 → 2.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.
- package/.eslintrc.json +3 -3
- package/README.md +12 -10
- package/api/federatedLogout.d.ts +1 -2
- package/api/federatedLogout.js +25 -63
- package/api/index.js +2 -18
- package/api/nextAuthConfig.js +43 -55
- package/api/refreshAccessToken.js +32 -40
- package/package.json +39 -35
- package/react/KeycloakSessionContext.js +53 -93
- package/react/index.js +1 -17
- package/src/api/federatedLogout.ts +39 -40
- package/src/api/index.ts +2 -2
- package/src/api/nextAuthConfig.ts +67 -67
- package/src/api/refreshAccessToken.ts +46 -46
- package/src/react/KeycloakSessionContext.tsx +192 -192
- package/tsconfig.json +104 -104
package/.eslintrc.json
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "next/core-web-vitals"
|
|
3
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"extends": "next/core-web-vitals"
|
|
3
|
+
}
|
package/README.md
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
# Next-Auth config for use with HEKsso (Keycloak)
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
# Next-Auth config for use with HEKsso (Keycloak)
|
|
2
|
+
|
|
3
|
+
> Version 2 of this package is no longer in CommonJS format, instead it is in ESM format.
|
|
4
|
+
|
|
5
|
+
The following environment variables are required:
|
|
6
|
+
|
|
7
|
+
NEXTAUTH_SECRET
|
|
8
|
+
NEXTAUTH_URL
|
|
9
|
+
KEYCLOAK_ISSUER
|
|
10
|
+
KEYCLOAK_CLIENT_ID
|
|
11
|
+
KEYCLOAK_CLIENT_SECRET
|
|
12
|
+
|
|
11
13
|
See `.env.example`
|
package/api/federatedLogout.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { NextApiRequest, NextApiResponse } from "next";
|
|
2
2
|
/**
|
|
3
3
|
* Provides a next api route for performing a federated logout of the user (logs ouf of keycloak)
|
|
4
|
-
* @param
|
|
5
|
-
* @param res NextApiRequest
|
|
4
|
+
* @param logoutPath Post redirect URI
|
|
6
5
|
* @returns
|
|
7
6
|
*/
|
|
8
7
|
export declare function federatedLogout(logoutPath: string): (req: NextApiRequest, res: NextApiResponse) => Promise<NextApiResponse<any> | undefined>;
|
package/api/federatedLogout.js
CHANGED
|
@@ -1,71 +1,33 @@
|
|
|
1
|
-
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
-
});
|
|
33
|
-
};
|
|
34
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
-
exports.federatedLogout = federatedLogout;
|
|
36
|
-
const jwt = __importStar(require("next-auth/jwt"));
|
|
1
|
+
import * as jwt from "next-auth/jwt";
|
|
37
2
|
/**
|
|
38
3
|
* Provides a next api route for performing a federated logout of the user (logs ouf of keycloak)
|
|
39
|
-
* @param
|
|
40
|
-
* @param res NextApiRequest
|
|
4
|
+
* @param logoutPath Post redirect URI
|
|
41
5
|
* @returns
|
|
42
6
|
*/
|
|
43
|
-
function federatedLogout(logoutPath) {
|
|
44
|
-
return function (req, res) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
return res.redirect(process.env.NEXTAUTH_URL || "");
|
|
51
|
-
}
|
|
52
|
-
const endsessionURL = `${process.env.KEYCLOAK_ISSUER}/protocol/openid-connect/logout`;
|
|
53
|
-
if (token.idToken) {
|
|
54
|
-
console.warn("Without an id_token the user won't be redirected back from the IdP after logout.");
|
|
55
|
-
const endsessionParams = new URLSearchParams({
|
|
56
|
-
id_token_hint: token.idToken,
|
|
57
|
-
post_logout_redirect_uri: process.env.NEXTAUTH_URL + logoutPath || ""
|
|
58
|
-
});
|
|
59
|
-
return res.redirect(`${endsessionURL}?${endsessionParams}`);
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
return res.redirect(`${endsessionURL}`);
|
|
63
|
-
}
|
|
7
|
+
export function federatedLogout(logoutPath) {
|
|
8
|
+
return async function (req, res) {
|
|
9
|
+
try {
|
|
10
|
+
const token = await jwt.getToken({ req, secret: process.env.NEXTAUTH_SECRET });
|
|
11
|
+
if (!token) {
|
|
12
|
+
console.warn("No JWT token found when calling /federated-logout endpoint");
|
|
13
|
+
return res.redirect(process.env.NEXTAUTH_URL || "");
|
|
64
14
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
15
|
+
const endsessionURL = `${process.env.KEYCLOAK_ISSUER}/protocol/openid-connect/logout`;
|
|
16
|
+
if (token.idToken) {
|
|
17
|
+
console.warn("Without an id_token the user won't be redirected back from the IdP after logout.");
|
|
18
|
+
const endsessionParams = new URLSearchParams({
|
|
19
|
+
id_token_hint: token.idToken,
|
|
20
|
+
post_logout_redirect_uri: process.env.NEXTAUTH_URL + logoutPath || ""
|
|
21
|
+
});
|
|
22
|
+
return res.redirect(`${endsessionURL}?${endsessionParams}`);
|
|
68
23
|
}
|
|
69
|
-
|
|
24
|
+
else {
|
|
25
|
+
return res.redirect(`${endsessionURL}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
console.error(error);
|
|
30
|
+
res.redirect(process.env.NEXTAUTH_URL || "");
|
|
31
|
+
}
|
|
70
32
|
};
|
|
71
33
|
}
|
package/api/index.js
CHANGED
|
@@ -1,18 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./federatedLogout"), exports);
|
|
18
|
-
__exportStar(require("./nextAuthConfig"), exports);
|
|
1
|
+
export * from "./federatedLogout";
|
|
2
|
+
export * from "./nextAuthConfig";
|
package/api/nextAuthConfig.js
CHANGED
|
@@ -1,69 +1,57 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
-
};
|
|
14
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.configureAuthOptions = configureAuthOptions;
|
|
16
|
-
const keycloak_1 = __importDefault(require("next-auth/providers/keycloak"));
|
|
17
|
-
const refreshAccessToken_1 = require("./refreshAccessToken");
|
|
1
|
+
import KeycloakProvider from "next-auth/providers/keycloak";
|
|
2
|
+
import { refreshAccessToken } from "./refreshAccessToken";
|
|
18
3
|
/**
|
|
19
4
|
* Provides authOptions for next-auth that configures it for use with the typical HEKsso setup
|
|
20
5
|
*/
|
|
21
|
-
function configureAuthOptions(options) {
|
|
6
|
+
export function configureAuthOptions(options) {
|
|
22
7
|
let callbacks = undefined;
|
|
23
8
|
if (options && "callbacks" in options) {
|
|
24
9
|
callbacks = options.callbacks;
|
|
25
10
|
}
|
|
26
|
-
return
|
|
27
|
-
|
|
11
|
+
return {
|
|
12
|
+
...options,
|
|
13
|
+
secret: process.env.NEXTAUTH_SECRET,
|
|
14
|
+
providers: [
|
|
15
|
+
KeycloakProvider({
|
|
28
16
|
clientId: process.env.KEYCLOAK_CLIENT_ID || "",
|
|
29
17
|
clientSecret: process.env.KEYCLOAK_CLIENT_SECRET || "",
|
|
30
18
|
issuer: process.env.KEYCLOAK_ISSUER, // something like "http://localhost:8080/realms/master"
|
|
31
19
|
authorization: { params: { scope: "openid email profile roles" } }
|
|
32
20
|
})
|
|
33
|
-
],
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
});
|
|
21
|
+
],
|
|
22
|
+
callbacks: {
|
|
23
|
+
async jwt(data) {
|
|
24
|
+
const hekGroups = data.profile?.hekGroups;
|
|
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.preferred_username;
|
|
31
|
+
if (data.account.expires_at)
|
|
32
|
+
data.token.accessTokenExpires = data.account.expires_at * 1000;
|
|
33
|
+
data.token.refreshToken = data.account.refresh_token;
|
|
34
|
+
return data.token;
|
|
35
|
+
}
|
|
36
|
+
// Return previous token if the access token has not expired yet
|
|
37
|
+
if (Date.now() < data.token.accessTokenExpires) {
|
|
38
|
+
return data.token;
|
|
39
|
+
}
|
|
40
|
+
// Access token has expired, try to update it
|
|
41
|
+
return refreshAccessToken(data.token);
|
|
55
42
|
},
|
|
56
|
-
session(
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
43
|
+
async session({ session, token }) {
|
|
44
|
+
// Send properties to the client, like an access_token from a provider.
|
|
45
|
+
const _session = session;
|
|
46
|
+
_session.accessToken = token.accessToken;
|
|
47
|
+
_session.accessTokenExpires = token.accessTokenExpires;
|
|
48
|
+
_session.hekGroups = token.hekGroups || [];
|
|
49
|
+
_session.username = token.username;
|
|
50
|
+
if (token.error)
|
|
51
|
+
_session.error = token.error;
|
|
52
|
+
return _session;
|
|
53
|
+
},
|
|
54
|
+
...callbacks
|
|
55
|
+
}
|
|
56
|
+
};
|
|
69
57
|
}
|
|
@@ -1,15 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.refreshAccessToken = refreshAccessToken;
|
|
13
1
|
/**
|
|
14
2
|
* Takes a token, and returns a new token with updated
|
|
15
3
|
* `accessToken` and `accessTokenExpires`. If an error occurs,
|
|
@@ -17,33 +5,37 @@ exports.refreshAccessToken = refreshAccessToken;
|
|
|
17
5
|
*
|
|
18
6
|
* This is a utility function and not an API route
|
|
19
7
|
*/
|
|
20
|
-
function refreshAccessToken(token) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (!response.ok) {
|
|
39
|
-
throw refreshedTokens;
|
|
40
|
-
}
|
|
41
|
-
return Object.assign(Object.assign({}, token), { accessToken: refreshedTokens.access_token, accessTokenExpires: Date.now() + refreshedTokens.expires_in * 1000, refreshToken: (_a = refreshedTokens.refresh_token) !== null && _a !== void 0 ? _a : token.refreshToken // Fall back to old refresh token
|
|
42
|
-
});
|
|
8
|
+
export async function refreshAccessToken(token) {
|
|
9
|
+
try {
|
|
10
|
+
const url = process.env.KEYCLOAK_ISSUER + "/protocol/openid-connect/token?";
|
|
11
|
+
const response = await fetch(url, {
|
|
12
|
+
headers: {
|
|
13
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
14
|
+
},
|
|
15
|
+
method: "POST",
|
|
16
|
+
body: new URLSearchParams({
|
|
17
|
+
client_id: process.env.KEYCLOAK_CLIENT_ID || "",
|
|
18
|
+
client_secret: process.env.KEYCLOAK_CLIENT_SECRET || "",
|
|
19
|
+
grant_type: "refresh_token",
|
|
20
|
+
refresh_token: token.refreshToken
|
|
21
|
+
})
|
|
22
|
+
});
|
|
23
|
+
const refreshedTokens = await response.json();
|
|
24
|
+
if (!response.ok) {
|
|
25
|
+
throw refreshedTokens;
|
|
43
26
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
27
|
+
return {
|
|
28
|
+
...token,
|
|
29
|
+
accessToken: refreshedTokens.access_token,
|
|
30
|
+
accessTokenExpires: Date.now() + refreshedTokens.expires_in * 1000,
|
|
31
|
+
refreshToken: refreshedTokens.refresh_token ?? token.refreshToken // Fall back to old refresh token
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
console.log(error);
|
|
36
|
+
return {
|
|
37
|
+
...token,
|
|
38
|
+
error: "RefreshAccessTokenError"
|
|
39
|
+
};
|
|
40
|
+
}
|
|
49
41
|
}
|
package/package.json
CHANGED
|
@@ -1,35 +1,39 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "next-auth-heksso",
|
|
3
|
-
"author": {
|
|
4
|
-
"name": "Voakie",
|
|
5
|
-
"email": "contact@voakie.com"
|
|
6
|
-
},
|
|
7
|
-
"license": "MIT",
|
|
8
|
-
"version": "
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
"prepublish
|
|
12
|
-
"prepublish:
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"clean
|
|
16
|
-
"clean:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"react": "^
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "next-auth-heksso",
|
|
3
|
+
"author": {
|
|
4
|
+
"name": "Voakie",
|
|
5
|
+
"email": "contact@voakie.com"
|
|
6
|
+
},
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"version": "2.0.0",
|
|
9
|
+
"type": "module",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"prepublish": "run-script-os",
|
|
12
|
+
"prepublish:default": "rm -rf api/ && rm -rf react/ && tsc",
|
|
13
|
+
"prepublish:windows": "del /s /q api && del /s /q react",
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"clean": "run-script-os",
|
|
16
|
+
"clean:default": "rm api/ -r && rm react/ -r -r",
|
|
17
|
+
"clean:windows": "del /s /q api && del /s /q react"
|
|
18
|
+
},
|
|
19
|
+
"main": "api/index.js",
|
|
20
|
+
"types": "api/index.d.ts",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"run-script-os": "^1.1.6",
|
|
26
|
+
"@types/node": "^24",
|
|
27
|
+
"@types/react": "^19",
|
|
28
|
+
"@types/react-dom": "^19",
|
|
29
|
+
"eslint": "^9.13.0",
|
|
30
|
+
"eslint-config-next": "^16",
|
|
31
|
+
"typescript": "^5.6.3"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"next": "^15 || ^16",
|
|
35
|
+
"next-auth": "^4",
|
|
36
|
+
"react": "^18 || ^19",
|
|
37
|
+
"react-dom": "^18 || ^19"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -1,71 +1,32 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
-
});
|
|
33
|
-
};
|
|
34
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
-
exports.KeycloakSessionContext = void 0;
|
|
36
|
-
exports.useKeycloakSession = useKeycloakSession;
|
|
37
|
-
exports.KeycloakSessionProvider = KeycloakSessionProvider;
|
|
38
|
-
const react_1 = __importStar(require("react"));
|
|
39
|
-
exports.KeycloakSessionContext = (0, react_1.createContext)({
|
|
1
|
+
import React, { Component, createContext, useContext } from "react";
|
|
2
|
+
export const KeycloakSessionContext = createContext({
|
|
40
3
|
accessTokenError: false,
|
|
41
|
-
getAccessToken: () =>
|
|
4
|
+
getAccessToken: async () => {
|
|
42
5
|
return "";
|
|
43
|
-
}
|
|
6
|
+
}
|
|
44
7
|
});
|
|
45
|
-
function useKeycloakSession() {
|
|
46
|
-
return
|
|
8
|
+
export function useKeycloakSession() {
|
|
9
|
+
return useContext(KeycloakSessionContext);
|
|
47
10
|
}
|
|
48
|
-
function refreshAccessToken() {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
"Content-Type": "application/json"
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
const data = yield response.json();
|
|
58
|
-
if (data.error) {
|
|
59
|
-
console.error(data.error);
|
|
60
|
-
return undefined;
|
|
11
|
+
async function refreshAccessToken() {
|
|
12
|
+
try {
|
|
13
|
+
const response = await fetch("/api/auth/session", {
|
|
14
|
+
method: "GET",
|
|
15
|
+
headers: {
|
|
16
|
+
"Content-Type": "application/json"
|
|
61
17
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
console.error(
|
|
18
|
+
});
|
|
19
|
+
const data = await response.json();
|
|
20
|
+
if (data.error) {
|
|
21
|
+
console.error(data.error);
|
|
66
22
|
return undefined;
|
|
67
23
|
}
|
|
68
|
-
|
|
24
|
+
return { accessToken: data.accessToken, accessTokenExpires: data.accessTokenExpires };
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
console.error(e);
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
69
30
|
}
|
|
70
31
|
/**
|
|
71
32
|
* Provider for the useKeycloakSession react hook. Has to directly hook into next-auth and next/router
|
|
@@ -75,11 +36,12 @@ function refreshAccessToken() {
|
|
|
75
36
|
* @param children
|
|
76
37
|
* @constructor
|
|
77
38
|
*/
|
|
78
|
-
function KeycloakSessionProvider({ session, signOut, children }) {
|
|
79
|
-
return (
|
|
39
|
+
export function KeycloakSessionProvider({ session, signOut, children }) {
|
|
40
|
+
return (React.createElement(_KeycloakSessionProvider, { session: session, signOut: signOut }, children));
|
|
80
41
|
}
|
|
81
42
|
// Proxy class component to prevent unnecessary re-renders
|
|
82
|
-
class _KeycloakSessionProvider extends
|
|
43
|
+
class _KeycloakSessionProvider extends Component {
|
|
44
|
+
contextValue;
|
|
83
45
|
constructor(props) {
|
|
84
46
|
super(props);
|
|
85
47
|
this.state = {
|
|
@@ -101,39 +63,37 @@ class _KeycloakSessionProvider extends react_1.Component {
|
|
|
101
63
|
}
|
|
102
64
|
return this.contextValue;
|
|
103
65
|
}
|
|
104
|
-
getAccessToken() {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if (refreshed) {
|
|
111
|
-
this.setState({
|
|
112
|
-
accessTokenError: false,
|
|
113
|
-
accessToken: refreshed.accessToken,
|
|
114
|
-
accessTokenExpires: refreshed.accessTokenExpires
|
|
115
|
-
});
|
|
116
|
-
return refreshed.accessToken;
|
|
117
|
-
}
|
|
118
|
-
else {
|
|
119
|
-
// Refresh failed due to network error
|
|
120
|
-
return undefined;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
catch (e) {
|
|
124
|
-
// Refresh failed because keycloak denied the request
|
|
125
|
-
console.error(e);
|
|
66
|
+
async getAccessToken() {
|
|
67
|
+
if (!this.state.accessToken ||
|
|
68
|
+
(this.state.accessTokenExpires && Date.now() >= this.state.accessTokenExpires)) {
|
|
69
|
+
try {
|
|
70
|
+
const refreshed = await refreshAccessToken();
|
|
71
|
+
if (refreshed) {
|
|
126
72
|
this.setState({
|
|
127
|
-
accessTokenError:
|
|
128
|
-
accessToken:
|
|
129
|
-
accessTokenExpires:
|
|
73
|
+
accessTokenError: false,
|
|
74
|
+
accessToken: refreshed.accessToken,
|
|
75
|
+
accessTokenExpires: refreshed.accessTokenExpires
|
|
130
76
|
});
|
|
77
|
+
return refreshed.accessToken;
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
// Refresh failed due to network error
|
|
131
81
|
return undefined;
|
|
132
82
|
}
|
|
133
83
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
84
|
+
catch (e) {
|
|
85
|
+
// Refresh failed because keycloak denied the request
|
|
86
|
+
console.error(e);
|
|
87
|
+
this.setState({
|
|
88
|
+
accessTokenError: true,
|
|
89
|
+
accessToken: undefined,
|
|
90
|
+
accessTokenExpires: undefined
|
|
91
|
+
});
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else
|
|
96
|
+
return this.state.accessToken;
|
|
137
97
|
}
|
|
138
98
|
componentDidUpdate() {
|
|
139
99
|
if (sessionDataGuard(this.props.session.data)) {
|
|
@@ -157,7 +117,7 @@ class _KeycloakSessionProvider extends react_1.Component {
|
|
|
157
117
|
}
|
|
158
118
|
}
|
|
159
119
|
render() {
|
|
160
|
-
return (
|
|
120
|
+
return (React.createElement(KeycloakSessionContext.Provider, { value: this.getContextValue() }, this.props.children));
|
|
161
121
|
}
|
|
162
122
|
}
|
|
163
123
|
function sessionDataGuard(sessionData) {
|
package/react/index.js
CHANGED
|
@@ -1,17 +1 @@
|
|
|
1
|
-
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./KeycloakSessionContext"), exports);
|
|
1
|
+
export * from "./KeycloakSessionContext";
|