|
1 | 1 | import fs from "fs"; |
2 | 2 | import session from "express-session"; |
3 | | -import jwt from "jsonwebtoken"; |
4 | 3 | import passport from "passport"; |
5 | 4 | import { Issuer, Strategy } from "openid-client"; |
6 | 5 |
|
7 | 6 | export let client; |
8 | 7 | export let issuerUrl; |
9 | 8 | export let keycloakIssuer; |
10 | 9 |
|
| 10 | +function base64urlToUtf8(str) { |
| 11 | + // base64url -> base64 |
| 12 | + str = str.replace(/-/g, "+").replace(/_/g, "/"); |
| 13 | + // padding |
| 14 | + const pad = str.length % 4; |
| 15 | + if (pad) str += "=".repeat(4 - pad); |
| 16 | + return Buffer.from(str, "base64").toString("utf8"); |
| 17 | +} |
| 18 | + |
| 19 | +export function jwtDecode(token) { |
| 20 | + if (typeof token !== "string") return null; |
| 21 | + const parts = token.split("."); |
| 22 | + if (parts.length < 2) return null; |
| 23 | + |
| 24 | + try { |
| 25 | + const header = JSON.parse(base64urlToUtf8(parts[0])); |
| 26 | + const payload = JSON.parse(base64urlToUtf8(parts[1])); |
| 27 | + return { header, payload }; |
| 28 | + } catch { |
| 29 | + return null; |
| 30 | + } |
| 31 | +} |
| 32 | + |
11 | 33 | export async function initKeycloak(app) { |
12 | 34 | // Load keycloak.json |
13 | 35 | const kcConfig = JSON.parse(fs.readFileSync("keycloak.json", "utf8")); |
@@ -46,10 +68,11 @@ export async function initKeycloak(app) { |
46 | 68 | const accessToken = tokenSet.access_token; |
47 | 69 | const refreshToken = tokenSet.refresh_token; |
48 | 70 | // Decode the ID token to get the user profile |
49 | | - const userProfile = jwt.decode(idToken); |
| 71 | + const id = jwtDecode(idToken); |
| 72 | + const userProfile = id?.payload; |
50 | 73 | // Include the access token in the user profile |
51 | 74 | userProfile.accessToken = accessToken; |
52 | | - userProfile.accessTokenDecoded = jwt.decode(accessToken); |
| 75 | + userProfile.accessTokenDecoded = jwtDecode(accessToken)?.payload; |
53 | 76 | userProfile.refreshToken = refreshToken; |
54 | 77 | userProfile.keycloakConfig = kcConfig; |
55 | 78 | done(null, userProfile, { returnTo: req.session.originalUrl }); |
@@ -137,7 +160,8 @@ export async function refreshAccessToken(req) { |
137 | 160 | try { |
138 | 161 | const tokenSet = await client.refresh(req.user.refreshToken); |
139 | 162 | req.user.accessToken = tokenSet.access_token; |
140 | | - req.user.accessTokenDecoded = jwt.decode(tokenSet.access_token); |
| 163 | + const access = jwtDecode(tokenSet.access_token); |
| 164 | + req.user.accessTokenDecoded = access?.payload; |
141 | 165 | req.user.refreshToken = tokenSet.refresh_token; |
142 | 166 | req.user.rolesCalculated = JSON.stringify(getLdapGroups(req)); |
143 | 167 | // Get updated user information |
|
0 commit comments