Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dependabot/npm and yarn/openid client 6.1.3 #36

Merged
merged 11 commits into from
Nov 19, 2024
Merged
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
cache: "npm"
node-version-file: package.json
- run: npm ci
- name: Cypress run
uses: cypress-io/github-action@v6
Expand Down
117 changes: 65 additions & 52 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import "dotenv/config";
import express from "express";
import { Issuer } from "openid-client";
import * as client from "openid-client";
import session from "express-session";
import morgan from "morgan";
import * as crypto from "crypto";
import bodyParser from "body-parser";
import { chain, isObject } from "lodash-es";

const port = parseInt(process.env.PORT, 10) || 3000;
const origin = `${process.env.HOST}`;
const redirectUri = `${origin}${process.env.CALLBACK_URL}`;

const app = express();

app.set("view engine", "ejs");
Expand All @@ -20,33 +17,38 @@ app.use(
rolling: true,
}),
);
app.enable('trust proxy');
app.use(morgan("combined"));

const removeNullValues = (obj) => Object.entries(obj).reduce((a,[k,v]) => (v ? (a[k]=v, a) : a), {})

const getMcpClient = async () => {
const mcpIssuer = await Issuer.discover(process.env.PC_PROVIDER);

return new mcpIssuer.Client({
client_id: process.env.PC_CLIENT_ID,
client_secret: process.env.PC_CLIENT_SECRET,
redirect_uris: [redirectUri],
response_types: ["code"],
id_token_signed_response_alg: process.env.PC_ID_TOKEN_SIGNED_RESPONSE_ALG,
userinfo_signed_response_alg:
process.env.PC_USERINFO_SIGNED_RESPONSE_ALG || null,
});
const objToUrlParams = (obj) =>
new URLSearchParams(
chain(obj)
.omitBy((v) => !v)
.mapValues((o) => (isObject(o) ? JSON.stringify(o) : o))
.value(),
);

const getCurrentUrl = (req) =>
new URL(`${req.protocol}://${req.get("host")}${req.originalUrl}`);

const getProviderConfig = async () => {
return await client.discovery(
new URL(process.env.PC_PROVIDER),
process.env.PC_CLIENT_ID,
{
client_secret: process.env.PC_CLIENT_SECRET,
id_token_signed_response_alg: process.env.PC_ID_TOKEN_SIGNED_RESPONSE_ALG,
userinfo_signed_response_alg:
process.env.PC_USERINFO_SIGNED_RESPONSE_ALG || null,
},
);
};

const acr_values = process.env.ACR_VALUES
? process.env.ACR_VALUES.split(",")
: null;
const login_hint = process.env.LOGIN_HINT || null;
const scope = process.env.PC_SCOPES;
const AUTHORIZATION_DEFAULT_PARAMS = {
scope,
login_hint,
acr_values,
redirect_uri: `${process.env.HOST}${process.env.CALLBACK_URL}`,
scope: process.env.PC_SCOPES,
login_hint: process.env.LOGIN_HINT || null,
acr_values: process.env.ACR_VALUES ? process.env.ACR_VALUES.split(",") : null,
claims: {
id_token: {
amr: {
Expand Down Expand Up @@ -75,19 +77,22 @@ app.get("/", async (req, res, next) => {
const getAuthorizationControllerFactory = (extraParams) => {
return async (req, res, next) => {
try {
const client = await getMcpClient();
const nonce = crypto.randomBytes(16).toString("hex");
const state = crypto.randomBytes(16).toString("hex");
const config = await getProviderConfig();
const nonce = client.randomNonce();
const state = client.randomState();

req.session.state = state;
req.session.nonce = nonce;

const redirectUrl = client.authorizationUrl(removeNullValues({
nonce,
state,
...AUTHORIZATION_DEFAULT_PARAMS,
...extraParams,
}));
const redirectUrl = client.buildAuthorizationUrl(
config,
objToUrlParams({
nonce,
state,
...AUTHORIZATION_DEFAULT_PARAMS,
...extraParams,
}),
);

res.redirect(redirectUrl);
} catch (e) {
Expand Down Expand Up @@ -143,29 +148,35 @@ app.post(
"/custom-connection",
bodyParser.urlencoded({ extended: false }),
(req, res, next) => {
const customParams = JSON.parse(req.body['custom-params'])
const customParams = JSON.parse(req.body["custom-params"]);

return getAuthorizationControllerFactory(customParams)(req, res, next);
},
);

app.get(process.env.CALLBACK_URL, async (req, res, next) => {
try {
const client = await getMcpClient();
const params = client.callbackParams(req);
const tokenSet = await client.callback(redirectUri, params, {
nonce: req.session.nonce,
state: req.session.state,
const config = await getProviderConfig();
const currentUrl = getCurrentUrl(req);
const tokens = await client.authorizationCodeGrant(config, currentUrl, {
expectedNonce: req.session.nonce,
expectedState: req.session.state,
});

req.session.nonce = null;
req.session.state = null;
req.session.userinfo = await client.userinfo(tokenSet.access_token);
req.session.idtoken = tokenSet.claims();
req.session.id_token_hint = tokenSet.id_token;
req.session.oauth2token = tokenSet;
const claims = tokens.claims();
req.session.userinfo = await client.fetchUserInfo(
config,
tokens.access_token,
claims.sub,
);
req.session.idtoken = claims;
req.session.id_token_hint = tokens.id_token;
req.session.oauth2token = tokens;
res.redirect("/");
} catch (e) {
console.error(e)
next(e);
}
});
Expand All @@ -174,11 +185,14 @@ app.post("/logout", async (req, res, next) => {
try {
const id_token_hint = req.session.id_token_hint;
req.session.destroy();
const client = await getMcpClient();
const redirectUrl = client.endSessionUrl({
post_logout_redirect_uri: `${origin}/`,
id_token_hint,
});
const config = await getProviderConfig();
const redirectUrl = client.buildEndSessionUrl(
config,
objToUrlParams({
post_logout_redirect_uri: `${process.env.HOST}/`,
id_token_hint,
}),
);

res.redirect(redirectUrl);
} catch (e) {
Expand All @@ -188,5 +202,4 @@ app.post("/logout", async (req, res, next) => {

app.listen(port, () => {
console.log(`App listening on port ${port}`);
console.log(process.env);
});
109 changes: 37 additions & 72 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@
"ejs": "^3.1.10",
"express": "^4.21.1",
"express-session": "^1.18.1",
"lodash-es": "^4.17.21",
"morgan": "^1.10.0",
"openid-client": "^5.7.0"
"openid-client": "^6.1.3"
},
"devDependencies": {
"prettier": "^3.3.3"
Expand Down
Loading