-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(h3-firebase-auth): init h3 firebase auth middleware (#4)
* fix(lint): unify rome check typescript * test: add h3 firebase test cases * feat(h3): init h3 firebase auth middleware * bump: release all * fix(auth): update typing of decoded firebase id token * chore: revert another packages to head * fix(h3-firebase-auth): update typo
- Loading branch information
1 parent
0889079
commit 6fd7877
Showing
13 changed files
with
1,327 additions
and
475 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,15 @@ | ||
{ | ||
"editor.formatOnSave": true, | ||
"editor.codeActionsOnSave": { | ||
"source.organizeImports.rome": true, | ||
"quickfix.rome": true | ||
}, | ||
"editor.rulers": [100], | ||
"editor.defaultFormatter": "rome.rome", | ||
"cSpell.words": [ | ||
"fiboup" | ||
] | ||
"edgelibs", | ||
"fiboup", | ||
"hono" | ||
], | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,22 +2,24 @@ | |
"name": "@fiboup/edgelibs", | ||
"version": "1.0.0", | ||
"private": true, | ||
"workspaces": [ | ||
"packages/**" | ||
], | ||
"workspaces": ["packages/**"], | ||
"scripts": { | ||
"build": "pnpm -r --parallel run build", | ||
"build:firebase-auth": "pnpm -r --filter=./packages/firebase-auth run build", | ||
"build:hono-firebase-auth": "pnpm -r --filter=./packages/hono-firebase-auth run build" | ||
"build:hono-firebase-auth": "pnpm -r --filter=./packages/hono-firebase-auth run build", | ||
"lint.format": "rome check --apply-unsafe packages/**/*.ts packages/**/**/*.ts", | ||
"lint.check": "rome check packages/**/*.ts packages/**/**/*.ts" | ||
}, | ||
"keywords": [], | ||
"author": "Hieu Tran <[email protected]>", | ||
"license": "MIT", | ||
"devDependencies": { | ||
"@changesets/cli": "^2.26.2", | ||
"eslint": "^8.39.0", | ||
"@types/supertest": "2.0.12", | ||
"rome": "12.1.3", | ||
"typescript": "^5.1.5", | ||
"unbuild": "^1.2.1" | ||
"typescript": "^5.1.6", | ||
"unbuild": "^1.2.1", | ||
"vitest": "0.34.1", | ||
"supertest": "6.3.3" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# @fiboup/h3-firebase-auth | ||
|
||
## 1.0.0 | ||
|
||
### Major Changes | ||
|
||
- Init h3 firebase auth middleware | ||
|
||
### Patch Changes | ||
|
||
- Updated dependencies | ||
- @fiboup/firebase-auth@1.1.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
# Firebase Authentication/Identity Platform integration for h3 | ||
|
||
This package allows easily integrate Firebase Authentication/Identity Platform to your [h3](https://github.com/unjs/h3) API project. | ||
|
||
## Features | ||
|
||
- h3 middleware to decode and verify JWT token issued by Firebase Authentication service | ||
- h3 context variable `user` for you to access any where in your application | ||
|
||
```ts | ||
const user = event.context.user // DecodedIdToken; | ||
``` | ||
|
||
- Allowed to custom `user` shape with `transformCurrentUser` | ||
|
||
|
||
## Install | ||
|
||
With NPM | ||
|
||
```bash | ||
npm install @fiboup/h3-firebase-auth | ||
``` | ||
|
||
With Yarn | ||
|
||
```bash | ||
yarn add @fiboup/h3-firebase-auth | ||
``` | ||
|
||
With pnpm | ||
|
||
```bash | ||
pnpm add @fiboup/h3-firebase-auth | ||
``` | ||
|
||
## Usage | ||
|
||
### Add authentication middleware to your h3 app | ||
|
||
```ts | ||
import { createApp } from "h3"; | ||
import { validateFirebaseAuth } from "@fiboup/h3-firebase-auth"; | ||
|
||
const app = new createApp(); | ||
|
||
app.use( | ||
"/", | ||
eventHandler({ | ||
onRequest: [ | ||
(event) => | ||
validateFirebaseAuth({ | ||
// Note: Go to your Firebase project, then visit Project settings for the project id*** | ||
projectId: "TEST", | ||
// If you ignore this field, default is `user` | ||
userContextKey: "currentUser", | ||
transformCurrentUser(user) { | ||
return { | ||
...user, | ||
nickname: user.email?.split("@")[0], | ||
}; | ||
}, | ||
})(event), | ||
], | ||
async handler(event) { | ||
const user = event.context.currentUser; | ||
return `Hello ${user.email}`; | ||
}, | ||
}), | ||
) | ||
``` | ||
|
||
To make your custom current user context type-safe, don't forget to write your custom h3 in H3EventContext | ||
on global typing of project, like `global.d.ts` | ||
|
||
|
||
```ts | ||
declare module "h3" { | ||
interface H3EventContext extends Record<string, any> { | ||
params?: Record<string, string>; | ||
/** | ||
* Matched router Node | ||
* | ||
* @experimental The object structure may change in non-major version. | ||
*/ | ||
matchedRoute?: RouteNode; | ||
sessions?: Record<string, Session>; | ||
clientAddress?: string; | ||
user?: DecodedIdToken; | ||
} | ||
} | ||
``` | ||
|
||
## License | ||
|
||
MIT © [Fiboup](https://github.com/fiboup) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { defineBuildConfig } from "unbuild"; | ||
|
||
export default defineBuildConfig({ | ||
entries: ["./src/index"], | ||
rollup: { | ||
emitCJS: true, | ||
}, | ||
declaration: true, | ||
clean: true, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
{ | ||
"name": "@fiboup/h3-firebase-auth", | ||
"author": "Harry Tran <[email protected]>", | ||
"license": "MIT", | ||
"version": "1.0.0", | ||
"description": "Firebase Authentication for H3", | ||
"type": "module", | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/fiboup/edgelibs.git", | ||
"directory": "packages/h3-firebase-auth" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/fiboup/edgelibs/issues" | ||
}, | ||
"exports": { | ||
".": { | ||
"types": "./dist/index.d.ts", | ||
"import": "./dist/index.mjs", | ||
"require": "./dist/index.cjs" | ||
} | ||
}, | ||
"main": "./dist/index.cjs", | ||
"types": "./dist/index.d.ts", | ||
"typesVersions": { | ||
"*": { | ||
"*": [ | ||
"*", | ||
"dist/*", | ||
"dist/*.d.ts", | ||
"dist/*/index.d.ts" | ||
] | ||
} | ||
}, | ||
"files": [ | ||
"dist" | ||
], | ||
"scripts": { | ||
"build": "unbuild", | ||
"test": "vitest" | ||
}, | ||
"devDependencies": { | ||
"h3": "^1.8.0" | ||
}, | ||
"peerDependencies": { | ||
"h3": "^1.8.0" | ||
}, | ||
"dependencies": { | ||
"@fiboup/firebase-auth": "workspace:*" | ||
}, | ||
"keywords": [ | ||
"firebase", | ||
"auth", | ||
"cloud identity", | ||
"identity platform", | ||
"CIAM", | ||
"h3" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export { JwtDecodeError } from "@fiboup/firebase-auth"; | ||
|
||
export * from "./middleware"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import type { DecodedIdToken } from "@fiboup/firebase-auth"; | ||
import { fetchGooglePublicKeys, verifyAndDecodeJwt } from "@fiboup/firebase-auth"; | ||
import { createError, defineRequestMiddleware, getHeader } from "h3"; | ||
|
||
const TOKEN_PREFIX = "Bearer "; | ||
const USER_CONTEXT_KEY = "user"; | ||
|
||
export type FirebaseAuthConfig = { | ||
projectId: string; | ||
transformCurrentUser?: (decodedToken: DecodedIdToken) => unknown; | ||
/** | ||
* If you leave not set this value, the default value is `user`. | ||
* @default user | ||
*/ | ||
userContextKey?: string; | ||
}; | ||
|
||
export type DefaultFirebaseAuthInjectedVariables = { | ||
currentUser?: DecodedIdToken; | ||
}; | ||
|
||
export const transformCurrentUser = (decodedToken: DecodedIdToken) => { | ||
return decodedToken; | ||
}; | ||
|
||
export const validateFirebaseAuth = (config: FirebaseAuthConfig) => { | ||
return defineRequestMiddleware(async (event) => { | ||
if (!config.projectId) { | ||
throw createError({ | ||
statusCode: 400, | ||
statusMessage: "Bad Request: Must provide projectId config", | ||
}); | ||
} | ||
|
||
const tokenHeader = getHeader(event, "Authorization") || ""; | ||
if (!tokenHeader) { | ||
throw createError({ statusCode: 401, statusMessage: "Authorization header is missing" }); | ||
} | ||
if (!tokenHeader.startsWith(TOKEN_PREFIX)) { | ||
throw createError({ | ||
statusCode: 401, | ||
statusMessage: `Authorization header must start with ${TOKEN_PREFIX}`, | ||
}); | ||
} | ||
|
||
const token = tokenHeader.substring(TOKEN_PREFIX.length); | ||
const googlePublicKeys = await fetchGooglePublicKeys(); | ||
const decodedToken = await verifyAndDecodeJwt(token, googlePublicKeys, config.projectId); | ||
const _transformCurrentUser = config?.transformCurrentUser || transformCurrentUser; | ||
const user = _transformCurrentUser(decodedToken); | ||
event.context[config.userContextKey ?? USER_CONTEXT_KEY] = user; | ||
}); | ||
}; | ||
|
||
export type { DecodedIdToken }; |
Oops, something went wrong.