o-auth-lib 1.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/README.md ADDED
@@ -0,0 +1,165 @@
1
+ # o-auth-lib
2
+
3
+ [![npm version](https://img.shields.io/npm/v/o-auth-lib.svg)](https://www.npmjs.com/package/o-auth-lib)
4
+ [![License: ISC](https://img.shields.io/badge/License-ISC-yellow.svg)](https://opensource.org/licenses/ISC)
5
+
6
+ A TypeScript authentication library for OAuth and normal login flows. The package is designed so consuming apps provide credentials and configuration at runtime, keeping the library reusable and secure.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm install o-auth-lib react
12
+ ```
13
+
14
+ ```bash
15
+ yarn add o-auth-lib react
16
+ ```
17
+
18
+ ```bash
19
+ pnpm add o-auth-lib react
20
+ ```
21
+
22
+ > **Requires:** `react@17` or `react@18`
23
+
24
+ ## Browser Support
25
+
26
+ - Modern browsers with support for:
27
+ - `crypto.getRandomValues()` (for PKCE)
28
+ - `crypto.subtle.digest()` (for SHA-256)
29
+ - `fetch` API
30
+ - `URLSearchParams`
31
+
32
+ Targets **ES2019** and above.
33
+
34
+ ## Usage
35
+
36
+ ### OAuth login
37
+
38
+ `useAuth()` is the recommended hook for browser-based OAuth login flows.
39
+
40
+ ```ts
41
+ import { useAuth } from "o-auth-lib";
42
+
43
+ const oauthConfig = {
44
+ authType: "oauth" as const,
45
+ provider: "google" as const,
46
+ clientId: import.meta.env.VITE_GOOGLE_CLIENT_ID,
47
+ redirectUri: import.meta.env.VITE_APP_REDIRECT_URI,
48
+ scopes: ["openid", "profile", "email"],
49
+ usePKCE: true,
50
+ };
51
+
52
+ function LoginButton() {
53
+ const { execute, loading, error, result } = useAuth(oauthConfig);
54
+
55
+ return (
56
+ <button onClick={() => execute()} disabled={loading}>
57
+ {loading ? "Signing in..." : "Sign in with Google"}
58
+ {error && <div>{error}</div>}
59
+ {result && <div>Authenticated</div>}
60
+ </button>
61
+ );
62
+ }
63
+ ```
64
+
65
+ > `usePKCE` is enabled by default for OAuth code flows, so browser apps do not need to use `clientSecret` in the frontend.
66
+
67
+ ### Generic authentication helper
68
+
69
+ For normal login flows, use `authenticate()` with a configurable auth endpoint.
70
+
71
+ ```ts
72
+ import { authenticate } from "o-auth-lib";
73
+
74
+ const normalConfig = {
75
+ authType: "normal" as const,
76
+ provider: "normal",
77
+ serviceName: "my-service",
78
+ authUrl: "https://api.example.com/auth/login",
79
+ email: "user@example.com",
80
+ password: "secret-password",
81
+ contentType: "application/json",
82
+ };
83
+
84
+ async function login() {
85
+ const result = await authenticate(normalConfig);
86
+ console.log(result.accessToken, result.data);
87
+ }
88
+ ```
89
+
90
+ ### Custom provider example
91
+
92
+ ```ts
93
+ import { authenticate } from "o-auth-lib";
94
+
95
+ const customOAuthConfig = {
96
+ authType: "oauth" as const,
97
+ provider: {
98
+ authorizeUrl: "https://custom.example.com/oauth/authorize",
99
+ tokenUrl: "https://custom.example.com/oauth/token",
100
+ responseType: "code",
101
+ scopeSeparator: " ",
102
+ },
103
+ clientId: import.meta.env.VITE_CUSTOM_CLIENT_ID,
104
+ redirectUri: import.meta.env.VITE_APP_REDIRECT_URI,
105
+ scopes: ["read", "write"],
106
+ };
107
+
108
+ const result = await authenticate(customOAuthConfig);
109
+ ```
110
+
111
+ ## Supported provider presets
112
+
113
+ - `google`
114
+ - `github`
115
+ - custom provider objects using `provider: { authorizeUrl, tokenUrl, ... }`
116
+
117
+ ## API Reference
118
+
119
+ ### `useAuth(config: AuthConfig): UseAuthResult`
120
+
121
+ React hook for authentication flows.
122
+
123
+ **Parameters:**
124
+ - `config` – OAuth or normal auth configuration
125
+ - `authType` – `"oauth"` or `"normal"`
126
+ - `provider` – Provider name or custom preset
127
+
128
+ **Returns:**
129
+ - `execute()` – Function to trigger authentication
130
+ - `loading` – Boolean indicating if auth is in progress
131
+ - `error` – Error message if authentication failed
132
+ - `result` – `AuthResult` containing access token and response data
133
+
134
+ ### `authenticate(config: AuthConfig): Promise<AuthResult>`
135
+
136
+ Generic async function for OAuth or normal authentication.
137
+
138
+ **Returns:**
139
+ - `authType` – Type of authentication used
140
+ - `provider` – Provider name
141
+ - `accessToken` – Access/bearer token if available
142
+ - `refreshToken` – Refresh token if available
143
+ - `data` – Raw response from OAuth provider or auth endpoint
144
+
145
+ ### PKCE Support
146
+
147
+ PKCE is enabled by default for OAuth authorization code flows. To disable:
148
+
149
+ ```ts
150
+ const config = {
151
+ authType: "oauth" as const,
152
+ provider: "google",
153
+ clientId: "...",
154
+ redirectUri: "...",
155
+ usePKCE: false, // Disable PKCE
156
+ };
157
+ ```
158
+
159
+ ## Important notes
160
+
161
+ - Do not store real credentials inside the published package.
162
+ - Pass `clientId` and other credentials from consuming apps, for example via environment variables.
163
+ - `clientSecret` should not be used in browser-only OAuth flows unless the application is a confidential client and the token exchange is performed on a trusted backend.
164
+ - The package publishes only `dist/` via `package.json` `files`, so local `.env` files are not included in the npm package.
165
+ - State validation is automatic and prevents CSRF attacks in OAuth flows.
@@ -0,0 +1,30 @@
1
+ import { OAuthConfig } from "./oauthService";
2
+ export type NormalAuthConfig = {
3
+ authType: "normal";
4
+ provider: "normal" | string;
5
+ serviceName?: string;
6
+ authUrl: string;
7
+ method?: "POST" | "PUT" | "PATCH" | "DELETE";
8
+ contentType?: "application/json" | "application/x-www-form-urlencoded";
9
+ email?: string;
10
+ password?: string;
11
+ credentials?: Record<string, string | number | boolean>;
12
+ extraBody?: Record<string, unknown>;
13
+ headers?: Record<string, string>;
14
+ };
15
+ export type OAuthAuthConfig = OAuthConfig & {
16
+ authType: "oauth";
17
+ };
18
+ export type AuthConfig = OAuthAuthConfig | NormalAuthConfig;
19
+ export type AuthResult = {
20
+ authType: "oauth" | "normal";
21
+ provider: string;
22
+ serviceName?: string;
23
+ accessToken?: string | number;
24
+ refreshToken?: string | number;
25
+ data: any;
26
+ };
27
+ export declare function authenticate(config: AuthConfig): Promise<AuthResult>;
28
+ export declare function authenticateOAuth(config: OAuthAuthConfig): Promise<AuthResult>;
29
+ export declare function authenticateNormal(config: NormalAuthConfig): Promise<AuthResult>;
30
+ //# sourceMappingURL=authService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authService.d.ts","sourceRoot":"","sources":["../src/authService.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,WAAW,EACZ,MAAM,gBAAgB,CAAC;AAExB,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;IAC7C,WAAW,CAAC,EAAE,kBAAkB,GAAG,mCAAmC,CAAC;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG;IAC1C,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,eAAe,GAAG,gBAAgB,CAAC;AAE5D,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,IAAI,EAAE,GAAG,CAAC;CACX,CAAC;AAEF,wBAAsB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAM1E;AAED,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC,CAwBpF;AAsBD,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,CA8BtF"}
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.authenticate = authenticate;
4
+ exports.authenticateOAuth = authenticateOAuth;
5
+ exports.authenticateNormal = authenticateNormal;
6
+ const oauthService_1 = require("./oauthService");
7
+ async function authenticate(config) {
8
+ if (config.authType === "normal") {
9
+ return authenticateNormal(config);
10
+ }
11
+ return authenticateOAuth(config);
12
+ }
13
+ async function authenticateOAuth(config) {
14
+ const authRequest = await (0, oauthService_1.createOAuthRequest)(config);
15
+ const oauthResult = await (0, oauthService_1.openAuthPopup)(authRequest.authUrl, config.redirectUri);
16
+ if (authRequest.state && oauthResult.state !== authRequest.state) {
17
+ throw new Error("OAuth state mismatch detected.");
18
+ }
19
+ if (oauthResult.error) {
20
+ throw new Error(oauthResult.error);
21
+ }
22
+ const tokenResponse = oauthResult.code
23
+ ? await (0, oauthService_1.fetchToken)(config, oauthResult.code, authRequest.codeVerifier)
24
+ : oauthResult;
25
+ return {
26
+ authType: "oauth",
27
+ provider: typeof config.provider === "string" ? config.provider : "custom",
28
+ serviceName: config.provider === "normal" ? "normal" : undefined,
29
+ accessToken: tokenResponse.access_token || tokenResponse.token || tokenResponse.accessToken,
30
+ refreshToken: tokenResponse.refresh_token || tokenResponse.refreshToken,
31
+ data: tokenResponse,
32
+ };
33
+ }
34
+ function buildNormalBody(config) {
35
+ const payload = {
36
+ ...(config.credentials || {}),
37
+ ...(config.email !== undefined ? { email: config.email } : {}),
38
+ ...(config.password !== undefined ? { password: config.password } : {}),
39
+ ...(config.extraBody || {}),
40
+ };
41
+ if ((config.contentType || "application/json") === "application/x-www-form-urlencoded") {
42
+ return new URLSearchParams(Object.entries(payload).reduce((result, [key, value]) => {
43
+ result[key] = String(value !== null && value !== void 0 ? value : "");
44
+ return result;
45
+ }, {})).toString();
46
+ }
47
+ return JSON.stringify(payload);
48
+ }
49
+ async function authenticateNormal(config) {
50
+ const method = config.method || "POST";
51
+ const contentType = config.contentType || "application/json";
52
+ const body = buildNormalBody(config);
53
+ const response = await fetch(config.authUrl, {
54
+ method,
55
+ headers: {
56
+ "Content-Type": contentType,
57
+ Accept: "application/json",
58
+ ...config.headers,
59
+ },
60
+ body,
61
+ });
62
+ if (!response.ok) {
63
+ const text = await response.text();
64
+ throw new Error(`Normal auth request failed: ${response.status} ${response.statusText} - ${text}`);
65
+ }
66
+ const data = await response.json();
67
+ return {
68
+ authType: "normal",
69
+ provider: config.provider,
70
+ serviceName: config.serviceName,
71
+ accessToken: data.access_token || data.token || data.accessToken,
72
+ refreshToken: data.refresh_token || data.refreshToken,
73
+ data,
74
+ };
75
+ }
76
+ //# sourceMappingURL=authService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authService.js","sourceRoot":"","sources":["../src/authService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=authService.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authService.test.d.ts","sourceRoot":"","sources":["../src/authService.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const authService_1 = require("./authService");
5
+ const originalFetch = global.fetch;
6
+ (0, vitest_1.afterEach)(() => {
7
+ vitest_1.vi.restoreAllMocks();
8
+ global.fetch = originalFetch;
9
+ });
10
+ (0, vitest_1.describe)("authService", () => {
11
+ (0, vitest_1.it)("sends JSON normal auth payload", async () => {
12
+ const fetchMock = vitest_1.vi.fn(() => Promise.resolve({
13
+ ok: true,
14
+ json: async () => ({ access_token: "abc123" }),
15
+ }));
16
+ global.fetch = fetchMock;
17
+ const result = await (0, authService_1.authenticate)({
18
+ authType: "normal",
19
+ provider: "normal",
20
+ authUrl: "https://example.com/login",
21
+ email: "user@example.com",
22
+ password: "secret",
23
+ contentType: "application/json",
24
+ });
25
+ (0, vitest_1.expect)(fetchMock).toHaveBeenCalled();
26
+ (0, vitest_1.expect)(result.accessToken).toBe("abc123");
27
+ });
28
+ (0, vitest_1.it)("sends form-urlencoded normal auth payload", async () => {
29
+ const fetchMock = vitest_1.vi.fn(() => Promise.resolve({
30
+ ok: true,
31
+ json: async () => ({ access_token: "abc123" }),
32
+ }));
33
+ global.fetch = fetchMock;
34
+ const result = await (0, authService_1.authenticate)({
35
+ authType: "normal",
36
+ provider: "normal",
37
+ authUrl: "https://example.com/login",
38
+ email: "user@example.com",
39
+ password: "secret",
40
+ contentType: "application/x-www-form-urlencoded",
41
+ });
42
+ (0, vitest_1.expect)(fetchMock).toHaveBeenCalledWith("https://example.com/login", vitest_1.expect.objectContaining({
43
+ method: "POST",
44
+ headers: vitest_1.expect.objectContaining({
45
+ "Content-Type": "application/x-www-form-urlencoded",
46
+ }),
47
+ }));
48
+ (0, vitest_1.expect)(result.accessToken).toBe("abc123");
49
+ });
50
+ });
51
+ //# sourceMappingURL=authService.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authService.test.js","sourceRoot":"","sources":["../src/authService.test.ts"],"names":[],"mappings":";;AAAA,mCAA6D;AAC7D,+CAA6C;AAE7C,MAAM,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC;AAEnC,IAAA,kBAAS,EAAC,GAAG,EAAE;IACb,WAAE,CAAC,eAAe,EAAE,CAAC;IACrB,MAAM,CAAC,KAAK,GAAG,aAAa,CAAC;AAC/B,CAAC,CAAC,CAAC;AAEH,IAAA,iBAAQ,EAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,IAAA,WAAE,EAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;QAC9C,MAAM,SAAS,GAAG,WAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAC3B,OAAO,CAAC,OAAO,CAAC;YACd,EAAE,EAAE,IAAI;YACR,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC;SACxC,CAAC,CACV,CAAC;QAEF,MAAM,CAAC,KAAK,GAAG,SAAgB,CAAC;QAEhC,MAAM,MAAM,GAAG,MAAM,IAAA,0BAAY,EAAC;YAChC,QAAQ,EAAE,QAAQ;YAClB,QAAQ,EAAE,QAAQ;YAClB,OAAO,EAAE,2BAA2B;YACpC,KAAK,EAAE,kBAAkB;YACzB,QAAQ,EAAE,QAAQ;YAClB,WAAW,EAAE,kBAAkB;SAChC,CAAC,CAAC;QAEH,IAAA,eAAM,EAAC,SAAS,CAAC,CAAC,gBAAgB,EAAE,CAAC;QACrC,IAAA,eAAM,EAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,MAAM,SAAS,GAAG,WAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAC3B,OAAO,CAAC,OAAO,CAAC;YACd,EAAE,EAAE,IAAI;YACR,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC;SACxC,CAAC,CACV,CAAC;QAEF,MAAM,CAAC,KAAK,GAAG,SAAgB,CAAC;QAEhC,MAAM,MAAM,GAAG,MAAM,IAAA,0BAAY,EAAC;YAChC,QAAQ,EAAE,QAAQ;YAClB,QAAQ,EAAE,QAAQ;YAClB,OAAO,EAAE,2BAA2B;YACpC,KAAK,EAAE,kBAAkB;YACzB,QAAQ,EAAE,QAAQ;YAClB,WAAW,EAAE,mCAAmC;SACjD,CAAC,CAAC;QAEH,IAAA,eAAM,EAAC,SAAS,CAAC,CAAC,oBAAoB,CACpC,2BAA2B,EAC3B,eAAM,CAAC,gBAAgB,CAAC;YACtB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,eAAM,CAAC,gBAAgB,CAAC;gBAC/B,cAAc,EAAE,mCAAmC;aACpD,CAAC;SACH,CAAC,CACH,CAAC;QACF,IAAA,eAAM,EAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,5 @@
1
+ export * from "./oauthService";
2
+ export * from "./authService";
3
+ export * from "./useAuth";
4
+ export * from "./useOAuth";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./oauthService"), exports);
18
+ __exportStar(require("./authService"), exports);
19
+ __exportStar(require("./useAuth"), exports);
20
+ __exportStar(require("./useOAuth"), exports);
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,iDAA+B;AAC/B,gDAA8B;AAC9B,4CAA0B;AAC1B,6CAA2B"}
@@ -0,0 +1,50 @@
1
+ export type OAuthProviderName = "google" | "github" | "normal";
2
+ export type OAuthProviderPreset = {
3
+ authorizeUrl: string;
4
+ tokenUrl: string;
5
+ scopeSeparator?: string;
6
+ responseType?: "code" | "token";
7
+ additionalAuthParams?: Record<string, string>;
8
+ defaultScopes?: string[];
9
+ };
10
+ export type OAuthConfig = {
11
+ provider: OAuthProviderName | OAuthProviderPreset;
12
+ clientId: string;
13
+ clientSecret?: string;
14
+ redirectUri: string;
15
+ scopes?: string[];
16
+ state?: string;
17
+ extraAuthParams?: Record<string, string>;
18
+ extraTokenParams?: Record<string, string>;
19
+ responseType?: "code" | "token";
20
+ grantType?: string;
21
+ usePKCE?: boolean;
22
+ pkceMethod?: "S256" | "plain";
23
+ codeVerifier?: string;
24
+ };
25
+ export type OAuthAuthResponse = {
26
+ code?: string;
27
+ access_token?: string;
28
+ token_type?: string;
29
+ expires_in?: number;
30
+ refresh_token?: string;
31
+ error?: string;
32
+ state?: string;
33
+ [key: string]: string | number | undefined;
34
+ };
35
+ export type OAuthRequest = {
36
+ authUrl: string;
37
+ codeVerifier?: string;
38
+ state?: string;
39
+ };
40
+ export declare function buildAuthUrl(config: OAuthConfig): string;
41
+ export declare function parseAuthResponse(url: string): OAuthAuthResponse;
42
+ export declare function createOAuthRequest(config: OAuthConfig): Promise<OAuthRequest>;
43
+ export declare function fetchToken(config: OAuthConfig, code: string, codeVerifier?: string): Promise<OAuthAuthResponse>;
44
+ export type PopupOptions = {
45
+ width?: number;
46
+ height?: number;
47
+ timeoutMs?: number;
48
+ };
49
+ export declare function openAuthPopup(authUrl: string, redirectUri: string, options?: PopupOptions): Promise<OAuthAuthResponse>;
50
+ //# sourceMappingURL=oauthService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauthService.d.ts","sourceRoot":"","sources":["../src/oauthService.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE/D,MAAM,MAAM,mBAAmB,GAAG;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9C,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,iBAAiB,GAAG,mBAAmB,CAAC;IAClD,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAqEF,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAiBxD;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,CAmBhE;AAED,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CA2BnF;AAED,wBAAsB,UAAU,CAC9B,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE,MAAM,EACZ,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,iBAAiB,CAAC,CAsC5B;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,iBAAiB,CAAC,CAiD5B"}
@@ -0,0 +1,202 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildAuthUrl = buildAuthUrl;
4
+ exports.parseAuthResponse = parseAuthResponse;
5
+ exports.createOAuthRequest = createOAuthRequest;
6
+ exports.fetchToken = fetchToken;
7
+ exports.openAuthPopup = openAuthPopup;
8
+ const providerPresets = {
9
+ google: {
10
+ authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth",
11
+ tokenUrl: "https://oauth2.googleapis.com/token",
12
+ scopeSeparator: " ",
13
+ responseType: "code",
14
+ defaultScopes: ["openid", "profile", "email"],
15
+ },
16
+ github: {
17
+ authorizeUrl: "https://github.com/login/oauth/authorize",
18
+ tokenUrl: "https://github.com/login/oauth/access_token",
19
+ scopeSeparator: " ",
20
+ responseType: "code",
21
+ additionalAuthParams: {
22
+ allow_signup: "true",
23
+ },
24
+ },
25
+ normal: {
26
+ authorizeUrl: "",
27
+ tokenUrl: "",
28
+ scopeSeparator: " ",
29
+ responseType: "code",
30
+ },
31
+ };
32
+ function normalizeProvider(config) {
33
+ if (typeof config.provider === "string") {
34
+ const preset = providerPresets[config.provider];
35
+ if (!preset) {
36
+ throw new Error(`OAuth provider preset "${config.provider}" is not defined.`);
37
+ }
38
+ return preset;
39
+ }
40
+ return config.provider;
41
+ }
42
+ function generateRandomString(length = 64) {
43
+ const array = new Uint8Array(length);
44
+ crypto.getRandomValues(array);
45
+ return Array.from(array)
46
+ .map((byte) => (byte % 36).toString(36))
47
+ .join("");
48
+ }
49
+ async function sha256(value) {
50
+ const encoder = new TextEncoder();
51
+ const data = encoder.encode(value);
52
+ return crypto.subtle.digest("SHA-256", data);
53
+ }
54
+ function base64UrlEncode(buffer) {
55
+ const bytes = new Uint8Array(buffer);
56
+ let binary = "";
57
+ bytes.forEach((byte) => {
58
+ binary += String.fromCharCode(byte);
59
+ });
60
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
61
+ }
62
+ async function createCodeChallenge(verifier, method = "S256") {
63
+ if (method === "plain") {
64
+ return verifier;
65
+ }
66
+ const digest = await sha256(verifier);
67
+ return base64UrlEncode(digest);
68
+ }
69
+ function buildAuthUrl(config) {
70
+ const provider = normalizeProvider(config);
71
+ if (!provider.authorizeUrl) {
72
+ throw new Error("The OAuth provider authorizeUrl is required.");
73
+ }
74
+ const params = new URLSearchParams({
75
+ response_type: config.responseType || provider.responseType || "code",
76
+ client_id: config.clientId,
77
+ redirect_uri: config.redirectUri,
78
+ scope: (config.scopes || provider.defaultScopes || []).join(provider.scopeSeparator || " "),
79
+ state: config.state || generateRandomString(16),
80
+ ...provider.additionalAuthParams,
81
+ ...config.extraAuthParams,
82
+ });
83
+ return `${provider.authorizeUrl}?${params.toString()}`;
84
+ }
85
+ function parseAuthResponse(url) {
86
+ const parsed = new URL(url, window.location.origin);
87
+ const searchParams = new URLSearchParams(parsed.search);
88
+ const hashParams = new URLSearchParams(parsed.hash.replace(/^#/, ""));
89
+ const combined = new URLSearchParams();
90
+ searchParams.forEach((value, key) => combined.append(key, value));
91
+ hashParams.forEach((value, key) => combined.append(key, value));
92
+ const result = {};
93
+ combined.forEach((value, key) => {
94
+ if (key === "expires_in") {
95
+ result.expires_in = Number(value);
96
+ }
97
+ else {
98
+ result[key] = value;
99
+ }
100
+ });
101
+ return result;
102
+ }
103
+ async function createOAuthRequest(config) {
104
+ const provider = normalizeProvider(config);
105
+ if (!provider.authorizeUrl) {
106
+ throw new Error("The OAuth provider authorizeUrl is required.");
107
+ }
108
+ const state = config.state || generateRandomString(16);
109
+ const extraAuthParams = {
110
+ ...provider.additionalAuthParams,
111
+ ...config.extraAuthParams,
112
+ };
113
+ let codeVerifier;
114
+ if (config.usePKCE !== false && (config.responseType || provider.responseType || "code") === "code") {
115
+ codeVerifier = config.codeVerifier || generateRandomString(128);
116
+ const codeChallenge = await createCodeChallenge(codeVerifier, config.pkceMethod || "S256");
117
+ extraAuthParams.code_challenge = codeChallenge;
118
+ extraAuthParams.code_challenge_method = config.pkceMethod || "S256";
119
+ }
120
+ const authUrl = buildAuthUrl({
121
+ ...config,
122
+ state,
123
+ extraAuthParams,
124
+ });
125
+ return { authUrl, codeVerifier, state };
126
+ }
127
+ async function fetchToken(config, code, codeVerifier) {
128
+ const provider = normalizeProvider(config);
129
+ if (!provider.tokenUrl) {
130
+ throw new Error("The OAuth provider tokenUrl is required to exchange the authorization code.");
131
+ }
132
+ const body = new URLSearchParams({
133
+ grant_type: config.grantType || "authorization_code",
134
+ code,
135
+ redirect_uri: config.redirectUri,
136
+ client_id: config.clientId,
137
+ ...config.extraTokenParams,
138
+ });
139
+ if (codeVerifier) {
140
+ body.append("code_verifier", codeVerifier);
141
+ }
142
+ if (config.clientSecret) {
143
+ body.append("client_secret", config.clientSecret);
144
+ }
145
+ const response = await fetch(provider.tokenUrl, {
146
+ method: "POST",
147
+ headers: {
148
+ "Content-Type": "application/x-www-form-urlencoded",
149
+ Accept: "application/json",
150
+ },
151
+ body: body.toString(),
152
+ });
153
+ if (!response.ok) {
154
+ const text = await response.text();
155
+ throw new Error(`Token request failed: ${response.status} ${response.statusText} - ${text}`);
156
+ }
157
+ const data = await response.json();
158
+ return data;
159
+ }
160
+ async function openAuthPopup(authUrl, redirectUri, options = {}) {
161
+ var _a;
162
+ const width = options.width || 500;
163
+ const height = options.height || 650;
164
+ const left = window.screenX + (window.innerWidth - width) / 2;
165
+ const top = window.screenY + (window.innerHeight - height) / 2;
166
+ const popup = window.open(authUrl, "oauth_popup", `width=${width},height=${height},left=${left},top=${top},resizable,scrollbars=yes`);
167
+ if (!popup) {
168
+ throw new Error("Unable to open OAuth popup window. Please allow popups for this site.");
169
+ }
170
+ const start = Date.now();
171
+ const timeoutMs = (_a = options.timeoutMs) !== null && _a !== void 0 ? _a : 120000;
172
+ return new Promise((resolve, reject) => {
173
+ const interval = window.setInterval(() => {
174
+ if (popup.closed) {
175
+ clearInterval(interval);
176
+ reject(new Error("OAuth popup was closed before authentication completed."));
177
+ return;
178
+ }
179
+ try {
180
+ const popupUrl = popup.location.href;
181
+ if (!popupUrl || popupUrl === "about:blank") {
182
+ return;
183
+ }
184
+ if (popupUrl.startsWith(redirectUri) || popup.location.search.includes("code") || popup.location.hash) {
185
+ const result = parseAuthResponse(popupUrl);
186
+ popup.close();
187
+ clearInterval(interval);
188
+ resolve(result);
189
+ }
190
+ }
191
+ catch (error) {
192
+ // Cross-origin access is expected until redirect back to our origin.
193
+ }
194
+ if (Date.now() - start > timeoutMs) {
195
+ clearInterval(interval);
196
+ popup.close();
197
+ reject(new Error("OAuth popup timeout exceeded."));
198
+ }
199
+ }, 500);
200
+ });
201
+ }
202
+ //# sourceMappingURL=oauthService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauthService.js","sourceRoot":"","sources":["../src/oauthService.ts"],"names":[],"mappings":";;AA+GA,oCAiBC;AAED,8CAmBC;AAED,gDA2BC;AAED,gCA0CC;AAQD,sCAqDC;AA/OD,MAAM,eAAe,GAAmD;IACtE,MAAM,EAAE;QACN,YAAY,EAAE,8CAA8C;QAC5D,QAAQ,EAAE,qCAAqC;QAC/C,cAAc,EAAE,GAAG;QACnB,YAAY,EAAE,MAAM;QACpB,aAAa,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC;KAC9C;IACD,MAAM,EAAE;QACN,YAAY,EAAE,0CAA0C;QACxD,QAAQ,EAAE,6CAA6C;QACvD,cAAc,EAAE,GAAG;QACnB,YAAY,EAAE,MAAM;QACpB,oBAAoB,EAAE;YACpB,YAAY,EAAE,MAAM;SACrB;KACF;IACD,MAAM,EAAE;QACN,YAAY,EAAE,EAAE;QAChB,QAAQ,EAAE,EAAE;QACZ,cAAc,EAAE,GAAG;QACnB,YAAY,EAAE,MAAM;KACrB;CACF,CAAC;AAEF,SAAS,iBAAiB,CAAC,MAAmB;IAC5C,IAAI,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAChD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,0BAA0B,MAAM,CAAC,QAAQ,mBAAmB,CAAC,CAAC;QAChF,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,OAAO,MAAM,CAAC,QAAQ,CAAC;AACzB,CAAC;AAED,SAAS,oBAAoB,CAAC,MAAM,GAAG,EAAE;IACvC,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;IACrC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAC9B,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;SACrB,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;SACvC,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,KAAa;IACjC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACnC,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAC/C,CAAC;AAED,SAAS,eAAe,CAAC,MAAmB;IAC1C,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;IACrC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QACrB,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IACH,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACjF,CAAC;AAED,KAAK,UAAU,mBAAmB,CAAC,QAAgB,EAAE,SAA2B,MAAM;IACpF,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;QACvB,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;IACtC,OAAO,eAAe,CAAC,MAAM,CAAC,CAAC;AACjC,CAAC;AAED,SAAgB,YAAY,CAAC,MAAmB;IAC9C,MAAM,QAAQ,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC3C,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;QACjC,aAAa,EAAE,MAAM,CAAC,YAAY,IAAI,QAAQ,CAAC,YAAY,IAAI,MAAM;QACrE,SAAS,EAAE,MAAM,CAAC,QAAQ;QAC1B,YAAY,EAAE,MAAM,CAAC,WAAW;QAChC,KAAK,EAAE,CAAC,MAAM,CAAC,MAAM,IAAI,QAAQ,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,IAAI,GAAG,CAAC;QAC3F,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,oBAAoB,CAAC,EAAE,CAAC;QAC/C,GAAG,QAAQ,CAAC,oBAAoB;QAChC,GAAG,MAAM,CAAC,eAAe;KAC1B,CAAC,CAAC;IAEH,OAAO,GAAG,QAAQ,CAAC,YAAY,IAAI,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;AACzD,CAAC;AAED,SAAgB,iBAAiB,CAAC,GAAW;IAC3C,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACpD,MAAM,YAAY,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACxD,MAAM,UAAU,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;IACtE,MAAM,QAAQ,GAAG,IAAI,eAAe,EAAE,CAAC;IAEvC,YAAY,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;IAClE,UAAU,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;IAEhE,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QAC9B,IAAI,GAAG,KAAK,YAAY,EAAE,CAAC;YACzB,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACtB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC;AAEM,KAAK,UAAU,kBAAkB,CAAC,MAAmB;IAC1D,MAAM,QAAQ,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC3C,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,oBAAoB,CAAC,EAAE,CAAC,CAAC;IACvD,MAAM,eAAe,GAA2B;QAC9C,GAAG,QAAQ,CAAC,oBAAoB;QAChC,GAAG,MAAM,CAAC,eAAe;KAC1B,CAAC;IAEF,IAAI,YAAgC,CAAC;IACrC,IAAI,MAAM,CAAC,OAAO,KAAK,KAAK,IAAI,CAAC,MAAM,CAAC,YAAY,IAAI,QAAQ,CAAC,YAAY,IAAI,MAAM,CAAC,KAAK,MAAM,EAAE,CAAC;QACpG,YAAY,GAAG,MAAM,CAAC,YAAY,IAAI,oBAAoB,CAAC,GAAG,CAAC,CAAC;QAChE,MAAM,aAAa,GAAG,MAAM,mBAAmB,CAAC,YAAY,EAAE,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,CAAC;QAC3F,eAAe,CAAC,cAAc,GAAG,aAAa,CAAC;QAC/C,eAAe,CAAC,qBAAqB,GAAG,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC;IACtE,CAAC;IAED,MAAM,OAAO,GAAG,YAAY,CAAC;QAC3B,GAAG,MAAM;QACT,KAAK;QACL,eAAe;KAChB,CAAC,CAAC;IAEH,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;AAC1C,CAAC;AAEM,KAAK,UAAU,UAAU,CAC9B,MAAmB,EACnB,IAAY,EACZ,YAAqB;IAErB,MAAM,QAAQ,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC3C,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,6EAA6E,CAAC,CAAC;IACjG,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC;QAC/B,UAAU,EAAE,MAAM,CAAC,SAAS,IAAI,oBAAoB;QACpD,IAAI;QACJ,YAAY,EAAE,MAAM,CAAC,WAAW;QAChC,SAAS,EAAE,MAAM,CAAC,QAAQ;QAC1B,GAAG,MAAM,CAAC,gBAAgB;KAC3B,CAAC,CAAC;IAEH,IAAI,YAAY,EAAE,CAAC;QACjB,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,YAAY,CAAC,CAAC;IAC7C,CAAC;IAED,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;QACxB,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE;QAC9C,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,mCAAmC;YACnD,MAAM,EAAE,kBAAkB;SAC3B;QACD,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE;KACtB,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,yBAAyB,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,MAAM,IAAI,EAAE,CAAC,CAAC;IAC/F,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IACnC,OAAO,IAAyB,CAAC;AACnC,CAAC;AAQM,KAAK,UAAU,aAAa,CACjC,OAAe,EACf,WAAmB,EACnB,UAAwB,EAAE;;IAE1B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,GAAG,CAAC;IACnC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,GAAG,CAAC;IACrC,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,GAAG,CAAC,MAAM,CAAC,UAAU,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9D,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,GAAG,CAAC,MAAM,CAAC,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC/D,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CACvB,OAAO,EACP,aAAa,EACb,SAAS,KAAK,WAAW,MAAM,SAAS,IAAI,QAAQ,GAAG,2BAA2B,CACnF,CAAC;IAEF,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAC;IAC3F,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,MAAM,SAAS,GAAG,MAAA,OAAO,CAAC,SAAS,mCAAI,MAAM,CAAC;IAE9C,OAAO,IAAI,OAAO,CAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACxD,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE;YACvC,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;gBACjB,aAAa,CAAC,QAAQ,CAAC,CAAC;gBACxB,MAAM,CAAC,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC,CAAC;gBAC7E,OAAO;YACT,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;gBACrC,IAAI,CAAC,QAAQ,IAAI,QAAQ,KAAK,aAAa,EAAE,CAAC;oBAC5C,OAAO;gBACT,CAAC;gBAED,IAAI,QAAQ,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;oBACtG,MAAM,MAAM,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;oBAC3C,KAAK,CAAC,KAAK,EAAE,CAAC;oBACd,aAAa,CAAC,QAAQ,CAAC,CAAC;oBACxB,OAAO,CAAC,MAAM,CAAC,CAAC;gBAClB,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,qEAAqE;YACvE,CAAC;YAED,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,SAAS,EAAE,CAAC;gBACnC,aAAa,CAAC,QAAQ,CAAC,CAAC;gBACxB,KAAK,CAAC,KAAK,EAAE,CAAC;gBACd,MAAM,CAAC,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC,CAAC;YACrD,CAAC;QACH,CAAC,EAAE,GAAG,CAAC,CAAC;IACV,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=oauthService.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauthService.test.d.ts","sourceRoot":"","sources":["../src/oauthService.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const oauthService_1 = require("./oauthService");
5
+ (0, vitest_1.describe)("oauthService", () => {
6
+ (0, vitest_1.it)("creates an OAuth request with PKCE and state", async () => {
7
+ const request = await (0, oauthService_1.createOAuthRequest)({
8
+ provider: "google",
9
+ clientId: "test-client",
10
+ redirectUri: "https://app.test/callback",
11
+ scopes: ["openid"],
12
+ usePKCE: true,
13
+ });
14
+ (0, vitest_1.expect)(request.authUrl).toContain("code_challenge=");
15
+ (0, vitest_1.expect)(request.authUrl).toContain("code_challenge_method=S256");
16
+ (0, vitest_1.expect)(request.authUrl).toContain("state=");
17
+ (0, vitest_1.expect)(request.codeVerifier).toBeDefined();
18
+ (0, vitest_1.expect)(request.state).toBeDefined();
19
+ });
20
+ (0, vitest_1.it)("parses an OAuth redirect response", () => {
21
+ const response = (0, oauthService_1.parseAuthResponse)("https://app.test/callback?code=abc123&state=xyz");
22
+ (0, vitest_1.expect)(response.code).toBe("abc123");
23
+ (0, vitest_1.expect)(response.state).toBe("xyz");
24
+ });
25
+ });
26
+ //# sourceMappingURL=oauthService.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauthService.test.js","sourceRoot":"","sources":["../src/oauthService.test.ts"],"names":[],"mappings":";;AAAA,mCAA8C;AAC9C,iDAAuE;AAEvE,IAAA,iBAAQ,EAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,IAAA,WAAE,EAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAkB,EAAC;YACvC,QAAQ,EAAE,QAAQ;YAClB,QAAQ,EAAE,aAAa;YACvB,WAAW,EAAE,2BAA2B;YACxC,MAAM,EAAE,CAAC,QAAQ,CAAC;YAClB,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;QAEH,IAAA,eAAM,EAAC,OAAO,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;QACrD,IAAA,eAAM,EAAC,OAAO,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,4BAA4B,CAAC,CAAC;QAChE,IAAA,eAAM,EAAC,OAAO,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC5C,IAAA,eAAM,EAAC,OAAO,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE,CAAC;QAC3C,IAAA,eAAM,EAAC,OAAO,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,QAAQ,GAAG,IAAA,gCAAiB,EAAC,iDAAiD,CAAC,CAAC;QACtF,IAAA,eAAM,EAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACrC,IAAA,eAAM,EAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { AuthConfig, AuthResult } from "./authService";
2
+ export type UseAuthResult = {
3
+ execute: () => Promise<AuthResult>;
4
+ loading: boolean;
5
+ error?: string;
6
+ result?: AuthResult;
7
+ };
8
+ export declare function useAuth(config: AuthConfig): UseAuthResult;
9
+ //# sourceMappingURL=useAuth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAuth.d.ts","sourceRoot":"","sources":["../src/useAuth.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,UAAU,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAErE,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB,CAAC;AAEF,wBAAgB,OAAO,CAAC,MAAM,EAAE,UAAU,GAAG,aAAa,CAuBzD"}
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useAuth = useAuth;
4
+ const react_1 = require("react");
5
+ const authService_1 = require("./authService");
6
+ function useAuth(config) {
7
+ const [loading, setLoading] = (0, react_1.useState)(false);
8
+ const [error, setError] = (0, react_1.useState)();
9
+ const [result, setResult] = (0, react_1.useState)();
10
+ const execute = (0, react_1.useCallback)(async () => {
11
+ setLoading(true);
12
+ setError(undefined);
13
+ try {
14
+ const response = await (0, authService_1.authenticate)(config);
15
+ setResult(response);
16
+ return response;
17
+ }
18
+ catch (err) {
19
+ const message = err instanceof Error ? err.message : String(err);
20
+ setError(message);
21
+ throw err;
22
+ }
23
+ finally {
24
+ setLoading(false);
25
+ }
26
+ }, [config]);
27
+ return { execute, loading, error, result };
28
+ }
29
+ //# sourceMappingURL=useAuth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAuth.js","sourceRoot":"","sources":["../src/useAuth.ts"],"names":[],"mappings":";;AAUA,0BAuBC;AAjCD,iCAA8C;AAC9C,+CAAqE;AASrE,SAAgB,OAAO,CAAC,MAAkB;IACxC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,IAAA,gBAAQ,EAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,IAAA,gBAAQ,GAAU,CAAC;IAC7C,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,IAAA,gBAAQ,GAAc,CAAC;IAEnD,MAAM,OAAO,GAAG,IAAA,mBAAW,EAAC,KAAK,IAAI,EAAE;QACrC,UAAU,CAAC,IAAI,CAAC,CAAC;QACjB,QAAQ,CAAC,SAAS,CAAC,CAAC;QAEpB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAA,0BAAY,EAAC,MAAM,CAAC,CAAC;YAC5C,SAAS,CAAC,QAAQ,CAAC,CAAC;YACpB,OAAO,QAAQ,CAAC;QAClB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,QAAQ,CAAC,OAAO,CAAC,CAAC;YAClB,MAAM,GAAG,CAAC;QACZ,CAAC;gBAAS,CAAC;YACT,UAAU,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC;IACH,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEb,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAC7C,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { useAuth as useOAuth } from "./useAuth";
2
+ //# sourceMappingURL=useOAuth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useOAuth.d.ts","sourceRoot":"","sources":["../src/useOAuth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useOAuth = void 0;
4
+ var useAuth_1 = require("./useAuth");
5
+ Object.defineProperty(exports, "useOAuth", { enumerable: true, get: function () { return useAuth_1.useAuth; } });
6
+ //# sourceMappingURL=useOAuth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useOAuth.js","sourceRoot":"","sources":["../src/useOAuth.ts"],"names":[],"mappings":";;;AAAA,qCAAgD;AAAvC,mGAAA,OAAO,OAAY"}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "o-auth-lib",
3
+ "version": "1.0.0",
4
+ "description": "A TypeScript-friendly authentication library for OAuth and custom login flows with PKCE support.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "prepare": "npm run build",
13
+ "test": "vitest run"
14
+ },
15
+ "keywords": [
16
+ "oauth",
17
+ "react",
18
+ "typescript",
19
+ "authentication",
20
+ "pkce"
21
+ ],
22
+ "author": "dataxis-labs",
23
+ "license": "ISC",
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "https://github.com/Dataxis-UditSingh/o-auth-lib.git"
27
+ },
28
+ "bugs": {
29
+ "url": "https://github.com/Dataxis-UditSingh/o-auth-lib/issues"
30
+ },
31
+ "homepage": "https://github.com/Dataxis-UditSingh/o-auth-lib#readme",
32
+ "type": "commonjs",
33
+ "peerDependencies": {
34
+ "react": "^17 || ^18"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "^20.0.0",
38
+ "@types/react": "^18.0.0",
39
+ "jsdom": "^29.1.1",
40
+ "typescript": "^5.0.0",
41
+ "vitest": "^4.1.7"
42
+ }
43
+ }