diff --git a/.changeset/heavy-bugs-perform.md b/.changeset/heavy-bugs-perform.md new file mode 100644 index 000000000..b8ec5d0a7 --- /dev/null +++ b/.changeset/heavy-bugs-perform.md @@ -0,0 +1,5 @@ +--- +'@hono/cloudflare-access': minor +--- + +Handle Access organization does not exist and Access not available cases diff --git a/packages/cloudflare-access/src/index.test.ts b/packages/cloudflare-access/src/index.test.ts index 851e6adc7..353b68181 100644 --- a/packages/cloudflare-access/src/index.test.ts +++ b/packages/cloudflare-access/src/index.test.ts @@ -116,14 +116,17 @@ describe('Cloudflare Access middleware', async () => { const keyPair2 = await generateJWTKeyPair(); const keyPair3 = await generateJWTKeyPair(); - vi.stubGlobal('fetch', async () => { - return Response.json({ - keys: [ - publicKeyToJWK(keyPair1.publicKey), - publicKeyToJWK(keyPair2.publicKey), - ], + beforeEach(() => { + vi.clearAllMocks(); + vi.stubGlobal('fetch', async () => { + return Response.json({ + keys: [ + publicKeyToJWK(keyPair1.publicKey), + publicKeyToJWK(keyPair2.publicKey), + ], + }) }) - }) + }); const app = new Hono() @@ -131,6 +134,12 @@ describe('Cloudflare Access middleware', async () => { app.get('/hello-behind-access', (c) => c.text('foo')) app.get('/access-payload', (c) => c.json(c.get('accessPayload'))) + app.onError((err, c) => { + return c.json({ + err: err.toString(), + }, 500) + }) + it('Should be throw Missing bearer token when nothing is sent', async () => { const res = await app.request('http://localhost/hello-behind-access') expect(res).not.toBeNull() @@ -248,4 +257,38 @@ describe('Cloudflare Access middleware', async () => { "exp":expect.any(Number) }) }) + + it('Should throw an error, if the access organization does not exist', async () => { + vi.stubGlobal('fetch', async () => { + return Response.json({success: false}, {status: 404}) + }) + + const res = await app.request('http://localhost/hello-behind-access', { + headers: { + 'cf-access-jwt-assertion': 'asdads' + } + }) + expect(res).not.toBeNull() + expect(res.status).toBe(500) + expect(await res.json()).toEqual({ + "err":"Error: @hono/cloudflare-access: The Access Organization 'my-cool-team-name' does not exist!" + }) + }) + + it('Should throw an error, if the access certs url is unavailable', async () => { + vi.stubGlobal('fetch', async () => { + return Response.json({success: false}, {status: 500}) + }) + + const res = await app.request('http://localhost/hello-behind-access', { + headers: { + 'cf-access-jwt-assertion': 'asdads' + } + }) + expect(res).not.toBeNull() + expect(res.status).toBe(500) + expect(await res.json()).toEqual({ + "err":"Error: @hono/cloudflare-access: Received unexpected HTTP code 500 from Cloudflare Access!" + }) + }) }) diff --git a/packages/cloudflare-access/src/index.ts b/packages/cloudflare-access/src/index.ts index cd69ff3ce..5b01e1c82 100644 --- a/packages/cloudflare-access/src/index.ts +++ b/packages/cloudflare-access/src/index.ts @@ -89,6 +89,14 @@ async function getPublicKeys(accessTeamName: string) { }, }) + if (!result.ok) { + if (result.status === 404) { + throw new Error(`@hono/cloudflare-access: The Access Organization '${accessTeamName}' does not exist!`) + } + + throw new Error(`@hono/cloudflare-access: Received unexpected HTTP code ${result.status} from Cloudflare Access!`) + } + const data: any = await result.json() // Because we keep CryptoKey's in memory between requests, we need to make sure they are refreshed once in a while