diff --git a/packages/auth0-fastify-api/src/index.spec.ts b/packages/auth0-fastify-api/src/index.spec.ts index 25d0fd3..1c6f42c 100644 --- a/packages/auth0-fastify-api/src/index.spec.ts +++ b/packages/auth0-fastify-api/src/index.spec.ts @@ -53,7 +53,7 @@ afterEach(() => { server.resetHandlers(); }); -test('should return 400 when no token', async () => { +test('should return 401 when no authorization header', async () => { const fastify = Fastify(); fastify.register(fastifyAuth0Api, { domain: domain, @@ -77,9 +77,43 @@ test('should return 400 when no token', async () => { url: '/test', }); - expect(res.statusCode).toBe(400); + expect(res.statusCode).toBe(401); expect(res.json().error).toBe('invalid_request'); expect(res.json().error_description).toBe('No Authorization provided'); + expect(res.headers['www-authenticate']).toBe('Bearer'); +}); + +test('should return 400 when invalid authorization header', async () => { + const fastify = Fastify(); + fastify.register(fastifyAuth0Api, { + domain: domain, + audience: '', + }); + + fastify.register(() => { + fastify.get( + '/test', + { + preHandler: fastify.requireAuth(), + }, + async () => { + return 'OK'; + } + ); + }); + + const res = await fastify.inject({ + method: 'GET', + url: '/test', + headers: { + authorization: 'Bearer' + } + }); + + expect(res.statusCode).toBe(400); + expect(res.json().error).toBe('invalid_request'); + expect(res.json().error_description).toBe('Invalid Authorization provided'); + expect(res.headers['www-authenticate']).toBe('Bearer error="invalid_request", error_description="Invalid Authorization provided"'); }); test('should return 200 when valid token', async () => { diff --git a/packages/auth0-fastify-api/src/index.ts b/packages/auth0-fastify-api/src/index.ts index 3ef7ea5..310a768 100644 --- a/packages/auth0-fastify-api/src/index.ts +++ b/packages/auth0-fastify-api/src/index.ts @@ -65,25 +65,41 @@ async function auth0FastifApi(fastify: FastifyInstance, options: Auth0FastifyApi customFetch: options.customFetch, }); - const replyWithError = (reply: FastifyReply, statusCode: number, error: string, errorDescription: string) => { - return reply - .code(statusCode) - .header( - 'WWW-Authenticate', - `Bearer error="${error.replaceAll('"', '\\"')}", error_description="${errorDescription.replaceAll('"', '\\"')}"` - ) - .send({ - error: error, - error_description: errorDescription, - }); + const replyWithError = ( + reply: FastifyReply, + statusCode: number, + error: string, + errorDescription: string, + ommitHeaderDetails = false + ) => { + const headerValue = ommitHeaderDetails + ? `Bearer` + : `Bearer error="${error.replaceAll('"', '\\"')}", error_description="${errorDescription.replaceAll( + '"', + '\\"' + )}"`; + + return reply.code(statusCode).header('WWW-Authenticate', headerValue).send({ + error: error, + error_description: errorDescription, + }); }; fastify.decorate('requireAuth', function (opts: AuthRouteOptions = {}) { return async function (request: FastifyRequest, reply: FastifyReply) { + const authorizationHeader = request.headers.authorization; + + if (!authorizationHeader) { + // If there is no authorization header, + // we need to return a 401 with just the supported scheme and no error/error_description in www-authenticate. + return replyWithError(reply, 401, 'invalid_request', 'No Authorization provided', true); + } + const accessToken = getToken(request); if (!accessToken) { - return replyWithError(reply, 400, 'invalid_request', 'No Authorization provided'); + // If the authorization header was malformed, we need to return a 400. + return replyWithError(reply, 400, 'invalid_request', 'Invalid Authorization provided'); } try { @@ -110,7 +126,6 @@ async function auth0FastifApi(fastify: FastifyInstance, options: Auth0FastifyApi }); } - export default fp(auth0FastifApi); function getToken(request: FastifyRequest): string | undefined {