Skip to content

Commit

Permalink
Merge pull request #1772 from navikt/validate_expiry
Browse files Browse the repository at this point in the history
401 for expired tokens i tokenx middleware
  • Loading branch information
kenglxn authored Jan 17, 2024
2 parents 01eddbc + 0d4318a commit 9154265
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 45 deletions.
28 changes: 22 additions & 6 deletions server/package-lock.json

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

1 change: 1 addition & 0 deletions server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"express-http-proxy": "1.6.3",
"http-proxy-middleware": "3.0.0-beta.1",
"http-terminator": "3.2.0",
"jose": "5.2.0",
"jsdom": "^16.4.0",
"mustache": "^4.2.0",
"openid-client": "5.5.0",
Expand Down
79 changes: 40 additions & 39 deletions server/tokenx.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import {Issuer, errors} from 'openid-client';
import { Issuer, errors } from 'openid-client';
import { decodeJwt } from 'jose';

const {
TOKEN_X_WELL_KNOWN_URL,
TOKEN_X_CLIENT_ID,
TOKEN_X_PRIVATE_JWK
} = process.env;
const { TOKEN_X_WELL_KNOWN_URL, TOKEN_X_CLIENT_ID, TOKEN_X_PRIVATE_JWK } = process.env;

const exchangeToken = async (tokenxClient, {subject_token, audience}) => {
const exchangeToken = async (tokenxClient, { subject_token, audience }) => {
return await tokenxClient.grant(
{
grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',
Expand All @@ -32,45 +29,49 @@ const createTokenXClient = async () => {
client_id: TOKEN_X_CLIENT_ID,
token_endpoint_auth_method: 'private_key_jwt',
},
{keys: [JSON.parse(TOKEN_X_PRIVATE_JWK)]}
{ keys: [JSON.parse(TOKEN_X_PRIVATE_JWK)] }
);
};

/**
* onProxyReq does not support async, so using middleware for tokenx instead
* ref: https://github.com/chimurai/http-proxy-middleware/issues/318
*/
export const tokenXMiddleware = (
{
audience,
tokenXClientPromise = audience ? createTokenXClient() : null,
log
}
) => async (req, res, next) => {
try {
if (!audience) {
next();
return;
}
export const tokenXMiddleware =
({ audience, tokenXClientPromise = audience ? createTokenXClient() : null, log }) =>
async (req, res, next) => {
try {
if (!audience) {
next();
return;
}

const subject_token = (req.headers.authorization || '').replace('Bearer', '').trim();
if (subject_token === '') {
log.info('no authorization header found, skipping tokenx.');
next();
return;
}

const { exp } = decodeJwt(subject_token);
if (!exp || exp * 1000 <= Date.now()) {
log.info('unauthorized request. subject_token is expired.');
res.status(401).send();
return;
}

const subject_token = (req.headers.authorization || '').replace('Bearer', '').trim();
if (subject_token === '') {
log.info("no authorization header found, skipping tokenx.")
const { access_token } = await exchangeToken(await tokenXClientPromise, {
subject_token,
audience,
});
req.headers.authorization = `Bearer ${access_token}`;
next();
return;
} catch (err) {
if (err instanceof errors.OPError) {
log.info(`token exchange feilet ${err.message}`, err);
res.status(401).send();
} else {
next(err);
}
}
const {access_token} = await exchangeToken(await tokenXClientPromise, {
subject_token,
audience
});
req.headers.authorization = `Bearer ${access_token}`;
next();
} catch (err) {
if (err instanceof errors.OPError) {
log.info(`token exchange feilet ${err.message}`, err);
res.status(401).send();
} else {
next(err);
}
}
};
};

0 comments on commit 9154265

Please sign in to comment.