JWKS Guard
JWKS Guard is a library that provides a way of validating JWKS.
Install the JWKS Guard
flowcore component add library/jwks-guardOr install the JWKS Guard manually
Create a lib/jwks-guard.ts file in your project’s lib folder, and add the following code:
import { ApiUnauthorizedException } from "@components/api-exceptions"import bearer from "@elysiajs/bearer"import Elysia from "elysia"import { type JWTPayload, createRemoteJWKSet, jwtVerify } from "jose"
export type AuthOptions = {  certificateUrl: string}
export type FlowcoreJWTPayload = JWTPayload & {  flowcore_user_id: string  email: string}
export type FlowcoreAuthenticatedUser = {  id: string  email: string}
/** * This method is used to create a JWKS guard. * @param {AuthOptions} options - The options for JWKS guard creation. * @returns The Elysia instance with the JWKS guard. * @throws {Error} - If the bearer token is invalid or the JWKS validation fails with a 401 error */export function createJwksGuard(options: AuthOptions) {  const jwks = createRemoteJWKSet(new URL(options.certificateUrl))
  const guardRoute = new Elysia()    .use(bearer())    .derive({ as: "scoped" }, async ({ bearer, set }): Promise<{ flowcoreUser: FlowcoreAuthenticatedUser }> => {      const token = bearer as string
      const { payload } = await jwtVerify<FlowcoreJWTPayload>(token, jwks, {}).catch(() => ({        payload: null,      }))
      if (!payload?.flowcore_user_id) {        throw new ApiUnauthorizedException()      }
      return {        flowcoreUser: {          id: payload.flowcore_user_id,          email: payload.email,        },      }    })
  return guardRoute}Usage
Add a guard to your Elysia app:
import env from "@/env"import { ApiUnauthorizedException } from "@/lib/api-exceptions"import { type FlowcoreAuthenticatedUser, createJwksGuard } from "@/lib/jwks-guard"import { RequestedAccessService } from "@/services/request-access" // Assuming you have a service for request accessimport Elysia from "elysia"
/** * Creates a JWKS guard using the provided certificate URL from the environment. * This guard is used to validate JWT tokens against a JWKS endpoint. */export const authenticatedFlowcoreUserGuard = createJwksGuard({ certificateUrl: env.JWKS_URL })
/** * An Elysia plugin that derives an authenticated Flowcore user from the context. * It checks if the user is a valid Flowcore user and creates a RequestedAccessService instance. * * @throws {ApiUnauthorizedException} If the user is not a valid Flowcore user. * @returns An object containing the flowcoreUser and requestAccessService. */export const authenticatedFlowcoreUser = new Elysia().derive({ as: "scoped" }, (context) => {  // biome-ignore lint/suspicious/noExplicitAny: <explanation>  const flowcoreUser = (context as any).flowcoreUser as unknown  if (!isFlowcoreUser(flowcoreUser)) {    throw new ApiUnauthorizedException()  }
  // Assuming you have a service for request access  const requestAccessService = new RequestedAccessService(flowcoreUser)
  return {    flowcoreUser,    requestAccessService,  }})
/** * Type guard function to check if a user object is a valid FlowcoreAuthenticatedUser. * * @param user - The user object to check. * @returns A boolean indicating whether the user is a valid FlowcoreAuthenticatedUser. */function isFlowcoreUser(user: unknown): user is FlowcoreAuthenticatedUser {  return typeof user === "object" && user !== null && "id" in user && typeof user.id === "string"}then add the guard to your Elysia app:
export default new Elysia({  prefix: "/api",  tags: ["api"],  detail: {    security: [{ bearerAuth: [], oauth2: [] }],  },})  .use(authenticatedFlowcoreUserGuard)then for your endpoints
export default new Elysia({  prefix: "/v1/data-cores",  tags: ["data-cores"],  detail: {    security: [{ bearerAuth: [], oauth2: [] }],  },})  .use(authenticatedFlowcoreUser)  .get("/", async () => {    return {      message: "Hello, world!",    }  }, {    beforeHandle: ({ flowcoreUser, RequestedAccessService, params}) =>      requestAccessService.onDataCore(FrnAction.Write, params.organizationId, params.dataCoreId ?? "*"),    params: t.Object({      organizationId: t.String(),      dataCoreId: t.Optional(t.String()),    }),  })