Skip to content

Commit 9bcb72f

Browse files
feat(auth): introduce new verification mechanism
1 parent 4941c33 commit 9bcb72f

File tree

4 files changed

+333
-26
lines changed

4 files changed

+333
-26
lines changed

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,14 @@
3333
"fastify": "^5.3.2",
3434
"fastify-cli": "^7.3.0",
3535
"fastify-plugin": "^5.0.1",
36+
"jsonwebtoken": "^9.0.2",
37+
"jwks-rsa": "^3.2.0",
3638
"openid-client": "^6.1.7"
3739
},
3840
"devDependencies": {
3941
"@eslint/js": "^9.19.0",
4042
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
43+
"@types/jsonwebtoken": "^9",
4144
"@types/node": "^22.12.0",
4245
"c8": "^10.1.3",
4346
"concurrently": "^9.1.2",

src/plugins/auth.ts

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import { UnionOneOf } from "../utils/typebox/union-oneof.js";
33
import { Type } from "@sinclair/typebox";
44
import { FastifyReply, FastifyRequest } from "fastify";
55
import fp from "fastify-plugin";
6-
import { skipSubjectCheck } from "oauth4webapi";
6+
import jwt, { JwtHeader, SigningKeyCallback } from "jsonwebtoken";
7+
import { JwksClient } from "jwks-rsa";
78
import * as client from "openid-client";
8-
import { WWWAuthenticateChallengeError } from "openid-client";
99

1010
export interface AuthPluginOptions {
1111
/** The discovery URL of the OpenID Connect provider. */
@@ -66,29 +66,37 @@ export default fp<AuthPluginOptions>(async (fastify, opts) => {
6666
fastify.log.warn("Skip Auth: ON");
6767
}
6868

69-
const config = await (async () => {
69+
const key = await (async () => {
7070
if (skip) {
7171
return null;
7272
} else {
73-
return await client.discovery(
73+
const config = await client.discovery(
7474
new URL(opts.authDiscoveryURL),
7575
opts.authClientID,
7676
);
77+
fastify.log.info(
78+
{ opts, metadata: config?.serverMetadata() },
79+
"Successfully discovered the OpenID Connect provider.",
80+
);
81+
82+
const jwksClient = new JwksClient({
83+
jwksUri: config.serverMetadata().jwks_uri ?? "",
84+
});
85+
return async (header: JwtHeader, callback: SigningKeyCallback) => {
86+
jwksClient.getSigningKey(header.kid, (err, key) => {
87+
const signingKey = key?.getPublicKey();
88+
callback(err, signingKey);
89+
});
90+
};
7791
}
7892
})();
7993

80-
fastify.log.info(
81-
{ opts, metadata: config?.serverMetadata() },
82-
"Successfully discovered the OpenID Connect provider.",
83-
);
84-
8594
fastify.decorateRequest("user", undefined);
8695
fastify.decorate(
8796
"auth",
8897
async function (request: FastifyRequest, reply: FastifyReply) {
89-
if (skip || !config) {
90-
return;
91-
}
98+
if (skip) return;
99+
if (!key) return;
92100

93101
// Extract the authorization header from the request
94102
const { authorization } = request.headers;
@@ -106,23 +114,24 @@ export default fp<AuthPluginOptions>(async (fastify, opts) => {
106114
return reply.status(400).send("Invalid Authorization Scheme");
107115
}
108116

109-
// Verify the token with the client
110117
try {
111-
const info = await client.fetchUserInfo(
112-
config,
113-
token,
114-
skipSubjectCheck,
115-
);
118+
const info = await new Promise<jwt.JwtPayload>((resolve, reject) => {
119+
jwt.verify(token, key, (err, info) => {
120+
if (err) {
121+
return reject(err);
122+
}
123+
resolve(info as jwt.JwtPayload);
124+
});
125+
});
116126
request.user = info.email && getUsernameFromEmail(info.email);
117127
} catch (e) {
128+
console.log(e);
118129
if (
119-
e instanceof WWWAuthenticateChallengeError &&
120-
e.response?.status === 401
130+
e instanceof jwt.JsonWebTokenError ||
131+
e instanceof jwt.TokenExpiredError ||
132+
e instanceof jwt.NotBeforeError
121133
) {
122-
return reply
123-
.status(401)
124-
.type("application/json")
125-
.send(await e.response.json());
134+
return reply.status(401).send(`${e.name}: ${e.message}`);
126135
}
127136
throw e;
128137
}

src/routes/auth-example/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const authExample: FastifyPluginAsync = async (
2626
preHandler: fastify.auth,
2727
},
2828
async function (request, reply) {
29-
return "this is an auth example";
29+
return `${request.user} is authenticated`;
3030
},
3131
);
3232

0 commit comments

Comments
 (0)