@draftlab/auth 0.0.3 → 0.0.4

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.
Files changed (74) hide show
  1. package/dist/allow.d.ts +58 -1
  2. package/dist/allow.js +61 -2
  3. package/dist/client.d.ts +2 -3
  4. package/dist/client.js +2 -2
  5. package/dist/core.d.ts +128 -8
  6. package/dist/core.js +496 -12
  7. package/dist/error.d.ts +242 -1
  8. package/dist/error.js +235 -1
  9. package/dist/index.d.ts +1 -8
  10. package/dist/index.js +1 -12
  11. package/dist/keys.d.ts +1 -1
  12. package/dist/keys.js +138 -3
  13. package/dist/pkce.js +160 -1
  14. package/dist/provider/code.d.ts +211 -3
  15. package/dist/provider/code.js +1 -1
  16. package/dist/provider/facebook.d.ts +2 -3
  17. package/dist/provider/facebook.js +1 -5
  18. package/dist/provider/github.d.ts +2 -3
  19. package/dist/provider/github.js +1 -5
  20. package/dist/provider/google.d.ts +2 -3
  21. package/dist/provider/google.js +1 -5
  22. package/dist/provider/oauth2.d.ts +175 -3
  23. package/dist/provider/oauth2.js +153 -5
  24. package/dist/provider/password.d.ts +384 -3
  25. package/dist/provider/password.js +4 -4
  26. package/dist/provider/provider.d.ts +226 -2
  27. package/dist/random.js +85 -1
  28. package/dist/storage/memory.d.ts +1 -1
  29. package/dist/storage/memory.js +1 -1
  30. package/dist/storage/storage.d.ts +161 -1
  31. package/dist/storage/storage.js +60 -1
  32. package/dist/storage/turso.d.ts +1 -1
  33. package/dist/storage/turso.js +1 -1
  34. package/dist/storage/unstorage.d.ts +1 -1
  35. package/dist/storage/unstorage.js +1 -1
  36. package/dist/subject.d.ts +61 -2
  37. package/dist/themes/theme.d.ts +208 -1
  38. package/dist/themes/theme.js +118 -1
  39. package/dist/ui/base.js +420 -2
  40. package/dist/ui/code.d.ts +1 -3
  41. package/dist/ui/code.js +3 -4
  42. package/dist/ui/form.js +59 -1
  43. package/dist/ui/icon.js +190 -1
  44. package/dist/ui/password.d.ts +1 -3
  45. package/dist/ui/password.js +2 -3
  46. package/dist/ui/select.js +278 -4
  47. package/dist/util.d.ts +71 -1
  48. package/dist/util.js +106 -1
  49. package/package.json +2 -2
  50. package/dist/allow-CixonwTW.d.ts +0 -59
  51. package/dist/allow-DX5cehSc.js +0 -63
  52. package/dist/base-DRutbxgL.js +0 -422
  53. package/dist/code-DJxdFR7p.d.ts +0 -212
  54. package/dist/core-BZHEAefX.d.ts +0 -129
  55. package/dist/core-CDM5o4rs.js +0 -498
  56. package/dist/error-CWAdNAzm.d.ts +0 -243
  57. package/dist/error-DgAKK7b2.js +0 -237
  58. package/dist/form-6XKM_cOk.js +0 -61
  59. package/dist/icon-Ci5uqGB_.js +0 -192
  60. package/dist/keys-EEfxEGfO.js +0 -140
  61. package/dist/oauth2-B7-6Z7Lc.js +0 -155
  62. package/dist/oauth2-CXHukHf2.d.ts +0 -176
  63. package/dist/password-C4KLmO0O.d.ts +0 -385
  64. package/dist/pkce-276Za_rZ.js +0 -162
  65. package/dist/provider-tndlqCzp.d.ts +0 -227
  66. package/dist/random-SXMYlaVr.js +0 -87
  67. package/dist/select-BjySLL8I.js +0 -280
  68. package/dist/storage-BEaqEPNQ.js +0 -62
  69. package/dist/storage-CxKerLlc.d.ts +0 -162
  70. package/dist/subject-DMIMVtaT.d.ts +0 -62
  71. package/dist/theme-C9by7VXf.d.ts +0 -209
  72. package/dist/theme-CswaLtbW.js +0 -120
  73. package/dist/util-CSdHUFOo.js +0 -108
  74. package/dist/util-DbSKG1Xm.d.ts +0 -72
