orange-auth 0.1.2 → 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 CHANGED
@@ -1,118 +1,177 @@
1
- # 🍊 Orange Auth
2
-
3
- ### THIS IS A VERY EARLY WIP, AND SHOULD NOT BE USED
4
-
5
- A lightweight authentication handler built for [@universal-middleware/core](https://www.npmjs.com/package/@universal-middleware/core), with support for plug-and-play providers and strategies. This package manages login/logout and session deserialization through HTTP handlers and secure cookies.
6
-
7
- ---
8
-
9
- ## Features
10
-
11
- - Provider-based authentication (e.g., Credentials, OAuth)
12
- - Strategy-based token serialization and deserialization (e.g., JWT)
13
- - Secure, HTTP-only cookie session management
14
- - Framework-agnostic and middleware-compatible
15
- - Written in TypeScript
16
-
17
- ---
18
-
19
- ## 📦 Installation
20
-
21
- ```bash
22
- npm install universal-auth
23
- ```
24
-
25
- 📁 Project Structure
26
-
27
- ```bash
28
- src/
29
- ├── @types/ # Custom type definitions (e.g., Session)
30
- ├── functions/ # Utility functions
31
- ├── providers/ # Implementations of IProvider
32
- ├── strategies/ # Implementations of IStrategy
33
- ├── lib.ts # Main exports
34
- ```
35
-
36
- ## 🚀 Usage
37
-
38
- ### 1. Define your auth configuration:
39
-
40
- ```ts
41
- import { CreateAuth } from "universal-auth";
42
- import { JwtStrategy } from "./strategies/jwt";
43
- import { CredentialsProvider } from "./providers/Credentials";
44
-
45
- const handler = CreateAuth({
46
- providers: [CredentialsProvider],
47
- secret: "your-secret-key",
48
- cookieName: "my-auth-cookie", // optional (default: "orange.auth")
49
- strategy: JwtStrategy,
50
- basePath: "/api/auth",
51
- });
52
- ```
53
-
54
- This will expose two routes:
55
-
56
- `GET /api/auth/login/:provider`
57
-
58
- `GET /api/auth/logout/:provider`
59
-
60
- You must implement a matching `provider.ID`, e.g. `"credentials"`.
61
-
62
- ### 2. Use in a universal middleware router:`
63
-
64
- ```ts
65
- import { router } from "@universal-middleware/core";
66
- import { handler as authHandler } from "./path-to-your-auth";
67
-
68
- export const app = router();
69
- app.use(authHandler);
70
- ```
71
-
72
- ### 3. Getting the current session:
73
-
74
- ```ts
75
- import { getSession } from "universal-auth";
76
-
77
- const session = await getSession(req);
78
- if (session) {
79
- console.log("Logged in as", session.user);
80
- }
81
- ```
82
-
83
- ## 🧩 Interfaces
84
-
85
- `IProvider`
86
-
87
- Defines how to log in a user and return a token:
88
-
89
- ```ts
90
- interface IProvider {
91
- ID: string;
92
- logIn(req: Request, config: ConfigOptions): Promise<string>;
93
- }
94
- ```
95
-
96
- `IStrategy`
97
-
98
- Defines how to serialize and deserialize tokens:
99
-
100
- ```ts
101
- interface IStrategy {
102
- deserialize(token: string, config: ConfigOptions): Promise<Session | null>;
103
- logOut(req: Request, config: ConfigOptions): Promise<void>;
104
- }
105
- ```
106
-
107
- ## 🔐 Security
108
- Cookies are set with:
109
-
110
- `HttpOnly: true`
111
-
112
- `SameSite: "Lax"`
113
-
114
- `Secure: true`
115
-
116
- `Max-Age: 600` (10 minutes)
117
-
118
- You may customize these by modifying the `CreateAuth` implementation.
1
+ # 🍊 Orange Auth
2
+
3
+ ### THIS IS A VERY EARLY WIP, AND SHOULD NOT BE USED IN PRODUCTION
4
+
5
+ Authentication middleware for [@universal-middleware/core](https://www.npmjs.com/package/@universal-middleware/core), supporting provider-based login/logout and strategy-driven session handling via secure cookies.
6
+
7
+ ## 🚀 Features
8
+
9
+ - Provider-based login/logout flow
10
+ - Pluggable strategies (e.g. JWT)
11
+ - Secure cookie-based session storage
12
+ - Simple, composable handler with session retrieval
13
+ - Optional cookie settings
14
+ - Framework-agnostic
15
+
16
+ ## 📦 Install
17
+
18
+ ```bash
19
+ npm install orange-auth
20
+ ```
21
+
22
+ ## 🧠 Usage
23
+
24
+ ### Setup
25
+
26
+ ```ts
27
+ import { CreateAuth } from "orange-auth";
28
+ import { JWT } from "orange-auth/strategies";
29
+ import { Credentials } from "orange-auth/providers";
30
+
31
+ const { handler, getSession } = CreateAuth({
32
+ providers: [new Credentials({ ... })],
33
+ strategy: new JWT({ ... }),
34
+ secret: "your-secret",
35
+ basePath: "/api/auth/:action/:provider",
36
+ });
37
+ ```
38
+
39
+ You can now use:
40
+ - `POST /api/auth/login/:provider`
41
+ - `POST /api/auth/logout/:provider`
42
+
43
+ ### Example (express middleware router)
44
+
45
+ ```ts
46
+ import express from "express";
47
+ import { handler } from "./auth";
48
+ import { createHandler } from "@universal-middleware/express";
49
+
50
+ const app = express();
51
+ app.get("/api/auth/{*auth}", createHandler(handler)());
52
+ ```
53
+
54
+ ## 🧾 Session Access
55
+
56
+ ```ts
57
+ import { getSession } from "./auth";
58
+
59
+ const session = await getSession(req);
60
+
61
+ if (session) {
62
+ console.log("Logged in user:", session.user);
63
+ }
64
+ ```
65
+
66
+ ## 🧩 Config Options
67
+
68
+ ```ts
69
+ type ConfigOptionsProps = {
70
+ /**
71
+ * All the available providers.
72
+ * If multiple instance of a single provider are used with the same name, the order does matter.
73
+ */
74
+ providers: IProvider[];
75
+
76
+ /**
77
+ * Your secret key.
78
+ */
79
+ secret: string;
80
+
81
+ /**
82
+ * A custom name for the cookie.
83
+ * Otherwise, the default name will be `orange.auth`
84
+ */
85
+ cookieName?: string;
86
+
87
+ /**
88
+ * The strategy to be used.
89
+ */
90
+ strategy: IStrategy;
91
+
92
+ /**
93
+ * This should be the url path that your auth is set up on, including the action and provider variables.
94
+ * @example
95
+ * ```js
96
+ * const app = express();
97
+ *
98
+ * const { handler } = CreateAuth({
99
+ * basePath: "/api/auth/:action/:provider",
100
+ * ...
101
+ * });
102
+ *
103
+ * app.all("/api/auth/{*auth}", createHandler(handler)());
104
+ * ```
105
+ */
106
+ basePath: string;
107
+
108
+ /**
109
+ * Cookie serialization options. see [MDN Cookie](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cookies)
110
+ */
111
+ cookieSettings?: SerializeOptions;
112
+ };
113
+ ```
114
+
115
+ ## 🧱 Interfaces
116
+
117
+ ### IProvider
118
+
119
+ ```ts
120
+ abstract class IProvider {
121
+ /**
122
+ * Custom name for a provider
123
+ */
124
+ ID: string;
125
+
126
+ /**
127
+ * Login function. This is used to call all the login flows of each provider.
128
+ * For now, the request's body **MUST** be JSON.
129
+ * @param req The request object.
130
+ * @param globalCfg The global auth config.
131
+ */
132
+ logIn(req: Request, globalCfg: ConfigOptions): Promise<string | null>;
133
+ }
134
+ ```
135
+
136
+ ### IStrategy
137
+
138
+ ```ts
139
+ abstract class IStrategy {
140
+ /**
141
+ * Handles how a session token is generated.
142
+ * @param session The validated session object.
143
+ * @param globalCfg The global auth config.
144
+ * @returns A newly generated token that will be sent as a cookie.
145
+ */
146
+ serialize(session: Session, globalCfg: ConfigOptions): Promise<string>;
147
+
148
+ /**
149
+ * Handles how a token is validated and deserialized into a session object.
150
+ * @param token A user's token.
151
+ * @param globalCfg The global auth config.
152
+ * @returns A user's session if validated and found, else `null`.
153
+ */
154
+ deserialize(token: string, globalCfg: ConfigOptions): Promise<Session | null>;
155
+
156
+ /**
157
+ * Handles how a session is destroyed when a user is logging out.
158
+ * @param req The request object.
159
+ * @param globalCfg The global auth config.
160
+ */
161
+ logOut(req: Request, globalCfg: ConfigOptions): Promise<void>;
162
+ }
163
+ ```
164
+
165
+ ---
166
+
167
+ ## 🔐 Cookie Defaults
168
+
169
+ By default, the cookie is:
170
+
171
+ - `httpOnly: true`
172
+ - `secure: true`
173
+ - `sameSite: "lax"`
174
+ - `path: "/"`
175
+ - `maxAge: 3600` (1 hour)
176
+
177
+ This can be customized via `cookieSettings` in the initial config.
@@ -1,6 +1,7 @@
1
- declare global {
2
- type MaybePromise<T> = T | Promise<T>;
3
- }
1
+ /**
2
+ * This is a Promise, or not...
3
+ */
4
+ export type MaybePromise<T> = T | Promise<T>;
4
5
  /**
5
6
  * General session type. This should be augmented to include your session's fields.
6
7
  */
@@ -1 +1 @@
1
- {"version":3,"file":"globals.d.ts","sourceRoot":"","sources":["../../src/@types/globals.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,CAAC;IACX,KAAK,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACzC;AAED;;GAEG;AACH,MAAM,WAAW,OAAQ,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACpD,EAAE,EAAE,MAAM,CAAC;CACd"}
1
+ {"version":3,"file":"globals.d.ts","sourceRoot":"","sources":["../../src/@types/globals.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,OAAQ,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACpD,EAAE,EAAE,MAAM,CAAC;CACd"}
@@ -0,0 +1,6 @@
1
+ import type { ConfigOptionsProps } from "../lib";
2
+ /**
3
+ * Internally used version of the options
4
+ */
5
+ export type ConfigOptions = Required<Omit<ConfigOptionsProps, "basePath">>;
6
+ //# sourceMappingURL=internals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internals.d.ts","sourceRoot":"","sources":["../../src/@types/internals.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAEjD;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,IAAI,CAAC,kBAAkB,EAAE,UAAU,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from "./jwt";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/functions/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC"}
@@ -0,0 +1 @@
1
+ export * from "./jwt";
@@ -1 +1 @@
1
- {"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../src/functions/jwt.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,MAAM,EACX,KAAK,aAAa,EACrB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEpC;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,EACpD,KAAK,EAAE,MAAM,EACb,iBAAiB,EAAE,MAAM,GAAG,SAAS,EACrC,OAAO,CAAC,EAAE,aAAa,qBAS1B"}
1
+ {"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../src/functions/jwt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,KAAK,MAAM,EAAE,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAGtH,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEpC;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,EACpD,KAAK,EAAE,MAAM,EACb,iBAAiB,EAAE,MAAM,GAAG,SAAS,EACrC,OAAO,CAAC,EAAE,aAAa,qBAS1B"}
@@ -1,4 +1,4 @@
1
- import { verify as baseVerify, } from "jsonwebtoken";
1
+ import { verify as baseVerify } from "jsonwebtoken";
2
2
  // The sign function is fine as-is
3
3
  export { sign } from "jsonwebtoken";
4
4
  /**
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./lib";
2
- export * from "./providers";
3
- export * from "./strategies";
2
+ export * from "./@types/globals";
3
+ export * as providers from "./providers";
4
+ export * as strategies from "./strategies";
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC;AACtB,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC;AACtB,cAAc,kBAAkB,CAAC;AACjC,OAAO,KAAK,SAAS,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,UAAU,MAAM,cAAc,CAAC"}
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "./lib";
2
- export * from "./providers";
3
- export * from "./strategies";
2
+ export * from "./@types/globals";
3
+ export * as providers from "./providers";
4
+ export * as strategies from "./strategies";
package/dist/lib.d.ts CHANGED
@@ -15,7 +15,10 @@ export type ConfigOptionsProps = Readonly<{
15
15
  /**
16
16
  * Your secret key.
17
17
  */
18
- secret: string;
18
+ secret: string | {
19
+ publicKey: string;
20
+ privateKey: string;
21
+ };
19
22
  /**
20
23
  * A custom name for the cookie.
21
24
  * Otherwise, the default name will be `orange.auth`
@@ -31,10 +34,12 @@ export type ConfigOptionsProps = Readonly<{
31
34
  * ```js
32
35
  * const app = express();
33
36
  *
34
- * app.all("/api/auth/{*auth}", createHandler(CreateAuth)({
35
- * basePath: "/api/auth/:action/:provider",
36
- * ...
37
- * }))
37
+ * const { handler } = CreateAuth({
38
+ * basePath: "/api/auth/:action/:provider",
39
+ * ...
40
+ * });
41
+ *
42
+ * app.all("/api/auth/{*auth}", createHandler(handler)());
38
43
  * ```
39
44
  */
40
45
  basePath: string;
@@ -43,18 +48,16 @@ export type ConfigOptionsProps = Readonly<{
43
48
  */
44
49
  cookieSettings?: SerializeOptions;
45
50
  }>;
46
- /**
47
- * Internally used version of the options
48
- */
49
- export type __internal__Options = Required<Omit<ConfigOptionsProps, "basePath">>;
50
- export declare const CreateAuth: (config: ConfigOptionsProps) => (req: Request, _: Universal.Context, runtime: import("@universal-middleware/core").RuntimeAdapter) => Promise<Response>;
51
51
  /**
52
52
  * Access a user's session.
53
53
  * @param req Something that has a `headers` field; either a Headers instance, or just a plain object.
54
54
  * @returns A session if found and valid, or `null`.
55
55
  */
56
- export declare const getSession: <T extends Session = Session>(req: {
57
- headers: Maybe<Headers | Record<string, string>>;
58
- }) => Promise<T | null> | null;
56
+ export declare const CreateAuth: (config: ConfigOptionsProps) => {
57
+ handler: () => (req: Request, _: Universal.Context, runtime: import("@universal-middleware/core").RuntimeAdapter) => Promise<Response>;
58
+ getSession: <T extends Session = Session>(req: {
59
+ headers: Maybe<Headers | Record<string, string>>;
60
+ }) => Promise<T | null>;
61
+ };
59
62
  export {};
60
63
  //# sourceMappingURL=lib.d.ts.map
package/dist/lib.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAW,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAuB,KAAK,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAGpE,KAAK,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;AAErC;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACtC;;;OAGG;IACH,SAAS,EAAE,SAAS,EAAE,CAAC;IAEvB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;IAEpB;;;;;;;;;;;OAWG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,cAAc,CAAC,EAAE,gBAAgB,CAAC;CACrC,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC,IAAI,CAAC,kBAAkB,EAAE,UAAU,CAAC,CAAC,CAAC;AAWjF,eAAO,MAAM,UAAU,WAAa,kBAAkB,4HA6EU,CAAC;AAEjE;;;;GAIG;AACH,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,KAAK;IAAE,OAAO,EAAE,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CAAE,6BAehH,CAAC"}
1
+ {"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAW,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAuB,KAAK,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAGpE,KAAK,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;AAarC;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACtC;;;OAGG;IACH,SAAS,EAAE,SAAS,EAAE,CAAC;IAEvB;;OAEG;IACH,MAAM,EAAE,MAAM,GAAG;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAE3D;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;IAEpB;;;;;;;;;;;;;OAaG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,cAAc,CAAC,EAAE,gBAAgB,CAAC;CACrC,CAAC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,UAAU,WAAa,kBAAkB;;iBA0F3B,CAAC,SAAS,OAAO,iBAAiB;QAAE,OAAO,EAAE,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;KAAE;CA4BhH,CAAC"}
package/dist/lib.js CHANGED
@@ -2,14 +2,21 @@ import Cookies from "universal-cookie";
2
2
  import { assign, find, isNil } from "lodash-es";
3
3
  import { serialize as cookie } from "cookie";
4
4
  import { params } from "@universal-middleware/core";
5
- // Default config, only set otherwise `assign` doesn't like it.
6
- let globalCfg = {
7
- cookieName: "orange.auth",
8
- providers: [],
9
- secret: crypto.randomUUID(),
10
- strategy: null,
11
- cookieSettings: {},
12
- };
5
+ if (!globalThis.crypto) {
6
+ /**
7
+ * Polyfill needed if this code runs on node18
8
+ */
9
+ Object.defineProperty(globalThis, "crypto", {
10
+ value: await import("node:crypto").then((crypto) => crypto.webcrypto),
11
+ writable: false,
12
+ configurable: true,
13
+ });
14
+ }
15
+ /**
16
+ * Access a user's session.
17
+ * @param req Something that has a `headers` field; either a Headers instance, or just a plain object.
18
+ * @returns A session if found and valid, or `null`.
19
+ */
13
20
  export const CreateAuth = ((config) => {
14
21
  const { secret, strategy, cookieName, providers, cookieSettings, basePath } = config;
15
22
  if (isNil(secret)) {
@@ -20,7 +27,7 @@ export const CreateAuth = ((config) => {
20
27
  }
21
28
  // We set the global config on startup, and not on the route handler,
22
29
  // otherwise a session cannot be accessed until someone logs in
23
- assign(globalCfg, {
30
+ const globalCfg = {
24
31
  cookieName: cookieName ?? "orange.auth",
25
32
  providers: providers ?? [],
26
33
  secret,
@@ -32,65 +39,69 @@ export const CreateAuth = ((config) => {
32
39
  secure: true,
33
40
  maxAge: 3600,
34
41
  },
35
- });
36
- return async (req, _, runtime) => {
37
- // Tries to get the action and provider info from the url
38
- const routeParams = params(req, runtime, basePath);
39
- if (isNil(routeParams?.["action"]) || isNil(routeParams["provider"])) {
40
- throw new Error('[ERROR]: Base path is missing! Make sure to set the "basePath" variable in the auth\'s config.');
41
- }
42
- // Finds the requested provider by name
43
- const path = routeParams["provider"];
44
- const provider = find(providers, (p) => p.ID === path);
45
- if (isNil(provider)) {
46
- return new Response("Page not found", { status: 404 });
47
- }
48
- // Handles each action independently
49
- switch (routeParams["action"]) {
50
- case "login": {
51
- // Use the found provider to login
52
- const token = await provider.logIn(req, globalCfg).catch(() => null);
53
- // If failed, return Bad Request response
54
- if (isNil(token))
55
- return new Response(null, { status: 400 });
56
- // Creates the set-cookie header
57
- const headers = new Headers();
58
- headers.set("Set-Cookie", cookie(globalCfg.cookieName, token, globalCfg.cookieSettings));
59
- // And returns it
60
- return new Response(null, { status: 200, headers });
61
- }
62
- case "logout": {
63
- // Use the strategy to logout
64
- await globalCfg.strategy.logOut(req, globalCfg);
65
- // Clears the header.
66
- const headers = new Headers();
67
- headers.set("Set-Cookie", cookie(globalCfg.cookieName, ""));
68
- // And send them
69
- return new Response(null, { status: 200, headers });
42
+ };
43
+ return {
44
+ handler: () => async (req, _, runtime) => {
45
+ // Tries to get the action and provider info from the url
46
+ const routeParams = params(req, runtime, basePath);
47
+ if (isNil(routeParams?.["action"]) || isNil(routeParams["provider"])) {
48
+ throw new Error('[ERROR]: Base path is missing! Make sure to set the "basePath" variable in the auth\'s config.');
70
49
  }
71
- default:
72
- // If a wrong action is requested, return a 404
50
+ // Finds the requested provider by name
51
+ const path = routeParams["provider"];
52
+ const provider = find(providers, (p) => p.ID === path);
53
+ if (isNil(provider)) {
73
54
  return new Response("Page not found", { status: 404 });
74
- }
55
+ }
56
+ // Handles each action independently
57
+ switch (routeParams["action"]) {
58
+ case "login": {
59
+ // Use the found provider to login
60
+ const token = await provider.logIn(req, globalCfg).catch(() => null);
61
+ // If failed, return Bad Request response
62
+ if (isNil(token))
63
+ return new Response(null, { status: 400 });
64
+ // Creates the set-cookie header
65
+ const headers = new Headers();
66
+ headers.set("Set-Cookie", cookie(globalCfg.cookieName, token, globalCfg.cookieSettings));
67
+ // And returns it
68
+ return new Response(null, { status: 200, headers });
69
+ }
70
+ case "logout": {
71
+ // Use the strategy to logout
72
+ await globalCfg.strategy.logOut(req, globalCfg);
73
+ // Clears the header.
74
+ const headers = new Headers();
75
+ headers.set("Set-Cookie", cookie(globalCfg.cookieName, "deleted",
76
+ // Use the same cookie config, but make sure it is expired
77
+ assign({}, globalCfg.cookieSettings, {
78
+ expires: new Date(0),
79
+ maxAge: undefined,
80
+ })));
81
+ // And send them
82
+ return new Response(null, { status: 200, headers });
83
+ }
84
+ default:
85
+ // If a wrong action is requested, return a 404
86
+ return new Response("Page not found", { status: 404 });
87
+ }
88
+ },
89
+ getSession: async (req) => {
90
+ if (isNil(req.headers))
91
+ return null;
92
+ // Here, it always outputs the original state
93
+ // console.log(ConfigManager.get());
94
+ // Find the correct cookie header
95
+ const cookieHeader = req.headers instanceof Headers ? req.headers.get("cookie") : req.headers["cookie"];
96
+ const cookie = new Cookies(cookieHeader);
97
+ if (isNil(cookie))
98
+ return null;
99
+ // Tries to extract the specific cookie.
100
+ const token = cookie.get(globalCfg.cookieName);
101
+ if (isNil(token))
102
+ return null;
103
+ // Tries to deserialize it
104
+ return globalCfg.strategy.deserialize(token, globalCfg);
105
+ },
75
106
  };
76
107
  });
77
- /**
78
- * Access a user's session.
79
- * @param req Something that has a `headers` field; either a Headers instance, or just a plain object.
80
- * @returns A session if found and valid, or `null`.
81
- */
82
- export const getSession = (req) => {
83
- if (isNil(req.headers))
84
- return null;
85
- // Find the correct cookie header
86
- const cookieHeader = req.headers instanceof Headers ? req.headers.get("cookie") : req.headers["cookie"];
87
- const cookie = new Cookies(cookieHeader);
88
- if (isNil(cookie))
89
- return null;
90
- // Tries to extract the specific cookie.
91
- const token = cookie.get(globalCfg.cookieName);
92
- if (isNil(token))
93
- return null;
94
- // Tries to deserialize it
95
- return globalCfg.strategy.deserialize(token, globalCfg);
96
- };
@@ -1,6 +1,6 @@
1
1
  import { IProvider } from "./IProvider";
2
- import type { __internal__Options } from "../lib";
3
- import type { Session } from "../@types/globals";
2
+ import type { Session, MaybePromise } from "../@types/globals";
3
+ import type { ConfigOptions } from "../@types/internals";
4
4
  /**
5
5
  * Configuration options of the Credentials provider
6
6
  */
@@ -29,6 +29,6 @@ export declare class Credentials<TCredentials extends string = string> extends I
29
29
  private config;
30
30
  constructor(config: CredentialsConfig<TCredentials>);
31
31
  getSession(): Promise<Session | null>;
32
- logIn(req: Request, globalCfg: __internal__Options): Promise<string | null>;
32
+ logIn(req: Request, globalCfg: ConfigOptions): Promise<string | null>;
33
33
  }
34
34
  //# sourceMappingURL=Credentials.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Credentials.d.ts","sourceRoot":"","sources":["../../src/providers/Credentials.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD;;GAEG;AACH,MAAM,MAAM,iBAAiB,CAAC,YAAY,SAAS,MAAM,IAAI,QAAQ,CAAC;IAClE;;;OAGG;IACH,IAAI,CAAC,EAAE,aAAa,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IACrC;;OAEG;IACH,WAAW,EAAE,YAAY,EAAE,CAAC;IAC5B;;;;;OAKG;IACH,SAAS,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,KAAK,YAAY,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;CAC1F,CAAC,CAAC;AAEH;;GAEG;AACH,qBAAa,WAAW,CAAC,YAAY,SAAS,MAAM,GAAG,MAAM,CAAE,SAAQ,SAAS;IAC5E,OAAO,CAAC,MAAM,CAAkC;gBAEpC,MAAM,EAAE,iBAAiB,CAAC,YAAY,CAAC;IAK7B,UAAU,IAAI,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAIrC,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAWpG"}
1
+ {"version":3,"file":"Credentials.d.ts","sourceRoot":"","sources":["../../src/providers/Credentials.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD;;GAEG;AACH,MAAM,MAAM,iBAAiB,CAAC,YAAY,SAAS,MAAM,IAAI,QAAQ,CAAC;IAClE;;;OAGG;IACH,IAAI,CAAC,EAAE,aAAa,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IACrC;;OAEG;IACH,WAAW,EAAE,YAAY,EAAE,CAAC;IAC5B;;;;;OAKG;IACH,SAAS,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,KAAK,YAAY,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;CAC1F,CAAC,CAAC;AAEH;;GAEG;AACH,qBAAa,WAAW,CAAC,YAAY,SAAS,MAAM,GAAG,MAAM,CAAE,SAAQ,SAAS;IAC5E,OAAO,CAAC,MAAM,CAAkC;gBAEpC,MAAM,EAAE,iBAAiB,CAAC,YAAY,CAAC;IAK7B,UAAU,IAAI,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAIrC,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAW9F"}
@@ -6,7 +6,7 @@ import { IProvider } from "./IProvider";
6
6
  export class Credentials extends IProvider {
7
7
  config;
8
8
  constructor(config) {
9
- super("credentials");
9
+ super(config.name ?? "credentials");
10
10
  this.config = config;
11
11
  }
12
12
  async getSession() {
@@ -1,5 +1,5 @@
1
- import type { __internal__Options } from "../lib";
2
1
  import type { Session } from "../@types/globals";
2
+ import type { ConfigOptions } from "../@types/internals";
3
3
  /**
4
4
  * Available url callback actions.
5
5
  */
@@ -19,14 +19,14 @@ declare abstract class IProvider {
19
19
  */
20
20
  get ID(): string;
21
21
  /** @deprecated You can use the top level `getSession` instead. */
22
- abstract getSession(req: Request, globalCfg: __internal__Options): Promise<Session | null>;
22
+ abstract getSession(req: Request, globalCfg: ConfigOptions): Promise<Session | null>;
23
23
  /**
24
24
  * Login function. This is used to call all the login flows of each provider.
25
25
  * For now, the request's body **MUST** be JSON.
26
26
  * @param req The request object.
27
27
  * @param globalCfg The global auth config.
28
28
  */
29
- abstract logIn(req: Request, globalCfg: __internal__Options): Promise<string | null>;
29
+ abstract logIn(req: Request, globalCfg: ConfigOptions): Promise<string | null>;
30
30
  }
31
31
  export { IProvider };
32
32
  //# sourceMappingURL=IProvider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"IProvider.d.ts","sourceRoot":"","sources":["../../src/providers/IProvider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEzC;;;GAGG;AACH,uBAAe,SAAS;IACpB;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;gBAElB,EAAE,EAAE,MAAM;IAItB;;OAEG;IACH,IAAW,EAAE,IAAI,MAAM,CAEtB;IAED,kEAAkE;aAClD,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAEjG;;;;;OAKG;aACa,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAC9F;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"IProvider.d.ts","sourceRoot":"","sources":["../../src/providers/IProvider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEzC;;;GAGG;AACH,uBAAe,SAAS;IACpB;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;gBAElB,EAAE,EAAE,MAAM;IAItB;;OAEG;IACH,IAAW,EAAE,IAAI,MAAM,CAEtB;IAED,kEAAkE;aAClD,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAE3F;;;;;OAKG;aACa,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CACxF;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
@@ -1,5 +1,5 @@
1
- import type { __internal__Options } from "../lib";
2
1
  import { type Session } from "../@types/globals";
2
+ import type { ConfigOptions } from "../@types/internals";
3
3
  /**
4
4
  * A strategy is used to handle the creation, validation and accessing a user's session.
5
5
  */
@@ -10,20 +10,20 @@ declare abstract class IStrategy {
10
10
  * @param globalCfg The global auth config.
11
11
  * @returns A newly generated token that will be sent as a cookie.
12
12
  */
13
- abstract serialize(session: Session, globalCfg: __internal__Options): Promise<string>;
13
+ abstract serialize(session: Session, globalCfg: ConfigOptions): Promise<string>;
14
14
  /**
15
15
  * Handles how a token is validated and deserialized into a session object.
16
16
  * @param token A user's token.
17
17
  * @param globalCfg The global auth config.
18
18
  * @returns A user's session if validated and found, else `null`.
19
19
  */
20
- abstract deserialize(token: string, globalCfg: __internal__Options): Promise<Session | null>;
20
+ abstract deserialize(token: string, globalCfg: ConfigOptions): Promise<Session | null>;
21
21
  /**
22
22
  * Handles how a session is destroyed when a user is logging out.
23
23
  * @param req The request object.
24
24
  * @param globalCfg The global auth config.
25
25
  */
26
- abstract logOut(req: Request, globalCfg: __internal__Options): Promise<void>;
26
+ abstract logOut(req: Request, globalCfg: ConfigOptions): Promise<void>;
27
27
  }
28
28
  export { IStrategy };
29
29
  //# sourceMappingURL=IStrategy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"IStrategy.d.ts","sourceRoot":"","sources":["../../src/strategies/IStrategy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD;;GAEG;AACH,uBAAe,SAAS;IACpB;;;;;OAKG;aACa,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC;IAE5F;;;;;OAKG;aACa,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAEnG;;;;OAIG;aACa,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;CACtF;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"IStrategy.d.ts","sourceRoot":"","sources":["../../src/strategies/IStrategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD;;GAEG;AACH,uBAAe,SAAS;IACpB;;;;;OAKG;aACa,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;IAEtF;;;;;OAKG;aACa,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAE7F;;;;OAIG;aACa,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;CAChF;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import { IStrategy } from "./IStrategy";
2
- import type { __internal__Options } from "../lib";
3
2
  import type { SignOptions } from "jsonwebtoken";
4
3
  import type { Session } from "../@types/globals";
4
+ import type { ConfigOptions } from "../@types/internals";
5
5
  /**
6
6
  * Basic JWT strategy
7
7
  */
@@ -11,8 +11,8 @@ declare class JWT extends IStrategy {
11
11
  */
12
12
  private signOptions;
13
13
  constructor(options?: SignOptions);
14
- serialize(session: Session, globalCfg: __internal__Options): Promise<string>;
15
- deserialize(token: string, globalCfg: __internal__Options): Promise<Session | null>;
14
+ serialize(session: Session, globalCfg: ConfigOptions): Promise<string>;
15
+ deserialize(token: string, globalCfg: ConfigOptions): Promise<Session | null>;
16
16
  logOut(): Promise<void>;
17
17
  }
18
18
  export { JWT };
@@ -1 +1 @@
1
- {"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../src/strategies/jwt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAElD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD;;GAEG;AACH,cAAM,GAAI,SAAQ,SAAS;IACvB;;OAEG;IACH,OAAO,CAAC,WAAW,CAAc;gBAErB,OAAO,GAAE,WAAiC;IAMtC,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC;IAK5E,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAKnF,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAI1C;AAED,OAAO,EAAE,GAAG,EAAE,CAAC"}
1
+ {"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../src/strategies/jwt.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAgBzD;;GAEG;AACH,cAAM,GAAI,SAAQ,SAAS;IACvB;;OAEG;IACH,OAAO,CAAC,WAAW,CAAc;gBAErB,OAAO,GAAE,WAAiC;IAMtC,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;IAKtE,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAK7E,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAI1C;AAED,OAAO,EAAE,GAAG,EAAE,CAAC"}
@@ -1,5 +1,18 @@
1
+ import { isString } from "lodash-es";
1
2
  import { IStrategy } from "./IStrategy";
2
3
  import { verify, sign } from "../functions/jwt";
4
+ /**
5
+ * Retrieves either the secret or a private key, depending on the used JWT algorithm
6
+ * @param secret Secret key, or key pair
7
+ * @returns The secret or private key
8
+ */
9
+ const secretOrPrivateKey = (secret) => isString(secret) ? secret : secret.privateKey;
10
+ /**
11
+ * Retrieves either the secret or a public key, depending on the used JWT algorithm
12
+ * @param secret Secret key, or key pair
13
+ * @returns The secret or public key
14
+ */
15
+ const secretOrPublicKey = (secret) => isString(secret) ? secret : secret.publicKey;
3
16
  /**
4
17
  * Basic JWT strategy
5
18
  */
@@ -14,11 +27,11 @@ class JWT extends IStrategy {
14
27
  }
15
28
  serialize(session, globalCfg) {
16
29
  // Directly call the sign function, but make it async.
17
- return Promise.resolve(sign(session, globalCfg.secret, this.signOptions));
30
+ return Promise.resolve(sign(session, secretOrPrivateKey(globalCfg.secret), this.signOptions));
18
31
  }
19
32
  deserialize(token, globalCfg) {
20
33
  // The verify function does everything for us, in this case.
21
- return verify(token, globalCfg.secret);
34
+ return verify(token, secretOrPublicKey(globalCfg.secret));
22
35
  }
23
36
  logOut() {
24
37
  // Since a JWT does not have any data in a DB, there is nothing to do here.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orange-auth",
3
- "version": "0.1.2",
3
+ "version": "1.0.0",
4
4
  "type": "module",
5
5
  "description": "Simple modular auth library",
6
6
  "main": "dist/index.js",
@@ -8,6 +8,16 @@
8
8
  "files": [
9
9
  "dist"
10
10
  ],
11
+ "exports": {
12
+ ".": {
13
+ "require": "./dist/index.js",
14
+ "default": "./dist/index.js",
15
+ "types": "./dist/index.d.ts"
16
+ },
17
+ "./strategies": "./dist/strategies/index.js",
18
+ "./providers": "./dist/providers/index.js",
19
+ "./functions": "./dist/functions/index.js"
20
+ },
11
21
  "scripts": {
12
22
  "build": "tsc"
13
23
  },