Merge pull request #8 from honojs/fix/support-service-worker-syntax

pull/34/head
Kei Kamikawa 2022-07-30 20:24:31 +09:00 committed by GitHub
commit 4cb4e8d957
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 234 additions and 144 deletions

View File

@ -6,6 +6,8 @@ Currently only Cloudflare Workers are supported officially. However, it may work
## Synopsis ## Synopsis
### Module Worker Syntax (recommend)
```ts ```ts
import { Hono } from "hono"; import { Hono } from "hono";
import { VerifyFirebaseAuthConfig, VerifyFirebaseAuthEnv, verifyFirebaseAuth, getFirebaseToken } from "@honojs/firebase-auth"; import { VerifyFirebaseAuthConfig, VerifyFirebaseAuthEnv, verifyFirebaseAuth, getFirebaseToken } from "@honojs/firebase-auth";
@ -28,6 +30,37 @@ app.get("/hello", (c) => {
export default app export default app
``` ```
### Service Worker Syntax
```ts
import { Hono } from "hono";
import { VerifyFirebaseAuthConfig, verifyFirebaseAuth, getFirebaseToken } from "@honojs/firebase-auth";
const config: VerifyFirebaseAuthConfig = {
// specify your firebase project ID.
projectId: "your-project-id",
// this is optional. but required in this mode.
keyStore: WorkersKVStoreSingle.getOrInitialize(
PUBLIC_JWK_CACHE_KEY,
PUBLIC_JWK_CACHE_KV
),
// this is also optional. But in this mode, you can only specify here.
firebaseEmulatorHost: FIREBASE_AUTH_EMULATOR_HOST,
}
const app = new Hono()
// set middleware
app.use("*", verifyFirebaseAuth(config));
app.get("/hello", (c) => {
const idToken = getFirebaseToken(c) // get id-token object.
return c.json(idToken)
});
app.fire()
```
## Config (`VerifyFirebaseAuthConfig`) ## Config (`VerifyFirebaseAuthConfig`)
### `projectId: string` (**required**) ### `projectId: string` (**required**)
@ -54,6 +87,12 @@ If you don't specify the field, this library uses [WorkersKVStoreSingle](https:/
Throws an exception if JWT validation fails. By default, this is output to the error log, but if you don't expect it, use this. Throws an exception if JWT validation fails. By default, this is output to the error log, but if you don't expect it, use this.
### `firebaseEmulatorHost?: string` (optional)
You can specify a host for the Firebase Auth emulator. This config is mainly used when **Service Worker Syntax** is used.
If not specified, check the [`FIREBASE_AUTH_EMULATOR_HOST` environment variable obtained from the request](https://github.com/Code-Hex/firebase-auth-cloudflare-workers#emulatorenv).
## Author ## Author
codehex <https://github.com/Code-Hex> codehex <https://github.com/Code-Hex>

View File

@ -18,6 +18,7 @@ export interface VerifyFirebaseAuthConfig {
keyStore?: KeyStorer; keyStore?: KeyStorer;
keyStoreInitializer?: (c: Context) => KeyStorer; keyStoreInitializer?: (c: Context) => KeyStorer;
disableErrorLog?: boolean; disableErrorLog?: boolean;
firebaseEmulatorHost?: string;
} }
const defaultKVStoreJWKCacheKey = "verify-firebase-auth-cached-public-key"; const defaultKVStoreJWKCacheKey = "verify-firebase-auth-cached-public-key";
@ -30,7 +31,7 @@ const defaultKeyStoreInitializer = (c: Context): KeyStorer => {
export const verifyFirebaseAuth = ( export const verifyFirebaseAuth = (
userConfig: VerifyFirebaseAuthConfig userConfig: VerifyFirebaseAuthConfig
): Handler<string, VerifyFirebaseAuthEnv> => { ): Handler => {
const config = { const config = {
projectId: userConfig.projectId, projectId: userConfig.projectId,
AuthorizationHeaderKey: AuthorizationHeaderKey:
@ -39,6 +40,7 @@ export const verifyFirebaseAuth = (
keyStoreInitializer: keyStoreInitializer:
userConfig.keyStoreInitializer ?? defaultKeyStoreInitializer, userConfig.keyStoreInitializer ?? defaultKeyStoreInitializer,
disableErrorLog: userConfig.disableErrorLog, disableErrorLog: userConfig.disableErrorLog,
firebaseEmulatorHost: userConfig.firebaseEmulatorHost,
}; };
return async (c, next) => { return async (c, next) => {
@ -55,7 +57,10 @@ export const verifyFirebaseAuth = (
); );
try { try {
const idToken = await auth.verifyIdToken(jwt, c.env); const idToken = await auth.verifyIdToken(jwt, {
FIREBASE_AUTH_EMULATOR_HOST:
config.firebaseEmulatorHost ?? c.env.FIREBASE_AUTH_EMULATOR_HOST,
});
setFirebaseToken(c, idToken); setFirebaseToken(c, idToken);
} catch (err) { } catch (err) {
if (!userConfig.disableErrorLog) { if (!userConfig.disableErrorLog) {

View File

@ -1,4 +1,8 @@
import { Auth, KeyStorer } from "firebase-auth-cloudflare-workers"; import {
Auth,
KeyStorer,
WorkersKVStoreSingle,
} from "firebase-auth-cloudflare-workers";
import { Hono } from "hono"; import { Hono } from "hono";
import { import {
VerifyFirebaseAuthEnv, VerifyFirebaseAuthEnv,
@ -26,6 +30,47 @@ describe("verifyFirebaseAuth middleware", () => {
await sleep(1000); // wait for iat await sleep(1000); // wait for iat
}); });
describe("service worker syntax", () => {
test("valid case, should be 200", async () => {
const app = new Hono();
resetAuth();
// This is assumed to be obtained from an environment variable.
const PUBLIC_JWK_CACHE_KEY = "testing-cache-key";
app.use(
"*",
verifyFirebaseAuth({
projectId: validProjectId,
keyStore: WorkersKVStoreSingle.getOrInitialize(
PUBLIC_JWK_CACHE_KEY,
PUBLIC_JWK_CACHE_KV
),
disableErrorLog: true,
firebaseEmulatorHost: emulatorHost,
})
);
app.get("/hello", (c) => c.json(getFirebaseToken(c)));
const req = new Request("http://localhost/hello", {
headers: {
Authorization: `Bearer ${user.idToken}`,
},
});
const res = await app.request(req);
expect(res).not.toBeNull();
expect(res.status).toBe(200);
const json = await res.json<{ aud: string; email: string }>();
expect(json.aud).toBe(validProjectId);
expect(json.email).toBe("codehex@hono.js");
});
});
describe("module worker syntax", () => {
test.each([ test.each([
[ [
"valid case, should be 200", "valid case, should be 200",
@ -186,7 +231,8 @@ describe("verifyFirebaseAuth middleware", () => {
const json = await res.json<{ aud: string; email: string }>(); const json = await res.json<{ aud: string; email: string }>();
expect(json.aud).toBe(validProjectId); expect(json.aud).toBe(validProjectId);
expect(json.email).toBe("codehex@example.com"); expect(json.email).toBe("codehex@hono.js");
});
}); });
}); });
@ -220,11 +266,11 @@ const generateDummyJWT = () => {
sub: "t1aLdTkAs0S0J0P6TNbjwbmry5B3", sub: "t1aLdTkAs0S0J0P6TNbjwbmry5B3",
iat: now - 1000, iat: now - 1000,
exp: now + 3000, // + 3s exp: now + 3000, // + 3s
email: "codehex@example.com", email: "codehex@hono.js",
email_verified: false, email_verified: false,
firebase: { firebase: {
identities: { identities: {
email: ["codehex@example.com"], email: ["codehex@hono.js"],
}, },
sign_in_provider: "password", sign_in_provider: "password",
}, },