package/dist/allow.d.ts CHANGED
@@ -1,2 +1,59 @@
1
- import { AllowCheckInput, defaultAllowCheck } from "./allow-CixonwTW.js";
1
+ //#region src/allow.d.ts
2
+ /**
3
+ * Client authorization validation utilities.
4
+ * Provides security checks to determine if OAuth authorization requests should be permitted
5
+ * based on redirect URI validation and domain matching policies.
6
+ */
7
+ /**
8
+ * Input parameters for authorization allow checks.
9
+ * Contains all necessary information to validate if a client request should be permitted.
10
+ */
11
+ interface AllowCheckInput {
12
+ /** The client ID of the application requesting authorization */
13
+ readonly clientID: string;
14
+ /** The redirect URI where the user will be sent after authorization */
15
+ readonly redirectURI: string;
16
+ /** Optional audience parameter for the authorization request */
17
+ readonly audience?: string;
18
+ }
19
+ /**
20
+ * Default authorization check that validates client requests based on redirect URI security.
21
+ *
22
+ * ## Security Policy
23
+ * - **Localhost**: Always allowed (for development)
24
+ * - **Same domain**: Redirect URI must match request origin at TLD+1 level
25
+ * - **Cross-domain**: Rejected for security
26
+ *
27
+ * This prevents unauthorized applications from hijacking authorization codes by using
28
+ * malicious redirect URIs that don't belong to the legitimate client application.
29
+ *
30
+ * @param input - Client request details including ID and redirect URI
31
+ * @param req - The original HTTP request for domain comparison
32
+ * @returns Promise resolving to true if the request should be allowed
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * // Allowed: localhost development
37
+ * await defaultAllowCheck({
38
+ * clientID: "dev-app",
39
+ * redirectURI: "http://localhost:3000/callback"
40
+ * }, request) // → true
41
+ *
42
+ * // Allowed: same domain
43
+ * // Request from: https://myapp.com
44
+ * await defaultAllowCheck({
45
+ * clientID: "web-app",
46
+ * redirectURI: "https://auth.myapp.com/callback"
47
+ * }, request) // → true
48
+ *
49
+ * // Rejected: different domain
50
+ * // Request from: https://myapp.com
51
+ * await defaultAllowCheck({
52
+ * clientID: "malicious-app",
53
+ * redirectURI: "https://evil.com/steal-codes"
54
+ * }, request) // → false
55
+ * ```
56
+ */
57
+ declare const defaultAllowCheck: (input: AllowCheckInput, req: Request) => Promise<boolean>;
58
+ //#endregion
2
59
  export { AllowCheckInput, defaultAllowCheck };
package/dist/allow.js CHANGED
@@ -1,4 +1,63 @@
1
- import "./util-CSdHUFOo.js";
2
- import { defaultAllowCheck } from "./allow-DX5cehSc.js";
1
+ import { isDomainMatch } from "./util.js";
3
2
 
