Skip to content

Commit

Permalink
[api] extract verify callback for more explicit typing
Browse files Browse the repository at this point in the history
  • Loading branch information
freemvmt committed Sep 6, 2024
1 parent a918020 commit e599a44
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 33 deletions.
3 changes: 1 addition & 2 deletions api.planx.uk/modules/auth/passport.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Issuer } from "openid-client";
import type { Authenticator } from "passport";
import passport from "passport";
import passport, { type Authenticator } from "passport";

import { googleStrategy } from "./strategy/google.js";
import {
Expand Down
61 changes: 32 additions & 29 deletions api.planx.uk/modules/auth/strategy/microsoft-oidc.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import type { TokenSet, Client, ClientMetadata } from "openid-client";
import type {
Client,
ClientMetadata,
IdTokenClaims,
StrategyVerifyCallbackReq,
} from "openid-client";
import { Strategy } from "openid-client";
import { buildJWT } from "../service.js";

Expand Down Expand Up @@ -31,36 +36,34 @@ export const getMicrosoftOidcStrategy = (client: Client): Strategy<Client> => {
// need the request in the verify callback to validate the returned nonce
passReqToCallback: true,
},
async (req: any, tokenSet: TokenSet, done: any): Promise<void> => {
// TODO: use tokenSet.state to pass the redirectTo query param through the auth flow
const claims = tokenSet.claims();
const email = claims.email;
const returned_nonce = claims.nonce;

if (returned_nonce != req.session.nonce) {
return done(
new Error("Returned nonce does not match session nonce"),
null,
);
}
verifyCallback,
);
};

if (!email) {
return done(new Error("Unable to authenticate without email"), null);
}
const verifyCallback: StrategyVerifyCallbackReq<Express.User> = async (
req: Http.IncomingMessageWithSession,
tokenSet,
done,
): Promise<void> => {
// TODO: use tokenSet.state to pass the redirectTo query param through the auth flow
const claims: IdTokenClaims = tokenSet.claims();
const email = claims.email;
const returned_nonce = claims.nonce;

const jwt = await buildJWT(email);
if (returned_nonce != req.session?.nonce) {
return done(new Error("Returned nonce does not match session nonce"));
}
if (!email) {
return done(new Error("Unable to authenticate without email"));
}

if (!jwt) {
return done(
{
status: 404,
message: `User (${email}) not found. Do you need to log in to a different Microsoft Account?`,
} as any,
null,
);
}
const jwt = await buildJWT(email);
if (!jwt) {
return done({
status: 404,
message: `User (${email}) not found. Do you need to log in to a different Microsoft Account?`,
});
}

return done(null, { jwt });
},
);
return done(null, { jwt });
};
13 changes: 11 additions & 2 deletions api.planx.uk/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import bodyParser from "body-parser";
import cookieParser from "cookie-parser";
import cookieSession from "cookie-session";
import cors, { CorsOptions } from "cors";
import express, { ErrorRequestHandler } from "express";
import express from "express";
import type { ErrorRequestHandler, Request } from "express";
import "express-async-errors";
import pinoLogger from "express-pino-logger";
import helmet from "helmet";
import { Server } from "http";
import { Server, type IncomingMessage } from "http";
import "isomorphic-fetch";
import noir from "pino-noir";
import airbrake from "./airbrake.js";
Expand Down Expand Up @@ -196,4 +197,12 @@ declare global {
};
}
}

namespace Http {
interface IncomingMessageWithSession extends IncomingMessage {
session?: {
nonce: string;
};
}
}
}

0 comments on commit e599a44

Please sign in to comment.