@kamod-ch/otok-oauth 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +163 -0
- package/dist/adapter/index.d.ts +2 -0
- package/dist/adapter/index.d.ts.map +1 -0
- package/dist/adapter/index.js +2 -0
- package/dist/adapter/index.js.map +1 -0
- package/dist/adapter/types.d.ts +30 -0
- package/dist/adapter/types.d.ts.map +1 -0
- package/dist/adapter/types.js +2 -0
- package/dist/adapter/types.js.map +1 -0
- package/dist/errors.d.ts +6 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +9 -0
- package/dist/errors.js.map +1 -0
- package/dist/flow.d.ts +28 -0
- package/dist/flow.d.ts.map +1 -0
- package/dist/flow.js +238 -0
- package/dist/flow.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.d.ts +21 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +60 -0
- package/dist/plugin.js.map +1 -0
- package/dist/profile/github.d.ts +3 -0
- package/dist/profile/github.d.ts.map +1 -0
- package/dist/profile/github.js +45 -0
- package/dist/profile/github.js.map +1 -0
- package/dist/profile/gitlab.d.ts +3 -0
- package/dist/profile/gitlab.d.ts.map +1 -0
- package/dist/profile/gitlab.js +25 -0
- package/dist/profile/gitlab.js.map +1 -0
- package/dist/profile/google.d.ts +3 -0
- package/dist/profile/google.d.ts.map +1 -0
- package/dist/profile/google.js +24 -0
- package/dist/profile/google.js.map +1 -0
- package/dist/profile/microsoft.d.ts +3 -0
- package/dist/profile/microsoft.d.ts.map +1 -0
- package/dist/profile/microsoft.js +26 -0
- package/dist/profile/microsoft.js.map +1 -0
- package/dist/providers/github.d.ts +7 -0
- package/dist/providers/github.d.ts.map +1 -0
- package/dist/providers/github.js +10 -0
- package/dist/providers/github.js.map +1 -0
- package/dist/providers/gitlab.d.ts +11 -0
- package/dist/providers/gitlab.d.ts.map +1 -0
- package/dist/providers/gitlab.js +9 -0
- package/dist/providers/gitlab.js.map +1 -0
- package/dist/providers/google.d.ts +7 -0
- package/dist/providers/google.d.ts.map +1 -0
- package/dist/providers/google.js +10 -0
- package/dist/providers/google.js.map +1 -0
- package/dist/providers/microsoft.d.ts +11 -0
- package/dist/providers/microsoft.d.ts.map +1 -0
- package/dist/providers/microsoft.js +9 -0
- package/dist/providers/microsoft.js.map +1 -0
- package/dist/providers/types.d.ts +9 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +3 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/redirect.d.ts +3 -0
- package/dist/redirect.d.ts.map +1 -0
- package/dist/redirect.js +6 -0
- package/dist/redirect.js.map +1 -0
- package/dist/state.d.ts +22 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +73 -0
- package/dist/state.js.map +1 -0
- package/package.json +88 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kamod
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# @kamod-ch/otok-oauth
|
|
2
|
+
|
|
3
|
+
OAuth login helpers (GitHub, Google) for [Otok](https://github.com/kamod-ch/otok) apps.
|
|
4
|
+
|
|
5
|
+
Ships as an **Otok plugin** (`oauth()`) and as **`createOAuthFlow`** for manual wiring. Sessions come from `@kamod-ch/otok-auth`.
|
|
6
|
+
|
|
7
|
+
See [MIGRATION.md](./MIGRATION.md) when upgrading from 1.0.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add @kamod-ch/otok-oauth @kamod-ch/otok-auth arctic hono @kamod-ch/otok
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Plugin (recommended)
|
|
16
|
+
|
|
17
|
+
Register **after** `auth()`:
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import auth from "@kamod-ch/otok-auth";
|
|
21
|
+
import oauth from "@kamod-ch/otok-oauth";
|
|
22
|
+
|
|
23
|
+
export default defineConfig({
|
|
24
|
+
plugins: [
|
|
25
|
+
auth({ /* … */ }),
|
|
26
|
+
oauth({
|
|
27
|
+
providers: {
|
|
28
|
+
github: {
|
|
29
|
+
clientId: env.GITHUB_CLIENT_ID,
|
|
30
|
+
clientSecret: env.GITHUB_CLIENT_SECRET,
|
|
31
|
+
redirectUri: `${env.APP_URL}/auth/github/callback`,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
adapter: oauthAdapter,
|
|
35
|
+
}),
|
|
36
|
+
],
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Composition (1.0 API, still supported)
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { Hono } from "hono";
|
|
44
|
+
import { createOAuthFlow } from "@kamod-ch/otok-oauth";
|
|
45
|
+
import type { OAuthAdapter } from "@kamod-ch/otok-oauth/adapter";
|
|
46
|
+
import { createSessionManager } from "@kamod-ch/otok-auth/session";
|
|
47
|
+
|
|
48
|
+
type User = { id: string; email: string | null };
|
|
49
|
+
|
|
50
|
+
const adapter: OAuthAdapter<User> = {
|
|
51
|
+
async findOrCreateUser(profile) {
|
|
52
|
+
// Look up by provider + providerAccountId, or create a local user.
|
|
53
|
+
return { id: "user_1", email: profile.email };
|
|
54
|
+
},
|
|
55
|
+
getUserId: (user) => user.id,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const sessions = createSessionManager<User>(
|
|
59
|
+
{
|
|
60
|
+
sessionCookie: "app_session",
|
|
61
|
+
csrfCookie: "app_csrf",
|
|
62
|
+
secure: () => process.env.NODE_ENV === "production",
|
|
63
|
+
},
|
|
64
|
+
/* your SessionAdapter */,
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
const oauth = createOAuthFlow({
|
|
68
|
+
secret: process.env.OAUTH_STATE_SECRET!,
|
|
69
|
+
adapter,
|
|
70
|
+
createSession: sessions.createSession,
|
|
71
|
+
providers: {
|
|
72
|
+
github: {
|
|
73
|
+
clientId: process.env.GITHUB_CLIENT_ID!,
|
|
74
|
+
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
|
|
75
|
+
redirectUri: process.env.GITHUB_REDIRECT_URI!,
|
|
76
|
+
},
|
|
77
|
+
google: {
|
|
78
|
+
clientId: process.env.GOOGLE_CLIENT_ID!,
|
|
79
|
+
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
|
|
80
|
+
redirectUri: process.env.GOOGLE_REDIRECT_URI!,
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// With createOtokApp({ configure }):
|
|
86
|
+
configure: (app) => {
|
|
87
|
+
oauth.mount(app);
|
|
88
|
+
};
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Registered routes (default `basePath: "/auth"`):
|
|
92
|
+
|
|
93
|
+
| Method | Path | Purpose |
|
|
94
|
+
|--------|------|---------|
|
|
95
|
+
| GET | `/auth/github` | Start GitHub login (`?next=/relative/path` optional) |
|
|
96
|
+
| GET | `/auth/github/callback` | GitHub callback |
|
|
97
|
+
| GET | `/auth/google` | Start Google login |
|
|
98
|
+
| GET | `/auth/google/callback` | Google callback |
|
|
99
|
+
|
|
100
|
+
On success the flow calls `adapter.findOrCreateUser`, then `createSession`, then redirects to a safe relative `next` path (or `/`).
|
|
101
|
+
|
|
102
|
+
On failure it redirects to `/login?error=<code>` (override with `loginPath` / `onError`).
|
|
103
|
+
|
|
104
|
+
## Login UI
|
|
105
|
+
|
|
106
|
+
Link to the authorize routes from your login page:
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
<a href="/auth/github?next=/studio">Continue with GitHub</a>
|
|
110
|
+
<a href="/auth/google?next=/studio">Continue with Google</a>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Error codes you may show from `?error=`:
|
|
114
|
+
|
|
115
|
+
- `invalid_state`
|
|
116
|
+
- `missing_code`
|
|
117
|
+
- `provider_error`
|
|
118
|
+
- `profile_error`
|
|
119
|
+
- `adapter_error`
|
|
120
|
+
- `provider_unavailable`
|
|
121
|
+
|
|
122
|
+
## Adapter
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
import type { OAuthAdapter, OAuthProfile } from "@kamod-ch/otok-oauth/adapter";
|
|
126
|
+
|
|
127
|
+
const adapter: OAuthAdapter<User> = {
|
|
128
|
+
async findOrCreateUser(profile: OAuthProfile) {
|
|
129
|
+
// profile.provider: "github" | "google"
|
|
130
|
+
// profile.providerAccountId, email, emailVerified, name, avatarUrl
|
|
131
|
+
},
|
|
132
|
+
getUserId: (user) => user.id,
|
|
133
|
+
};
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Exports
|
|
137
|
+
|
|
138
|
+
| Subpath | Purpose |
|
|
139
|
+
|---------|---------|
|
|
140
|
+
| `@kamod-ch/otok-oauth` | `createOAuthFlow`, errors, `OAuthProfile` |
|
|
141
|
+
| `@kamod-ch/otok-oauth/adapter` | `OAuthAdapter`, `OAuthProfile` |
|
|
142
|
+
| `@kamod-ch/otok-oauth/providers/github` | GitHub client helpers |
|
|
143
|
+
| `@kamod-ch/otok-oauth/providers/google` | Google client helpers |
|
|
144
|
+
| `@kamod-ch/otok-oauth/state` | Signed OAuth state cookie helpers |
|
|
145
|
+
|
|
146
|
+
## Env vars (app)
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
OAUTH_STATE_SECRET= # min. 32 random bytes
|
|
150
|
+
GITHUB_CLIENT_ID=
|
|
151
|
+
GITHUB_CLIENT_SECRET=
|
|
152
|
+
GITHUB_REDIRECT_URI= # e.g. http://localhost:3000/auth/github/callback
|
|
153
|
+
GOOGLE_CLIENT_ID=
|
|
154
|
+
GOOGLE_CLIENT_SECRET=
|
|
155
|
+
GOOGLE_REDIRECT_URI= # e.g. http://localhost:3000/auth/google/callback
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Design notes
|
|
159
|
+
|
|
160
|
+
- Uses [Arctic](https://arcticjs.dev) for provider clients (GitHub authorization code; Google with PKCE).
|
|
161
|
+
- State and PKCE verifier are stored in a short-lived signed httpOnly cookie.
|
|
162
|
+
- `?next=` is open-redirect safe (same-origin relative paths only).
|
|
163
|
+
- Account linking, refresh-token storage, and additional providers are out of scope for v1.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapter/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adapter/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export type OAuthProviderId = "github" | "google" | "microsoft" | "gitlab";
|
|
2
|
+
export type OAuthProfile = {
|
|
3
|
+
provider: OAuthProviderId;
|
|
4
|
+
providerAccountId: string;
|
|
5
|
+
email: string | null;
|
|
6
|
+
emailVerified: boolean;
|
|
7
|
+
name: string | null;
|
|
8
|
+
avatarUrl: string | null;
|
|
9
|
+
};
|
|
10
|
+
export interface OAuthAdapter<TUser> {
|
|
11
|
+
findOrCreateUser(profile: OAuthProfile): Promise<TUser>;
|
|
12
|
+
getUserId(user: TUser): string;
|
|
13
|
+
/**
|
|
14
|
+
* Link an OAuth account to an existing signed-in user.
|
|
15
|
+
* Must verify the current session before linking.
|
|
16
|
+
*/
|
|
17
|
+
linkAccount?(input: {
|
|
18
|
+
user: TUser;
|
|
19
|
+
profile: OAuthProfile;
|
|
20
|
+
}): Promise<TUser>;
|
|
21
|
+
}
|
|
22
|
+
export interface OAuthTokenSet {
|
|
23
|
+
accessToken: string;
|
|
24
|
+
refreshToken?: string | null;
|
|
25
|
+
expiresAt?: Date | null;
|
|
26
|
+
}
|
|
27
|
+
export interface OAuthTokenRefreshHandler {
|
|
28
|
+
refresh(provider: OAuthProviderId, refreshToken: string): Promise<OAuthTokenSet>;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/adapter/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE3E,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,eAAe,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,aAAa,EAAE,OAAO,CAAC;IACvB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,CAAC;AAEF,MAAM,WAAW,YAAY,CAAC,KAAK;IACjC,gBAAgB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IACxD,SAAS,CAAC,IAAI,EAAE,KAAK,GAAG,MAAM,CAAC;IAC/B;;;OAGG;IACH,WAAW,CAAC,CAAC,KAAK,EAAE;QAClB,IAAI,EAAE,KAAK,CAAC;QACZ,OAAO,EAAE,YAAY,CAAC;KACvB,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,CAAC,QAAQ,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CAClF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/adapter/types.ts"],"names":[],"mappings":""}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type OAuthErrorCode = "invalid_state" | "missing_code" | "provider_error" | "profile_error" | "adapter_error" | "provider_unavailable" | "pkce_error" | "link_verification_failed";
|
|
2
|
+
export declare class OAuthFlowError extends Error {
|
|
3
|
+
readonly code: OAuthErrorCode;
|
|
4
|
+
constructor(code: OAuthErrorCode, message?: string);
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GACtB,eAAe,GACf,cAAc,GACd,gBAAgB,GAChB,eAAe,GACf,eAAe,GACf,sBAAsB,GACtB,YAAY,GACZ,0BAA0B,CAAC;AAE/B,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;gBAElB,IAAI,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,MAAM;CAKnD"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAUA,MAAM,OAAO,cAAe,SAAQ,KAAK;IAC9B,IAAI,CAAiB;IAE9B,YAAY,IAAoB,EAAE,OAAgB;QAChD,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;QAC7B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF"}
|
package/dist/flow.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Context } from "hono";
|
|
2
|
+
import type { Hono } from "hono";
|
|
3
|
+
import type { OAuthAdapter, OAuthProviderId, OAuthTokenRefreshHandler } from "./adapter/types.js";
|
|
4
|
+
import { type OAuthErrorCode } from "./errors.js";
|
|
5
|
+
import type { OAuthProviderConfig } from "./providers/types.js";
|
|
6
|
+
export type OAuthFlowOptions<TUser> = {
|
|
7
|
+
secret: string;
|
|
8
|
+
adapter: OAuthAdapter<TUser>;
|
|
9
|
+
createSession: (c: Context, userId: string) => Promise<void>;
|
|
10
|
+
providers: Partial<Record<OAuthProviderId, OAuthProviderConfig>>;
|
|
11
|
+
basePath?: string;
|
|
12
|
+
stateCookie?: string;
|
|
13
|
+
secure?: boolean | ((c: Context) => boolean);
|
|
14
|
+
loginPath?: string;
|
|
15
|
+
redirectAllowlist?: readonly string[];
|
|
16
|
+
tokenRefresh?: OAuthTokenRefreshHandler;
|
|
17
|
+
/** Called after a successful login, before redirect. */
|
|
18
|
+
onSuccess?: (c: Context, user: TUser) => void | Promise<void>;
|
|
19
|
+
/** Override default error redirect. */
|
|
20
|
+
onError?: (c: Context, code: OAuthErrorCode) => Response | Promise<Response>;
|
|
21
|
+
};
|
|
22
|
+
export type OAuthFlow<TUser> = {
|
|
23
|
+
mount(app: Hono): void;
|
|
24
|
+
authorize(provider: OAuthProviderId): (c: Context) => Promise<Response>;
|
|
25
|
+
callback(provider: OAuthProviderId): (c: Context) => Promise<Response>;
|
|
26
|
+
};
|
|
27
|
+
export declare function createOAuthFlow<TUser>(options: OAuthFlowOptions<TUser>): OAuthFlow<TUser>;
|
|
28
|
+
//# sourceMappingURL=flow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow.d.ts","sourceRoot":"","sources":["../src/flow.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAGjC,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAClG,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAalE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAchE,MAAM,MAAM,gBAAgB,CAAC,KAAK,IAAI;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;IAC7B,aAAa,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,mBAAmB,CAAC,CAAC,CAAC;IACjE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,YAAY,CAAC,EAAE,wBAAwB,CAAC;IACxC,wDAAwD;IACxD,SAAS,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,uCAAuC;IACvC,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAC9E,CAAC;AAEF,MAAM,MAAM,SAAS,CAAC,KAAK,IAAI;IAC7B,KAAK,CAAC,GAAG,EAAE,IAAI,GAAG,IAAI,CAAC;IACvB,SAAS,CAAC,QAAQ,EAAE,eAAe,GAAG,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxE,QAAQ,CAAC,QAAQ,EAAE,eAAe,GAAG,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CACxE,CAAC;AA4BF,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,gBAAgB,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,CAoMzF"}
|
package/dist/flow.js
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { generateCodeVerifier, generateState } from "arctic";
|
|
2
|
+
import { deleteCookie, getCookie, setCookie } from "hono/cookie";
|
|
3
|
+
import { tryGetAuthRuntime } from "@kamod-ch/otok-auth/registry";
|
|
4
|
+
import { OAuthFlowError } from "./errors.js";
|
|
5
|
+
import { fetchGitHubProfile } from "./profile/github.js";
|
|
6
|
+
import { fetchGitLabProfile } from "./profile/gitlab.js";
|
|
7
|
+
import { fetchGoogleProfile } from "./profile/google.js";
|
|
8
|
+
import { fetchMicrosoftProfile } from "./profile/microsoft.js";
|
|
9
|
+
import { createGitHubClient, githubScopes } from "./providers/github.js";
|
|
10
|
+
import { createGitLabClient, gitlabScopes } from "./providers/gitlab.js";
|
|
11
|
+
import { createGoogleClient, googleScopes } from "./providers/google.js";
|
|
12
|
+
import { createMicrosoftClient, microsoftScopes, } from "./providers/microsoft.js";
|
|
13
|
+
import { safeNextPath } from "./redirect.js";
|
|
14
|
+
import { DEFAULT_MAX_AGE_MS, sealOAuthState, unsealOAuthState, } from "./state.js";
|
|
15
|
+
const DEFAULT_BASE_PATH = "/auth";
|
|
16
|
+
const DEFAULT_STATE_COOKIE = "otok_oauth_state";
|
|
17
|
+
const DEFAULT_LOGIN_PATH = "/login";
|
|
18
|
+
const STATE_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_MAX_AGE_MS / 1000);
|
|
19
|
+
function resolveSecure(c, secure) {
|
|
20
|
+
if (typeof secure === "function")
|
|
21
|
+
return secure(c);
|
|
22
|
+
if (typeof secure === "boolean")
|
|
23
|
+
return secure;
|
|
24
|
+
return process.env.NODE_ENV === "production";
|
|
25
|
+
}
|
|
26
|
+
function joinPath(base, ...parts) {
|
|
27
|
+
const normalizedBase = base.endsWith("/") ? base.slice(0, -1) : base || "";
|
|
28
|
+
const suffix = parts.map((part) => part.replace(/^\/+|\/+$/g, "")).filter(Boolean).join("/");
|
|
29
|
+
return `${normalizedBase}/${suffix}`.replace(/\/{2,}/g, "/");
|
|
30
|
+
}
|
|
31
|
+
function errorRedirect(loginPath, code) {
|
|
32
|
+
const url = new URL(loginPath, "http://localhost");
|
|
33
|
+
url.searchParams.set("error", code);
|
|
34
|
+
const location = `${url.pathname}${url.search}`;
|
|
35
|
+
return new Response(null, {
|
|
36
|
+
status: 303,
|
|
37
|
+
headers: { Location: location },
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function resolveAllowlist(options) {
|
|
41
|
+
return options.redirectAllowlist ?? tryGetAuthRuntime()?.redirectAllowlist ?? ["/"];
|
|
42
|
+
}
|
|
43
|
+
export function createOAuthFlow(options) {
|
|
44
|
+
if (!options.secret) {
|
|
45
|
+
throw new Error("createOAuthFlow requires a non-empty secret");
|
|
46
|
+
}
|
|
47
|
+
const basePath = options.basePath ?? DEFAULT_BASE_PATH;
|
|
48
|
+
const stateCookie = options.stateCookie ?? DEFAULT_STATE_COOKIE;
|
|
49
|
+
const loginPath = options.loginPath ?? DEFAULT_LOGIN_PATH;
|
|
50
|
+
const allowlist = resolveAllowlist(options);
|
|
51
|
+
async function fail(c, code) {
|
|
52
|
+
if (options.onError)
|
|
53
|
+
return options.onError(c, code);
|
|
54
|
+
return errorRedirect(loginPath, code);
|
|
55
|
+
}
|
|
56
|
+
function authorize(provider) {
|
|
57
|
+
return async (c) => {
|
|
58
|
+
const config = options.providers[provider];
|
|
59
|
+
if (!config)
|
|
60
|
+
return fail(c, "provider_unavailable");
|
|
61
|
+
const providerError = c.req.query("error");
|
|
62
|
+
if (providerError)
|
|
63
|
+
return fail(c, "provider_error");
|
|
64
|
+
try {
|
|
65
|
+
const state = generateState();
|
|
66
|
+
const next = safeNextPath(c.req.query("next"), allowlist);
|
|
67
|
+
const link = c.req.query("link") === "1";
|
|
68
|
+
let codeVerifier = null;
|
|
69
|
+
let authorizationURL;
|
|
70
|
+
if (provider === "github") {
|
|
71
|
+
const client = createGitHubClient(config);
|
|
72
|
+
authorizationURL = client.createAuthorizationURL(state, githubScopes(config));
|
|
73
|
+
}
|
|
74
|
+
else if (provider === "google") {
|
|
75
|
+
const client = createGoogleClient(config);
|
|
76
|
+
codeVerifier = generateCodeVerifier();
|
|
77
|
+
authorizationURL = client.createAuthorizationURL(state, codeVerifier, googleScopes(config));
|
|
78
|
+
}
|
|
79
|
+
else if (provider === "microsoft") {
|
|
80
|
+
const client = createMicrosoftClient(config);
|
|
81
|
+
codeVerifier = generateCodeVerifier();
|
|
82
|
+
authorizationURL = client.createAuthorizationURL(state, codeVerifier, microsoftScopes(config));
|
|
83
|
+
}
|
|
84
|
+
else if (provider === "gitlab") {
|
|
85
|
+
const client = createGitLabClient(config);
|
|
86
|
+
authorizationURL = client.createAuthorizationURL(state, gitlabScopes(config));
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
return fail(c, "provider_unavailable");
|
|
90
|
+
}
|
|
91
|
+
const payload = {
|
|
92
|
+
provider,
|
|
93
|
+
state,
|
|
94
|
+
codeVerifier,
|
|
95
|
+
next,
|
|
96
|
+
link,
|
|
97
|
+
issuedAt: Date.now(),
|
|
98
|
+
};
|
|
99
|
+
setCookie(c, stateCookie, sealOAuthState(payload, options.secret), {
|
|
100
|
+
httpOnly: true,
|
|
101
|
+
secure: resolveSecure(c, options.secure),
|
|
102
|
+
sameSite: "Lax",
|
|
103
|
+
path: "/",
|
|
104
|
+
maxAge: STATE_COOKIE_MAX_AGE_SECONDS,
|
|
105
|
+
});
|
|
106
|
+
return c.redirect(authorizationURL.toString(), 302);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return fail(c, "provider_error");
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function callback(provider) {
|
|
114
|
+
return async (c) => {
|
|
115
|
+
const config = options.providers[provider];
|
|
116
|
+
if (!config)
|
|
117
|
+
return fail(c, "provider_unavailable");
|
|
118
|
+
const providerError = c.req.query("error");
|
|
119
|
+
if (providerError)
|
|
120
|
+
return fail(c, "provider_error");
|
|
121
|
+
const code = c.req.query("code");
|
|
122
|
+
const returnedState = c.req.query("state");
|
|
123
|
+
if (!code)
|
|
124
|
+
return fail(c, "missing_code");
|
|
125
|
+
if (!returnedState)
|
|
126
|
+
return fail(c, "invalid_state");
|
|
127
|
+
const cookieValue = getCookie(c, stateCookie);
|
|
128
|
+
deleteCookie(c, stateCookie, { path: "/" });
|
|
129
|
+
if (!cookieValue)
|
|
130
|
+
return fail(c, "invalid_state");
|
|
131
|
+
const payload = unsealOAuthState(cookieValue, options.secret);
|
|
132
|
+
if (!payload || payload.provider !== provider || payload.state !== returnedState) {
|
|
133
|
+
return fail(c, "invalid_state");
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
let accessToken;
|
|
137
|
+
let refreshToken = null;
|
|
138
|
+
if (provider === "github") {
|
|
139
|
+
const client = createGitHubClient(config);
|
|
140
|
+
const tokens = await client.validateAuthorizationCode(code);
|
|
141
|
+
accessToken = tokens.accessToken();
|
|
142
|
+
refreshToken = tokens.hasRefreshToken() ? tokens.refreshToken() : null;
|
|
143
|
+
}
|
|
144
|
+
else if (provider === "google") {
|
|
145
|
+
if (!payload.codeVerifier)
|
|
146
|
+
return fail(c, "pkce_error");
|
|
147
|
+
const client = createGoogleClient(config);
|
|
148
|
+
const tokens = await client.validateAuthorizationCode(code, payload.codeVerifier);
|
|
149
|
+
accessToken = tokens.accessToken();
|
|
150
|
+
refreshToken = tokens.hasRefreshToken() ? tokens.refreshToken() : null;
|
|
151
|
+
}
|
|
152
|
+
else if (provider === "microsoft") {
|
|
153
|
+
if (!payload.codeVerifier)
|
|
154
|
+
return fail(c, "pkce_error");
|
|
155
|
+
const client = createMicrosoftClient(config);
|
|
156
|
+
const tokens = await client.validateAuthorizationCode(code, payload.codeVerifier);
|
|
157
|
+
accessToken = tokens.accessToken();
|
|
158
|
+
refreshToken = tokens.hasRefreshToken() ? tokens.refreshToken() : null;
|
|
159
|
+
}
|
|
160
|
+
else if (provider === "gitlab") {
|
|
161
|
+
const client = createGitLabClient(config);
|
|
162
|
+
const tokens = await client.validateAuthorizationCode(code);
|
|
163
|
+
accessToken = tokens.accessToken();
|
|
164
|
+
refreshToken = tokens.hasRefreshToken() ? tokens.refreshToken() : null;
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
return fail(c, "provider_unavailable");
|
|
168
|
+
}
|
|
169
|
+
if (refreshToken && options.tokenRefresh) {
|
|
170
|
+
await options.tokenRefresh.refresh(provider, refreshToken);
|
|
171
|
+
}
|
|
172
|
+
let profile;
|
|
173
|
+
try {
|
|
174
|
+
if (provider === "github") {
|
|
175
|
+
profile = await fetchGitHubProfile(accessToken);
|
|
176
|
+
}
|
|
177
|
+
else if (provider === "google") {
|
|
178
|
+
profile = await fetchGoogleProfile(accessToken);
|
|
179
|
+
}
|
|
180
|
+
else if (provider === "microsoft") {
|
|
181
|
+
profile = await fetchMicrosoftProfile(accessToken);
|
|
182
|
+
}
|
|
183
|
+
else if (provider === "gitlab") {
|
|
184
|
+
const baseURL = config.baseURL ?? "https://gitlab.com";
|
|
185
|
+
profile = await fetchGitLabProfile(accessToken, baseURL);
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
return fail(c, "provider_unavailable");
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
if (error instanceof OAuthFlowError)
|
|
193
|
+
return fail(c, error.code);
|
|
194
|
+
return fail(c, "profile_error");
|
|
195
|
+
}
|
|
196
|
+
let user;
|
|
197
|
+
try {
|
|
198
|
+
if (payload.link) {
|
|
199
|
+
const runtime = tryGetAuthRuntime();
|
|
200
|
+
const current = runtime ? await runtime.helpers.getSession(c) : null;
|
|
201
|
+
if (!current || !options.adapter.linkAccount) {
|
|
202
|
+
return fail(c, "link_verification_failed");
|
|
203
|
+
}
|
|
204
|
+
user = await options.adapter.linkAccount({ user: current, profile });
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
user = await options.adapter.findOrCreateUser(profile);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
return fail(c, "adapter_error");
|
|
212
|
+
}
|
|
213
|
+
const userId = options.adapter.getUserId(user);
|
|
214
|
+
if (!payload.link) {
|
|
215
|
+
await options.createSession(c, userId);
|
|
216
|
+
}
|
|
217
|
+
await options.onSuccess?.(c, user);
|
|
218
|
+
const destination = payload.next ?? "/";
|
|
219
|
+
return c.redirect(destination, 303);
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
if (error instanceof OAuthFlowError)
|
|
223
|
+
return fail(c, error.code);
|
|
224
|
+
return fail(c, "provider_error");
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
function mount(app) {
|
|
229
|
+
for (const provider of Object.keys(options.providers)) {
|
|
230
|
+
if (!options.providers[provider])
|
|
231
|
+
continue;
|
|
232
|
+
app.get(joinPath(basePath, provider), authorize(provider));
|
|
233
|
+
app.get(joinPath(basePath, provider, "callback"), callback(provider));
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return { mount, authorize, callback };
|
|
237
|
+
}
|
|
238
|
+
//# sourceMappingURL=flow.js.map
|
package/dist/flow.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow.js","sourceRoot":"","sources":["../src/flow.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { createOAuthFlow, type OAuthFlow, type OAuthFlowOptions } from "./flow.js";
|
|
2
|
+
export { OAuthFlowError, type OAuthErrorCode } from "./errors.js";
|
|
3
|
+
export type { OAuthAdapter, OAuthProfile, OAuthProviderId, OAuthTokenRefreshHandler, OAuthTokenSet, } from "./adapter/types.js";
|
|
4
|
+
export { safeNextPath } from "./redirect.js";
|
|
5
|
+
export { default } from "./plugin.js";
|
|
6
|
+
export type { OAuthPluginOptions } from "./plugin.js";
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,WAAW,CAAC;AACnF,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAClE,YAAY,EACV,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,wBAAwB,EACxB,aAAa,GACd,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAyC,MAAM,WAAW,CAAC;AACnF,OAAO,EAAE,cAAc,EAAuB,MAAM,aAAa,CAAC;AAQlE,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { OAuthAdapter } from "./adapter/types.js";
|
|
2
|
+
import { createOAuthFlow, type OAuthFlowOptions } from "./flow.js";
|
|
3
|
+
import type { OAuthProviderConfig } from "./providers/types.js";
|
|
4
|
+
import type { OAuthProviderId } from "./adapter/types.js";
|
|
5
|
+
export interface OAuthPluginOptions<TUser = unknown> {
|
|
6
|
+
secret?: string;
|
|
7
|
+
adapter: OAuthAdapter<TUser>;
|
|
8
|
+
providers: Partial<Record<OAuthProviderId, OAuthProviderConfig>>;
|
|
9
|
+
basePath?: string;
|
|
10
|
+
loginPath?: string;
|
|
11
|
+
redirectAllowlist?: readonly string[];
|
|
12
|
+
secure?: OAuthFlowOptions<TUser>["secure"];
|
|
13
|
+
onSuccess?: OAuthFlowOptions<TUser>["onSuccess"];
|
|
14
|
+
onError?: OAuthFlowOptions<TUser>["onError"];
|
|
15
|
+
tokenRefresh?: OAuthFlowOptions<TUser>["tokenRefresh"];
|
|
16
|
+
}
|
|
17
|
+
/** Otok plugin factory — register after auth() in otok.config.ts. */
|
|
18
|
+
export default function oauth<TUser = unknown>(options: OAuthPluginOptions<TUser>): import("@kamod-ch/otok-config").OtokPlugin<unknown>;
|
|
19
|
+
/** Programmatic setup — backward compatible with createOAuthFlow(). */
|
|
20
|
+
export { createOAuthFlow };
|
|
21
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,KAAK,gBAAgB,EAAE,MAAM,WAAW,CAAC;AACnE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,MAAM,WAAW,kBAAkB,CAAC,KAAK,GAAG,OAAO;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;IAC7B,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,mBAAmB,CAAC,CAAC,CAAC;IACjE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,MAAM,CAAC,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC3C,SAAS,CAAC,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC;IACjD,OAAO,CAAC,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC;IAC7C,YAAY,CAAC,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,CAAC;CACxD;AAkDD,qEAAqE;AACrE,MAAM,CAAC,OAAO,UAAU,KAAK,CAAC,KAAK,GAAG,OAAO,EAAE,OAAO,EAAE,kBAAkB,CAAC,KAAK,CAAC,uDAOhF;AAED,uEAAuE;AACvE,OAAO,EAAE,eAAe,EAAE,CAAC"}
|