3
+ //#region src/allow.ts
4
+ /**
5
+ * Default authorization check that validates client requests based on redirect URI security.
6
+ *
7
+ * ## Security Policy
8
+ * - **Localhost**: Always allowed (for development)
9
+ * - **Same domain**: Redirect URI must match request origin at TLD+1 level
10
+ * - **Cross-domain**: Rejected for security
11
+ *
12
+ * This prevents unauthorized applications from hijacking authorization codes by using
13
+ * malicious redirect URIs that don't belong to the legitimate client application.
14
+ *
15
+ * @param input - Client request details including ID and redirect URI
16
+ * @param req - The original HTTP request for domain comparison
17
+ * @returns Promise resolving to true if the request should be allowed
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * // Allowed: localhost development
22
+ * await defaultAllowCheck({
23
+ * clientID: "dev-app",
24
+ * redirectURI: "http://localhost:3000/callback"
25
+ * }, request) // → true
26
+ *
27
+ * // Allowed: same domain
28
+ * // Request from: https://myapp.com
29
+ * await defaultAllowCheck({
30
+ * clientID: "web-app",
31
+ * redirectURI: "https://auth.myapp.com/callback"
32
+ * }, request) // → true
33
+ *
34
+ * // Rejected: different domain
35
+ * // Request from: https://myapp.com
36
+ * await defaultAllowCheck({
37
+ * clientID: "malicious-app",
38
+ * redirectURI: "https://evil.com/steal-codes"
39
+ * }, request) // → false
40
+ * ```
41
+ */
42
+ const defaultAllowCheck = (input, req) => {
43
+ return Promise.resolve((() => {
44
+ let redirectHostname;
45
+ try {
46
+ redirectHostname = new URL(input.redirectURI).hostname;
47
+ } catch {
48
+ return false;
49
+ }
50
+ if (redirectHostname === "localhost" || redirectHostname === "127.0.0.1") return true;
51
+ let currentHostname;
52
+ try {
53
+ const forwardedHost = req.headers.get("x-forwarded-host");
54
+ currentHostname = forwardedHost ? new URL(`https://${forwardedHost}`).hostname : new URL(req.url).hostname;
55
+ } catch {
56
+ return false;
57
+ }
58
+ return isDomainMatch(redirectHostname, currentHostname);
59
+ })());
60
+ };
61
+
62
+ //#endregion
4
63
  export { defaultAllowCheck };
package/dist/client.d.ts CHANGED
@@ -1,6 +1,5 @@
1
- import { InvalidAccessTokenError, InvalidAuthorizationCodeError, InvalidRefreshTokenError, InvalidSubjectError } from "./error-CWAdNAzm.js";
2
- import "./util-DbSKG1Xm.js";
3
- import { SubjectSchema } from "./subject-DMIMVtaT.js";
1
+ import { InvalidAccessTokenError, InvalidAuthorizationCodeError, InvalidRefreshTokenError, InvalidSubjectError } from "./error.js";
2
+ import { SubjectSchema } from "./subject.js";
4
3
  import { StandardSchemaV1 } from "@standard-schema/spec";
5
4
 
6
5
  //#region src/client.d.ts
package/dist/client.js CHANGED
@@ -1,5 +1,5 @@
1
- import { InvalidAccessTokenError, InvalidAuthorizationCodeError, InvalidRefreshTokenError, InvalidSubjectError } from "./error-DgAKK7b2.js";
2
- import { generatePKCE } from "./pkce-276Za_rZ.js";
1
+ import { InvalidAccessTokenError, InvalidAuthorizationCodeError, InvalidRefreshTokenError, InvalidSubjectError } from "./error.js";
2
+ import { generatePKCE } from "./pkce.js";
3
3
  import { createLocalJWKSet, errors, jwtVerify } from "jose";
4
4
 
5
5
  //#region src/client.ts
