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

Remove as JWTPayload #179

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

Nydauron
Copy link
Contributor

Adds static type checking to res.local.payload if strongJwtVerification() or weakJwtVerification() is called, removing the need for as JWTPayload to ever be used. If res.locals.payload is accessed without calling one of the two middleware factories, then the type of res.locals.payload will be unknown.

router.get("/my-new-route-with-authorization/", strongJwtVerification(), async (_, res) => {
    const payload = res.locals.payload;
    //      ^?      JWTPayload
});

router.get("/my-new-route-with-authorization/", weakJwtVerification(), async (_, res) => {
    const payload = res.locals.payload;
    //      ^?      JWTPayload | undefined
});

router.get("/my-new-public-route/", async (_, res) => {
    const payload = res.locals.payload;
    //      ^?      unknown
});

I also went ahead and added doc comments to both strongJwtVerification() and weakJwtVerification() as both were not really clear as to what they do and what sets them apart.

Some things to note

  • Strongly typing all of the Express handlers causes no propagation across functions, which breaks this feature. It is best to let TypeScript use its type inferencing. Otherwise you would need to append additional generic hints to all the arguments:
router.get("/my-new-route/", strongJwtVerification(), async (_
: Request, res: Response) => {
    const payload = res.locals.payload;
    //      ^?      unknown
});
  • If strongJwtVerification() or weakJwtVerification() is called, TypeScript will infer that all references to res.locals.payload are of type JWTPayload. If a handler function is run before strongJwtVerification() or weakJwtVerification() that reads res.locals.payload, it will lead to UB. Note that this isn't any better than mindlessly casting res.locals.payload to JWTPayload (what is currently being done on main).
router.get(
    "/my-new-route/",
    async (_, res) => {
        const payload = res.locals.payload;
        //      ^?      JWTPayload
        console.log(payload.id); // This will be UB
    },
    strongJwtVerification(),
);

I'm not sure if there is a way to give the next handler function a new context object in Express since the context locals is baked into res, and req and res are all mutably shared across all handlers, so I don't know if splitting contexts is a limitation of Express. I'm not too familiar with other frameworks, but for example, TRPC can modify context between handlers and middleware, allowing types to be hardened in future handlers (see first example: ctx.user is of type User | undefined and if the middleware succeeds, the new type of ctx.user that is passed to future is of type User): https://trpc.io/docs/server/middlewares

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant