Skip to content
This repository has been archived by the owner on Apr 5, 2024. It is now read-only.

Commit

Permalink
feat: add keycloak secrets
Browse files Browse the repository at this point in the history
  • Loading branch information
malo-octo committed Jan 9, 2024
1 parent 04eb1f1 commit 4e6742b
Show file tree
Hide file tree
Showing 5 changed files with 231 additions and 67 deletions.
150 changes: 83 additions & 67 deletions src/pages/api/auth/[...nextauth].ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,17 @@ import { Account } from "next-auth";
import { User } from "next-auth";
import { JWT } from "next-auth/jwt";
import KeycloakProvider from "next-auth/providers/keycloak";
import VaultModule from "../../../../vault/VaultModule"

import { refreshAccessToken } from "../../../lib/auth";


const vaultModule = new VaultModule("integrated");
const keycloakClientId = vaultModule.readSecret("kv/data/integrated/keycloak_client_id")
const keycloakClientSecret = vaultModule.readSecret("kv/data/integrated/keycloak_client_secret")
const nextauthSecret = vaultModule.readSecret("kv/data/integrated/nextauth_secret")


interface ExtendedToken extends JWT {
accessToken: string;
refreshToken: string;
Expand All @@ -14,75 +22,83 @@ interface ExtendedToken extends JWT {
user: User;
}

export default NextAuth({
debug: true,
providers: [
KeycloakProvider({
clientId: process.env.KEYCLOAK_CLIENT_ID ?? "",
clientSecret: process.env.KEYCLOAK_CLIENT_SECRET ?? "",
issuer: process.env.KEYCLOAK_URL ?? "",
}),
],
export default async() => {
const clientId = await keycloakClientId;
const clientSecret = await keycloakClientSecret;
const authSecret = await nextauthSecret;

callbacks: {
//@ts-ignore
async jwt({
token,
user,
account,
}: {
token: JWT;
user: User;
account: Account;
}) {
// Initial sign in
//console.log("jwt", { token, user, account });
if (account && user) {
return {
accessToken: account.access_token,
refreshToken: account.refresh_token,
idToken: account.id_token,
accessTokenExpires: account.expires_at
? account.expires_at * 1000
: null,
user,
};
}
return await NextAuth({
debug: true,
providers: [
KeycloakProvider({
clientId: clientId ?? "",
clientSecret: clientSecret ?? "",
issuer: process.env.KEYCLOAK_URL ?? "",
}),
],
secret: authSecret,

// Return previous token if the access token has not expired yet
if (
token.accessTokenExpires &&
Date.now() < Number(token.accessTokenExpires)
) {
return token as ExtendedToken;
}
callbacks: {
//@ts-ignore
async jwt({
token,
user,
account,
}: {
token: JWT;
user: User;
account: Account;
}) {
// Initial sign in
//console.log("jwt", { token, user, account });
if (account && user) {
return {
accessToken: account.access_token,
refreshToken: account.refresh_token,
idToken: account.id_token,
accessTokenExpires: account.expires_at
? account.expires_at * 1000
: null,
user,
};
}

// Access token has expired, try to update it
return refreshAccessToken(token);
},
// @ts-ignore
async session({
session,
token,
}: {
session: Session;
token: ExtendedToken;
}) {
if (token) {
session.user = token.user;
//@ts-ignore
session.accessToken = token.accessToken;
//@ts-ignore
session.refreshToken = token.refreshToken;
//@ts-ignore
session.idToken = token.idToken;
//@ts-ignore
session.accessTokenExpires = token.accessTokenExpires;
//@ts-ignore
session.error = token.error;
}
// Return previous token if the access token has not expired yet
if (
token.accessTokenExpires &&
Date.now() < Number(token.accessTokenExpires)
) {
return token as ExtendedToken;
}

return session;
// Access token has expired, try to update it
return refreshAccessToken(token);
},
// @ts-ignore
async session({
session,
token,
}: {
session: Session;
token: ExtendedToken;
}) {
if (token) {
session.user = token.user;
//@ts-ignore
session.accessToken = token.accessToken;
//@ts-ignore
session.refreshToken = token.refreshToken;
//@ts-ignore
session.idToken = token.idToken;
//@ts-ignore
session.accessTokenExpires = token.accessTokenExpires;
//@ts-ignore
session.error = token.error;
}

return session;
},
},
},
});
});

}
65 changes: 65 additions & 0 deletions vault/VaultModule.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs = __importStar(require("fs"));
const vault = require("node-vault");
class VaultModule {
constructor(vaultRole) {
this.vaultClient = vault({
apiVersion: 'v1',
endpoint: "http://vault.vault-dev.svc:8200",
});
this.vaultRole = vaultRole;
this.isKubelogged = false;
}
async readSecret(path) {
const JWT_TOKEN_FILE = "/var/run/secrets/kubernetes.io/serviceaccount/token";
const jwt = fs.readFileSync(JWT_TOKEN_FILE);
if (!this.isKubelogged) {
try {
const result = await this.vaultClient.kubernetesLogin({
"role": this.vaultRole,
"jwt": jwt.toString()
});
this.vaultClient.token = result.auth.client_token;
}
catch (error) {
console.error('Error authenticating to vault instance:', error.message);
throw error;
}
this.isKubelogged = true;
}
try {
const { data } = await this.vaultClient.read(path);
const obj = Object.keys(data.data);
return data.data[obj[0]];
}
catch (error) {
console.error('Error reading secret:', error.message);
throw error;
}
}
}
exports.default = VaultModule;
48 changes: 48 additions & 0 deletions vault/VaultModule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import * as fs from 'fs';

const vault = require("node-vault");


class VaultModule {
private vaultClient: any;
private readonly vaultRole: string
private isKubelogged: boolean

constructor(vaultRole: string) {
this.vaultClient = vault({
apiVersion: 'v1',
endpoint: "http://vault.vault-dev.svc:8200",
});
this.vaultRole = vaultRole
this.isKubelogged = false
}

async readSecret(path: string): Promise<any> {
const JWT_TOKEN_FILE="/var/run/secrets/kubernetes.io/serviceaccount/token";
const jwt = fs.readFileSync(JWT_TOKEN_FILE);

if (!this.isKubelogged) {
try {
const result = await this.vaultClient.kubernetesLogin({
"role": this.vaultRole,
"jwt": jwt.toString()
});
this.vaultClient.token = result.auth.client_token;
} catch (error) {
console.error('Error authenticating to vault instance:', error.message);
throw error;
}
this.isKubelogged = true
}
try {
const res = await this.vaultClient.read(path);
let obj = Object.keys(res.data.data)
return res.data.data[obj[0]]
} catch (error) {
console.error('Error reading secret:', error.message);
throw error;
}
}
}

export default VaultModule;
19 changes: 19 additions & 0 deletions vault/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "vault-integrated",
"version": "1.0.0",
"description": "Vault integrated for template application",
"main": "app.js",
"scripts": {
"build": "tsc",
"start": "node index.ts"
},
"dependencies": {
"node-vault": "^0.10.2"
},
"devDependencies": {
"typescript": "5.1.6"
},
"engines": {
"node": "18.11.17"
}
}
16 changes: 16 additions & 0 deletions vault/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"compilerOptions": {
"target": "es2018",
"module": "commonjs",
"outDir": ".",
"rootDir": ".",
"strict": true,
"esModuleInterop": true
},
"include": [
"*.ts"
],
"exclude": [
"node_modules"
]
}

0 comments on commit 4e6742b

Please sign in to comment.