@augmenting-integrations/auth 0.1.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Augmenting Integrations LLC
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.
@@ -0,0 +1,65 @@
1
+ import { type DefaultSession } from "next-auth";
2
+ export type Role = "visitor" | "sales" | "agent" | "admin";
3
+ declare module "next-auth" {
4
+ interface Session {
5
+ user: {
6
+ role: Role;
7
+ } & DefaultSession["user"];
8
+ }
9
+ interface User {
10
+ role: Role;
11
+ }
12
+ }
13
+ export type CreateAuthOptions = {
14
+ /**
15
+ * Path prefixes that require an authenticated session.
16
+ * Empty array = no gating (rare).
17
+ */
18
+ authedRoutePrefixes: string[];
19
+ /**
20
+ * Page to redirect to when an unauthed user hits a gated route. Can be a
21
+ * relative path (`"/login"`) for in-app login, or a fully-qualified URL
22
+ * (`"https://compass.aillc.link/login"`) to delegate login to a peer app
23
+ * on a sibling subdomain. Default: `/login`.
24
+ */
25
+ signInPage?: string;
26
+ /**
27
+ * Cookie domain for the session token. Set this to the parent domain
28
+ * (e.g. `.compass.aillc.link`) when running across multiple subdomains
29
+ * so the session JWT is readable by every app sharing that parent.
30
+ * Default: read from `process.env.AUTH_COOKIE_DOMAIN`; if unset, Auth.js
31
+ * defaults to host-only (current request hostname).
32
+ *
33
+ * In dev (NODE_ENV !== "production"), this is ignored — cookies stay
34
+ * scoped to localhost so per-port apps don't collide.
35
+ */
36
+ cookieDomain?: string;
37
+ /**
38
+ * Override prod/dev detection. Default reads NODE_ENV.
39
+ */
40
+ isProd?: boolean;
41
+ };
42
+ /**
43
+ * Build an Auth.js v5 NextAuth() invocation. Each consuming app calls this
44
+ * once at module scope and re-exports the returned `handlers`, `auth`,
45
+ * `signIn`, `signOut`.
46
+ *
47
+ * Cognito creds are read from process.env (typically set from SSM at deploy):
48
+ * AUTH_COGNITO_ID, AUTH_COGNITO_SECRET, AUTH_COGNITO_ISSUER, AUTH_SECRET
49
+ */
50
+ export declare function createAuth(opts: CreateAuthOptions): import("next-auth").NextAuthResult;
51
+ /**
52
+ * Convenience: build the proxy default-export for `src/proxy.ts`. In Next 16
53
+ * the proxy must be a default export and must live at `src/proxy.ts` — the
54
+ * named-export form throws "TypeError: adapterFn is not a function".
55
+ *
56
+ * Usage:
57
+ * // src/proxy.ts
58
+ * import { auth } from "@/lib/auth";
59
+ * export default auth;
60
+ * export const config = {
61
+ * matcher: ["/dashboard", "/dashboard/:path*"],
62
+ * };
63
+ */
64
+ export type { NextAuthConfig } from "next-auth";
65
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAiB,EAAE,KAAK,cAAc,EAAuB,MAAM,WAAW,CAAC;AAI/E,MAAM,MAAM,IAAI,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AAI3D,OAAO,QAAQ,WAAW,CAAC;IACzB,UAAU,OAAO;QACf,IAAI,EAAE;YACJ,IAAI,EAAE,IAAI,CAAC;SACZ,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;KAC5B;IACD,UAAU,IAAI;QACZ,IAAI,EAAE,IAAI,CAAC;KACZ;CACF;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;OAGG;IACH,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAUF;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,iBAAiB,sCAoGjD;AAED;;;;;;;;;;;;GAYG;AACH,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,130 @@
1
+ // Auth.js v5 (the package is still distributed as `next-auth`, but treat
2
+ // these as Auth.js v5 internally — docs at https://authjs.dev, NOT
3
+ // next-auth.js.org which is v4 and incompatible).
4
+ //
5
+ // Provider strategy:
6
+ // - Production: Cognito OIDC. Group membership from `cognito:groups`
7
+ // drives role.
8
+ // - Dev / preview: Credentials with a role picker, BUT shaped to mirror
9
+ // Cognito's claim payload so consumers (callbacks, gates, audit logs)
10
+ // never branch on environment. Same `sub`, `email`, `cognito:groups`
11
+ // in both modes.
12
+ //
13
+ // IMPORTANT: do not let the dev-mode session diverge from production. If
14
+ // you add a claim in prod, also add it (with a synthetic value) in dev.
15
+ import NextAuth from "next-auth";
16
+ import Credentials from "next-auth/providers/credentials";
17
+ import Cognito from "next-auth/providers/cognito";
18
+ const VALID_ROLES = ["visitor", "sales", "agent", "admin"];
19
+ function roleFromGroups(groups) {
20
+ if (Array.isArray(groups) && groups.length > 0) {
21
+ const first = String(groups[0]).toLowerCase();
22
+ if (VALID_ROLES.includes(first))
23
+ return first;
24
+ }
25
+ return "visitor";
26
+ }
27
+ /**
28
+ * Build an Auth.js v5 NextAuth() invocation. Each consuming app calls this
29
+ * once at module scope and re-exports the returned `handlers`, `auth`,
30
+ * `signIn`, `signOut`.
31
+ *
32
+ * Cognito creds are read from process.env (typically set from SSM at deploy):
33
+ * AUTH_COGNITO_ID, AUTH_COGNITO_SECRET, AUTH_COGNITO_ISSUER, AUTH_SECRET
34
+ */
35
+ export function createAuth(opts) {
36
+ const isProd = opts.isProd ?? process.env.NODE_ENV === "production";
37
+ const signInPage = opts.signInPage ?? "/login";
38
+ // Cookie domain is only honored in production. In dev, leaving it unset
39
+ // keeps the cookie scoped to localhost so apps on different ports don't
40
+ // stomp on each other.
41
+ const cookieDomain = isProd
42
+ ? (opts.cookieDomain ?? process.env.AUTH_COOKIE_DOMAIN)
43
+ : undefined;
44
+ const SECRET = process.env.AUTH_SECRET ?? (isProd ? undefined : "dev-only-fallback-not-for-prod");
45
+ const config = {
46
+ secret: SECRET,
47
+ cookies: cookieDomain
48
+ ? {
49
+ sessionToken: {
50
+ name: "authjs.session-token",
51
+ options: {
52
+ domain: cookieDomain,
53
+ sameSite: "lax",
54
+ secure: true,
55
+ httpOnly: true,
56
+ path: "/",
57
+ },
58
+ },
59
+ }
60
+ : undefined,
61
+ providers: isProd
62
+ ? [
63
+ Cognito({
64
+ clientId: process.env.AUTH_COGNITO_ID,
65
+ clientSecret: process.env.AUTH_COGNITO_SECRET,
66
+ issuer: process.env.AUTH_COGNITO_ISSUER,
67
+ }),
68
+ ]
69
+ : [
70
+ Credentials({
71
+ name: "Mock role (dev only)",
72
+ credentials: {
73
+ role: {
74
+ label: "Role",
75
+ type: "text",
76
+ placeholder: "visitor | sales | agent | admin",
77
+ },
78
+ },
79
+ authorize: async (credentials) => {
80
+ const role = credentials?.role;
81
+ if (!role || !VALID_ROLES.includes(role))
82
+ return null;
83
+ const display = role.charAt(0).toUpperCase() + role.slice(1);
84
+ return {
85
+ id: `mock-${role}`,
86
+ name: `${display} (mock)`,
87
+ email: `${role}@example.local`,
88
+ role,
89
+ };
90
+ },
91
+ }),
92
+ ],
93
+ session: { strategy: "jwt" },
94
+ callbacks: {
95
+ jwt: ({ token, user, profile }) => {
96
+ if (user) {
97
+ token.sub ??= user.id ?? undefined;
98
+ token.email ??= user.email ?? undefined;
99
+ if (!isProd && user.role) {
100
+ token["cognito:groups"] = [
101
+ user.role,
102
+ ];
103
+ }
104
+ }
105
+ if (isProd && profile) {
106
+ const groups = profile["cognito:groups"];
107
+ if (groups) {
108
+ token["cognito:groups"] = groups;
109
+ }
110
+ }
111
+ return token;
112
+ },
113
+ session: ({ session, token }) => {
114
+ session.user.role = roleFromGroups(token["cognito:groups"]);
115
+ return session;
116
+ },
117
+ authorized: ({ auth: session, request: { nextUrl } }) => {
118
+ const path = nextUrl.pathname;
119
+ const isAuthedRoute = opts.authedRoutePrefixes.some((prefix) => path === prefix || path.startsWith(`${prefix}/`));
120
+ if (!session && isAuthedRoute)
121
+ return false;
122
+ return true;
123
+ },
124
+ },
125
+ pages: { signIn: signInPage },
126
+ trustHost: true,
127
+ };
128
+ return NextAuth(config);
129
+ }
130
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.mjs ADDED
@@ -0,0 +1,104 @@
1
+ // src/index.ts
2
+ import NextAuth from "next-auth";
3
+ import Credentials from "next-auth/providers/credentials";
4
+ import Cognito from "next-auth/providers/cognito";
5
+ var VALID_ROLES = ["visitor", "sales", "agent", "admin"];
6
+ function roleFromGroups(groups) {
7
+ if (Array.isArray(groups) && groups.length > 0) {
8
+ const first = String(groups[0]).toLowerCase();
9
+ if (VALID_ROLES.includes(first)) return first;
10
+ }
11
+ return "visitor";
12
+ }
13
+ function createAuth(opts) {
14
+ const isProd = opts.isProd ?? process.env.NODE_ENV === "production";
15
+ const signInPage = opts.signInPage ?? "/login";
16
+ const cookieDomain = isProd ? opts.cookieDomain ?? process.env.AUTH_COOKIE_DOMAIN : void 0;
17
+ const SECRET = process.env.AUTH_SECRET ?? (isProd ? void 0 : "dev-only-fallback-not-for-prod");
18
+ const config = {
19
+ secret: SECRET,
20
+ cookies: cookieDomain ? {
21
+ sessionToken: {
22
+ name: "authjs.session-token",
23
+ options: {
24
+ domain: cookieDomain,
25
+ sameSite: "lax",
26
+ secure: true,
27
+ httpOnly: true,
28
+ path: "/"
29
+ }
30
+ }
31
+ } : void 0,
32
+ providers: isProd ? [
33
+ Cognito({
34
+ clientId: process.env.AUTH_COGNITO_ID,
35
+ clientSecret: process.env.AUTH_COGNITO_SECRET,
36
+ issuer: process.env.AUTH_COGNITO_ISSUER
37
+ })
38
+ ] : [
39
+ Credentials({
40
+ name: "Mock role (dev only)",
41
+ credentials: {
42
+ role: {
43
+ label: "Role",
44
+ type: "text",
45
+ placeholder: "visitor | sales | agent | admin"
46
+ }
47
+ },
48
+ authorize: async (credentials) => {
49
+ const role = credentials?.role;
50
+ if (!role || !VALID_ROLES.includes(role)) return null;
51
+ const display = role.charAt(0).toUpperCase() + role.slice(1);
52
+ return {
53
+ id: `mock-${role}`,
54
+ name: `${display} (mock)`,
55
+ email: `${role}@example.local`,
56
+ role
57
+ };
58
+ }
59
+ })
60
+ ],
61
+ session: { strategy: "jwt" },
62
+ callbacks: {
63
+ jwt: ({ token, user, profile }) => {
64
+ if (user) {
65
+ token.sub ??= user.id ?? void 0;
66
+ token.email ??= user.email ?? void 0;
67
+ if (!isProd && user.role) {
68
+ token["cognito:groups"] = [
69
+ user.role
70
+ ];
71
+ }
72
+ }
73
+ if (isProd && profile) {
74
+ const groups = profile["cognito:groups"];
75
+ if (groups) {
76
+ token["cognito:groups"] = groups;
77
+ }
78
+ }
79
+ return token;
80
+ },
81
+ session: ({ session, token }) => {
82
+ session.user.role = roleFromGroups(
83
+ token["cognito:groups"]
84
+ );
85
+ return session;
86
+ },
87
+ authorized: ({ auth: session, request: { nextUrl } }) => {
88
+ const path = nextUrl.pathname;
89
+ const isAuthedRoute = opts.authedRoutePrefixes.some(
90
+ (prefix) => path === prefix || path.startsWith(`${prefix}/`)
91
+ );
92
+ if (!session && isAuthedRoute) return false;
93
+ return true;
94
+ }
95
+ },
96
+ pages: { signIn: signInPage },
97
+ trustHost: true
98
+ };
99
+ return NextAuth(config);
100
+ }
101
+ export {
102
+ createAuth
103
+ };
104
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Auth.js v5 (the package is still distributed as `next-auth`, but treat\n// these as Auth.js v5 internally — docs at https://authjs.dev, NOT\n// next-auth.js.org which is v4 and incompatible).\n//\n// Provider strategy:\n// - Production: Cognito OIDC. Group membership from `cognito:groups`\n// drives role.\n// - Dev / preview: Credentials with a role picker, BUT shaped to mirror\n// Cognito's claim payload so consumers (callbacks, gates, audit logs)\n// never branch on environment. Same `sub`, `email`, `cognito:groups`\n// in both modes.\n//\n// IMPORTANT: do not let the dev-mode session diverge from production. If\n// you add a claim in prod, also add it (with a synthetic value) in dev.\n\nimport NextAuth, { type DefaultSession, type NextAuthConfig } from \"next-auth\";\nimport Credentials from \"next-auth/providers/credentials\";\nimport Cognito from \"next-auth/providers/cognito\";\n\nexport type Role = \"visitor\" | \"sales\" | \"agent\" | \"admin\";\n\nconst VALID_ROLES: Role[] = [\"visitor\", \"sales\", \"agent\", \"admin\"];\n\ndeclare module \"next-auth\" {\n interface Session {\n user: {\n role: Role;\n } & DefaultSession[\"user\"];\n }\n interface User {\n role: Role;\n }\n}\n\nexport type CreateAuthOptions = {\n /**\n * Path prefixes that require an authenticated session.\n * Empty array = no gating (rare).\n */\n authedRoutePrefixes: string[];\n /**\n * Page to redirect to when an unauthed user hits a gated route. Can be a\n * relative path (`\"/login\"`) for in-app login, or a fully-qualified URL\n * (`\"https://compass.aillc.link/login\"`) to delegate login to a peer app\n * on a sibling subdomain. Default: `/login`.\n */\n signInPage?: string;\n /**\n * Cookie domain for the session token. Set this to the parent domain\n * (e.g. `.compass.aillc.link`) when running across multiple subdomains\n * so the session JWT is readable by every app sharing that parent.\n * Default: read from `process.env.AUTH_COOKIE_DOMAIN`; if unset, Auth.js\n * defaults to host-only (current request hostname).\n *\n * In dev (NODE_ENV !== \"production\"), this is ignored — cookies stay\n * scoped to localhost so per-port apps don't collide.\n */\n cookieDomain?: string;\n /**\n * Override prod/dev detection. Default reads NODE_ENV.\n */\n isProd?: boolean;\n};\n\nfunction roleFromGroups(groups: unknown): Role {\n if (Array.isArray(groups) && groups.length > 0) {\n const first = String(groups[0]).toLowerCase();\n if ((VALID_ROLES as string[]).includes(first)) return first as Role;\n }\n return \"visitor\";\n}\n\n/**\n * Build an Auth.js v5 NextAuth() invocation. Each consuming app calls this\n * once at module scope and re-exports the returned `handlers`, `auth`,\n * `signIn`, `signOut`.\n *\n * Cognito creds are read from process.env (typically set from SSM at deploy):\n * AUTH_COGNITO_ID, AUTH_COGNITO_SECRET, AUTH_COGNITO_ISSUER, AUTH_SECRET\n */\nexport function createAuth(opts: CreateAuthOptions) {\n const isProd = opts.isProd ?? process.env.NODE_ENV === \"production\";\n const signInPage = opts.signInPage ?? \"/login\";\n // Cookie domain is only honored in production. In dev, leaving it unset\n // keeps the cookie scoped to localhost so apps on different ports don't\n // stomp on each other.\n const cookieDomain = isProd\n ? (opts.cookieDomain ?? process.env.AUTH_COOKIE_DOMAIN)\n : undefined;\n\n const SECRET =\n process.env.AUTH_SECRET ?? (isProd ? undefined : \"dev-only-fallback-not-for-prod\");\n\n const config: NextAuthConfig = {\n secret: SECRET,\n cookies: cookieDomain\n ? {\n sessionToken: {\n name: \"authjs.session-token\",\n options: {\n domain: cookieDomain,\n sameSite: \"lax\",\n secure: true,\n httpOnly: true,\n path: \"/\",\n },\n },\n }\n : undefined,\n providers: isProd\n ? [\n Cognito({\n clientId: process.env.AUTH_COGNITO_ID,\n clientSecret: process.env.AUTH_COGNITO_SECRET,\n issuer: process.env.AUTH_COGNITO_ISSUER,\n }),\n ]\n : [\n Credentials({\n name: \"Mock role (dev only)\",\n credentials: {\n role: {\n label: \"Role\",\n type: \"text\",\n placeholder: \"visitor | sales | agent | admin\",\n },\n },\n authorize: async (credentials) => {\n const role = credentials?.role as Role | undefined;\n if (!role || !VALID_ROLES.includes(role)) return null;\n const display = role.charAt(0).toUpperCase() + role.slice(1);\n return {\n id: `mock-${role}`,\n name: `${display} (mock)`,\n email: `${role}@example.local`,\n role,\n };\n },\n }),\n ],\n session: { strategy: \"jwt\" },\n callbacks: {\n jwt: ({ token, user, profile }) => {\n if (user) {\n token.sub ??= user.id ?? undefined;\n token.email ??= user.email ?? undefined;\n if (!isProd && (user as { role?: Role }).role) {\n (token as Record<string, unknown>)[\"cognito:groups\"] = [\n (user as { role: Role }).role,\n ];\n }\n }\n if (isProd && profile) {\n const groups = (profile as Record<string, unknown>)[\"cognito:groups\"];\n if (groups) {\n (token as Record<string, unknown>)[\"cognito:groups\"] = groups;\n }\n }\n return token;\n },\n session: ({ session, token }) => {\n session.user.role = roleFromGroups(\n (token as Record<string, unknown>)[\"cognito:groups\"],\n );\n return session;\n },\n authorized: ({ auth: session, request: { nextUrl } }) => {\n const path = nextUrl.pathname;\n const isAuthedRoute = opts.authedRoutePrefixes.some(\n (prefix) => path === prefix || path.startsWith(`${prefix}/`),\n );\n if (!session && isAuthedRoute) return false;\n return true;\n },\n },\n pages: { signIn: signInPage },\n trustHost: true,\n };\n\n return NextAuth(config);\n}\n\n/**\n * Convenience: build the proxy default-export for `src/proxy.ts`. In Next 16\n * the proxy must be a default export and must live at `src/proxy.ts` — the\n * named-export form throws \"TypeError: adapterFn is not a function\".\n *\n * Usage:\n * // src/proxy.ts\n * import { auth } from \"@/lib/auth\";\n * export default auth;\n * export const config = {\n * matcher: [\"/dashboard\", \"/dashboard/:path*\"],\n * };\n */\nexport type { NextAuthConfig } from \"next-auth\";\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@augmenting-integrations/auth",
3
+ "version": "0.1.0",
4
+ "description": "Auth.js v5 factory: Cognito in prod, Credentials role-picker in dev. Same JWT shape (sub, email, cognito:groups) regardless of provider.",
5
+ "license": "MIT",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "sideEffects": false,
10
+ "main": "./dist/index.cjs",
11
+ "module": "./dist/index.js",
12
+ "types": "./dist/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "import": "./dist/index.js",
17
+ "require": "./dist/index.cjs"
18
+ }
19
+ },
20
+ "files": [
21
+ "dist",
22
+ "README.md"
23
+ ],
24
+ "peerDependencies": {
25
+ "next": "^16.0.0",
26
+ "next-auth": "^5.0.0-beta.31",
27
+ "react": "^19.0.0"
28
+ },
29
+ "devDependencies": {
30
+ "next": "^16.2.5",
31
+ "next-auth": "^5.0.0-beta.31",
32
+ "react": "^19.0.0",
33
+ "tsup": "^8.3.5",
34
+ "typescript": "^5.7.2",
35
+ "vitest": "^4.1.5"
36
+ },
37
+ "scripts": {
38
+ "build": "tsup",
39
+ "clean": "rm -rf dist",
40
+ "test": "vitest run --passWithNoTests"
41
+ }
42
+ }