package/dist/core.d.ts CHANGED
@@ -1,9 +1,129 @@
1
- import "./allow-CixonwTW.js";
2
- import "./error-CWAdNAzm.js";
3
- import "./util-DbSKG1Xm.js";
4
- import "./subject-DMIMVtaT.js";
5
- import "./storage-CxKerLlc.js";
6
- import "./provider-tndlqCzp.js";
7
- import "./theme-C9by7VXf.js";
8
- import { AuthorizationState, OnSuccessResponder, issuer } from "./core-BZHEAefX.js";
1
+ import { AllowCheckInput } from "./allow.js";
2
+ import { UnknownStateError } from "./error.js";
3
+ import { Prettify } from "./util.js";
4
+ import { SubjectPayload, SubjectSchema } from "./subject.js";
5
+ import { StorageAdapter } from "./storage/storage.js";
6
+ import { Provider } from "./provider/provider.js";
7
+ import { Theme } from "./themes/theme.js";
8
+ import { Router } from "@draftlab/auth-router";
9
+
10
+ //#region src/core.d.ts
11
+
12
+ /**
13
+ * Sets the subject payload in the JWT token and returns the response.
14
+ */
15
+ interface OnSuccessResponder<T extends {
16
+ type: string;
17
+ properties: unknown;
18
+ }> {
19
+ subject<Type extends T["type"]>(type: Type, properties: Extract<T, {
20
+ type: Type;
21
+ }>["properties"], opts?: {
22
+ ttl?: {
23
+ access?: number;
24
+ refresh?: number;
25
+ };
26
+ subject?: string;
27
+ }): Promise<Response>;
28
+ }
29
+ /**
30
+ * Authorization state for OAuth 2.0 flows.
31
+ */
32
+ interface AuthorizationState {
33
+ /** OAuth redirect URI */
34
+ redirect_uri: string;
35
+ /** OAuth response type */
36
+ response_type: string;
37
+ /** OAuth state parameter for CSRF protection */
38
+ state: string;
39
+ /** OAuth client identifier */
40
+ client_id: string;
41
+ /** OAuth audience parameter */
42
+ audience: string;
43
+ /** PKCE challenge data for code verification */
44
+ pkce?: {
45
+ challenge: string;
46
+ method: "S256";
47
+ };
48
+ }
49
+ /**
50
+ * Main issuer input configuration interface.
51
+ */
52
+ interface IssuerInput<Providers extends Record<string, Provider<unknown>>, Subjects extends SubjectSchema, Result = { [Key in keyof Providers]: Prettify<{
53
+ provider: Key;
54
+ } & (Providers[Key] extends Provider<infer T> ? T : Record<string, unknown>)> }[keyof Providers]> {
55
+ /** The storage adapter for persisting tokens and sessions */
56
+ storage: StorageAdapter;
57
+ /** Auth providers configuration */
58
+ providers: Providers;
59
+ /** Subject schemas for token validation */
60
+ subjects: Subjects;
61
+ /** Base path for embedded scenarios */
62
+ basePath?: string;
63
+ /** Success callback for completed authentication */
64
+ success(response: OnSuccessResponder<SubjectPayload<Subjects>>, input: Result, req: Request, clientID: string): Promise<Response>;
65
+ /** Theme configuration for UI */
66
+ theme?: Theme;
67
+ /** TTL configuration for tokens and sessions */
68
+ ttl?: {
69
+ access?: number;
70
+ refresh?: number;
71
+ reuse?: number;
72
+ retention?: number;
73
+ };
74
+ /** Provider selection UI function */
75
+ select?(providers: Record<string, string>, req: Request): Promise<Response>;
76
+ /** Optional start callback */
77
+ start?(req: Request): Promise<void>;
78
+ /** Error handling callback */
79
+ error?(error: UnknownStateError, req: Request): Promise<Response>;
80
+ /** Client authorization check function */
81
+ allow?(input: AllowCheckInput, req: Request): Promise<boolean>;
82
+ /**
83
+ * Refresh callback for updating user claims.
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * refresh: async (payload, req) => {
88
+ * const user = await getUserBySubject(payload.subject)
89
+ * if (!user || !user.active) {
90
+ * return undefined // Revoke the token
91
+ * }
92
+ *
93
+ * return {
94
+ * type: payload.type,
95
+ * properties: {
96
+ * userID: user.id,
97
+ * role: user.role,
98
+ * permissions: user.permissions,
99
+ * lastLogin: new Date().toISOString()
100
+ * }
101
+ * }
102
+ * }
103
+ * ```
104
+ */
105
+ refresh?(payload: {
106
+ type: SubjectPayload<Subjects>["type"];
107
+ properties: SubjectPayload<Subjects>["properties"];
108
+ subject: string;
109
+ clientID: string;
110
+ scopes?: string[];
111
+ }, req: Request): Promise<{
112
+ type: SubjectPayload<Subjects>["type"];
113
+ properties: SubjectPayload<Subjects>["properties"];
114
+ subject?: string;
115
+ scopes?: string[];
116
+ } | undefined>;
117
+ }
118
+ /**
119
+ * Create an Draft Auth server, a Router app that handles OAuth 2.0 flows.
120
+ */
121
+ declare const issuer: <Providers extends Record<string, Provider<unknown>>, Subjects extends SubjectSchema, Result = { [key in keyof Providers]: {
122
+ provider: key;
123
+ } & (Providers[key] extends Provider<infer T> ? T : Record<string, unknown>) }[keyof Providers]>(input: IssuerInput<Providers, Subjects, Result>) => Router<{
124
+ Variables: {
125
+ authorization: AuthorizationState;
126
+ };
127
+ }>;
128
+ //#endregion
9
129
  export { AuthorizationState, OnSuccessResponder, issuer };