nextjs-hasura-auth 0.1.1 → 0.1.3
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/APOLLO.md +101 -174
- package/GENERATOR.md +4 -5
- package/README.md +9 -5
- package/dist/lib/apollo.d.ts +11 -9
- package/dist/lib/apollo.js +127 -90
- package/dist/lib/auth.d.ts +16 -0
- package/dist/lib/auth.js +159 -0
- package/dist/lib/authDbUtils.d.ts +48 -0
- package/dist/lib/authDbUtils.js +183 -0
- package/dist/lib/client.d.ts +81 -0
- package/dist/lib/client.js +353 -0
- package/dist/lib/email.d.ts +7 -0
- package/dist/lib/email.js +90 -0
- package/dist/lib/generator.d.ts +2 -7
- package/dist/lib/generator.js +394 -392
- package/dist/lib/graphql-proxy.d.ts +6 -0
- package/dist/lib/graphql-proxy.js +385 -0
- package/dist/lib/hasura-schema.d.ts +1 -0
- package/dist/lib/hasura-schema.js +65 -0
- package/dist/lib/hasura.d.ts +16 -0
- package/dist/lib/hasura.js +102 -0
- package/dist/lib/hooks/useCheckConnection.d.ts +7 -0
- package/dist/lib/hooks/useCheckConnection.js +62 -0
- package/dist/lib/index.d.ts +5 -0
- package/dist/lib/index.js +5 -0
- package/dist/lib/test-utils.d.ts +11 -0
- package/dist/lib/test-utils.js +59 -0
- package/dist/lib/tokenUtils.d.ts +14 -0
- package/dist/lib/tokenUtils.js +94 -0
- package/dist/package.json +22 -4
- package/dist/public/hasura-schema.json +7995 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/package.json +17 -6
package/dist/lib/apollo.js
CHANGED
@@ -12,52 +12,41 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
13
13
|
};
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
15
|
-
exports.
|
16
|
-
exports.
|
15
|
+
exports.CHECK_CONNECTION_QUERY = exports.CHECK_CONNECTION_SUBSCRIPTION = void 0;
|
16
|
+
exports.createApolloClient = createApolloClient;
|
17
17
|
exports.getClient = getClient;
|
18
|
-
exports.
|
18
|
+
exports.useCreateApolloClient = useCreateApolloClient;
|
19
19
|
exports.checkConnection = checkConnection;
|
20
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
20
21
|
const client_1 = require("@apollo/client");
|
21
22
|
const context_1 = require("@apollo/client/link/context");
|
22
23
|
const utilities_1 = require("@apollo/client/utilities");
|
24
|
+
// Restore GraphQLWsLink imports
|
23
25
|
const subscriptions_1 = require("@apollo/client/link/subscriptions");
|
24
26
|
const graphql_ws_1 = require("graphql-ws");
|
25
27
|
const cross_fetch_1 = __importDefault(require("cross-fetch"));
|
26
28
|
const debug_1 = __importDefault(require("./debug"));
|
27
29
|
const react_1 = require("react");
|
30
|
+
const jwt_1 = require("./jwt");
|
31
|
+
// Remove deprecated WebSocketLink import
|
32
|
+
// import { WebSocketLink } from '@apollo/client/link/ws';
|
33
|
+
const error_1 = require("@apollo/client/link/error");
|
28
34
|
// Create a debug logger for this module
|
29
35
|
const debug = (0, debug_1.default)('apollo');
|
30
36
|
// Determine if running on client
|
31
37
|
const isClient = typeof window !== 'undefined';
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
let secretKey;
|
41
|
-
try {
|
42
|
-
const jwtConfig = typeof jwtSecret === 'string' ? JSON.parse(jwtSecret) : jwtSecret;
|
43
|
-
secretKey = jwtConfig.key;
|
44
|
-
if (!secretKey) {
|
45
|
-
throw new Error('JWT key not found in configuration');
|
46
|
-
}
|
47
|
-
}
|
48
|
-
catch (e) {
|
49
|
-
// If failed to parse as JSON, use as string
|
50
|
-
secretKey = jwtSecret;
|
51
|
-
}
|
52
|
-
// Convert key to Uint8Array (required for jose)
|
53
|
-
return new TextEncoder().encode(secretKey);
|
54
|
-
}
|
55
|
-
catch (error) {
|
56
|
-
debug('apollo', '❌ Error getting JWT secret:', error);
|
57
|
-
throw error;
|
38
|
+
const createRoleLink = () => (0, context_1.setContext)((request, previousContext) => {
|
39
|
+
// Get the role from the operation's context passed in the hook options
|
40
|
+
const role = previousContext === null || previousContext === void 0 ? void 0 : previousContext.role; // Correctly access context via the second argument
|
41
|
+
debug(`roleLink: Role from context: ${role}`);
|
42
|
+
if (role) {
|
43
|
+
return {
|
44
|
+
headers: Object.assign(Object.assign({}, previousContext.headers), { 'X-Hasura-Role': role }),
|
45
|
+
};
|
58
46
|
}
|
59
|
-
|
60
|
-
|
47
|
+
// If no role is provided in the context, don't add the header
|
48
|
+
return {};
|
49
|
+
});
|
61
50
|
/**
|
62
51
|
* Create Apollo Client
|
63
52
|
*
|
@@ -67,81 +56,113 @@ exports.getJwtSecret = getJwtSecret;
|
|
67
56
|
* @param {string} options.secret - Admin secret for Hasura
|
68
57
|
* @returns {ApolloClient} Apollo Client
|
69
58
|
*/
|
70
|
-
function
|
59
|
+
function createApolloClient(options = {}) {
|
71
60
|
// Default values
|
72
61
|
const { url = process.env.NEXT_PUBLIC_HASURA_GRAPHQL_URL, ws = false, token = undefined, secret = process.env.HASURA_ADMIN_SECRET } = options;
|
73
62
|
if (!url) {
|
74
63
|
throw new Error('❌ options.url or NEXT_PUBLIC_HASURA_GRAPHQL_URL not defined');
|
75
64
|
}
|
76
65
|
debug('apollo', '🔌 Creating Apollo client with endpoint:', url);
|
77
|
-
//
|
78
|
-
const
|
66
|
+
// --- NEW: Link to set Hasura Role Header ---
|
67
|
+
const roleLink = createRoleLink();
|
68
|
+
// --- END NEW ---
|
69
|
+
// --- Existing Links ---
|
70
|
+
// Create base HttpLink (no auth here initially)
|
71
|
+
const baseHttpLink = new client_1.HttpLink({
|
79
72
|
uri: url,
|
80
73
|
fetch: cross_fetch_1.default,
|
81
74
|
});
|
82
|
-
// Create
|
83
|
-
const
|
84
|
-
|
75
|
+
// Create link for adding auth (JWT or Admin Secret)
|
76
|
+
const authHeaderLink = (0, context_1.setContext)((_, { headers }) => {
|
77
|
+
// Return the headers to the context so httpLink can read them
|
78
|
+
if (token) {
|
79
|
+
debug('apollo', '🔒 Using JWT token for Authorization header');
|
85
80
|
return {
|
86
81
|
headers: Object.assign(Object.assign({}, headers), { Authorization: `Bearer ${token}` })
|
87
82
|
};
|
88
|
-
})
|
89
|
-
: client_1.ApolloLink.from([]);
|
90
|
-
// Choose link based on token or secret availability
|
91
|
-
let httpLink;
|
92
|
-
if (token) {
|
93
|
-
// If token provided, use it for authorization
|
94
|
-
httpLink = client_1.ApolloLink.from([authLink, publicHttpLink]);
|
95
|
-
}
|
96
|
-
else if (secret) {
|
97
|
-
// If no token but admin secret exists, use it
|
98
|
-
httpLink = new client_1.HttpLink({
|
99
|
-
uri: url,
|
100
|
-
fetch: cross_fetch_1.default,
|
101
|
-
headers: {
|
102
|
-
'x-hasura-admin-secret': secret || ''
|
103
|
-
}
|
104
|
-
});
|
105
|
-
;
|
106
|
-
}
|
107
|
-
else {
|
108
|
-
// If neither token nor secret, use public access
|
109
|
-
httpLink = publicHttpLink;
|
110
|
-
}
|
111
|
-
// Create link splitter for queries
|
112
|
-
let splitLink = httpLink;
|
113
|
-
// If WebSocket connection needed and we're in browser
|
114
|
-
if (ws && isClient) {
|
115
|
-
const wsEndpoint = url.replace('http', 'ws').replace('https', 'wss');
|
116
|
-
// Configure connection parameters
|
117
|
-
const connectionParams = {};
|
118
|
-
if (token) {
|
119
|
-
// If token provided, use it for WebSocket authorization
|
120
|
-
connectionParams.headers = {
|
121
|
-
Authorization: `Bearer ${token}`,
|
122
|
-
};
|
123
83
|
}
|
124
84
|
else if (secret) {
|
125
|
-
|
126
|
-
|
127
|
-
'x-hasura-admin-secret': secret
|
85
|
+
debug('apollo', '🔑 Using Admin Secret for x-hasura-admin-secret header');
|
86
|
+
return {
|
87
|
+
headers: Object.assign(Object.assign({}, headers), { 'x-hasura-admin-secret': secret })
|
128
88
|
};
|
129
89
|
}
|
130
|
-
|
90
|
+
debug('apollo', '🔓 Sending request without authentication headers');
|
91
|
+
return { headers };
|
92
|
+
});
|
93
|
+
// Chain the links: roleLink -> authHeaderLink -> baseHttpLink
|
94
|
+
const httpLink = client_1.ApolloLink.from([roleLink, authHeaderLink, baseHttpLink]);
|
95
|
+
// --- End Existing Links Modification ---
|
96
|
+
// --- WebSocket Link Setup (Remains largely the same) ---
|
97
|
+
let link = httpLink; // Start with the combined HTTP link
|
98
|
+
// --- Debugging WS Link Creation ---
|
99
|
+
debug('apollo', `🚀 Checking WS setup: ws=${ws}, isClient=${isClient}`);
|
100
|
+
if (ws && isClient) {
|
101
|
+
debug('apollo', '✅ Entering WS Link creation block.'); // Log entry
|
102
|
+
const wsEndpoint = url.replace('http', 'ws').replace('https://', 'wss');
|
103
|
+
debug('apollo', '🔌 Setting up GraphQLWsLink for:', wsEndpoint);
|
104
|
+
// --- Restore GraphQLWsLink ---
|
131
105
|
const wsLink = new subscriptions_1.GraphQLWsLink((0, graphql_ws_1.createClient)({
|
132
106
|
url: wsEndpoint,
|
133
|
-
connectionParams: () =>
|
107
|
+
connectionParams: () => __awaiter(this, void 0, void 0, function* () {
|
108
|
+
debug('apollo', '⚙️ Evaluating connectionParams function...');
|
109
|
+
const params = {};
|
110
|
+
if (token) {
|
111
|
+
debug('apollo', '🔒 Using JWT token for WS connectionParams (from function)');
|
112
|
+
params.headers = { Authorization: `Bearer ${token}` };
|
113
|
+
}
|
114
|
+
else if (secret) {
|
115
|
+
debug('apollo', '🔑 Using Admin Secret for WS connectionParams (from function)');
|
116
|
+
params.headers = { 'x-hasura-admin-secret': secret };
|
117
|
+
}
|
118
|
+
else {
|
119
|
+
debug('apollo', '🔓 WebSocket connection without specific auth params (from function)');
|
120
|
+
}
|
121
|
+
debug('apollo', '⚙️ connectionParams function returning:', params);
|
122
|
+
return params;
|
123
|
+
}),
|
124
|
+
// Note: Dynamically changing headers per subscription via context
|
125
|
+
// is not standard in GraphQLWsLink. The roleLink above won't affect this.
|
126
|
+
// --- Add event handlers for diagnostics ---
|
127
|
+
on: {
|
128
|
+
connected: (socket) => debug('apollo', '🔗 [graphql-ws] WebSocket connected:', socket),
|
129
|
+
ping: (received) => debug('apollo', `➡️ [graphql-ws] Ping ${received ? 'received' : 'sent'}`),
|
130
|
+
pong: (received) => debug('apollo', `⬅️ [graphql-ws] Pong ${received ? 'received' : 'sent'}`),
|
131
|
+
error: (err) => debug('apollo', '❌ [graphql-ws] WebSocket error:', err),
|
132
|
+
closed: (event) => debug('apollo', '🚪 [graphql-ws] WebSocket closed:', event),
|
133
|
+
}
|
134
|
+
// --- End event handlers ---
|
134
135
|
}));
|
135
|
-
|
136
|
-
|
136
|
+
/* --- Remove Deprecated WebSocketLink ---
|
137
|
+
const wsLink = new WebSocketLink({
|
138
|
+
uri: wsEndpoint,
|
139
|
+
options: {
|
140
|
+
reconnect: true,
|
141
|
+
connectionParams: connectionParams, // Pass prepared headers here
|
142
|
+
// Note: Timeout options might be needed depending on env
|
143
|
+
}
|
144
|
+
});
|
145
|
+
debug('apollo', '🔗 DEPRECATED WebSocketLink created.');
|
146
|
+
*/
|
147
|
+
// Split based on operation type
|
148
|
+
link = (0, client_1.split)(({ query }) => {
|
137
149
|
const definition = (0, utilities_1.getMainDefinition)(query);
|
150
|
+
const isSubscription = definition.kind === 'OperationDefinition' &&
|
151
|
+
definition.operation === 'subscription';
|
152
|
+
debug('apollo', `🔗 Split link decision: isSubscription=${isSubscription}`);
|
138
153
|
return (definition.kind === 'OperationDefinition' &&
|
139
154
|
definition.operation === 'subscription');
|
140
|
-
}, wsLink,
|
155
|
+
}, wsLink, // Use wsLink for subscriptions
|
156
|
+
httpLink // Use httpLink (with roleLink and authHeaderLink) for query/mutation
|
157
|
+
);
|
158
|
+
}
|
159
|
+
else {
|
160
|
+
debug('apollo', '❌ Skipping WS Link creation.', { ws, isClient });
|
141
161
|
}
|
142
|
-
//
|
143
|
-
|
144
|
-
|
162
|
+
// --- End WebSocket Setup ---
|
163
|
+
// Create Apollo Client with the final composed link
|
164
|
+
const apolloClient = new client_1.ApolloClient({
|
165
|
+
link: link, // Use the potentially split link
|
145
166
|
cache: new client_1.InMemoryCache(),
|
146
167
|
defaultOptions: {
|
147
168
|
watchQuery: {
|
@@ -157,6 +178,10 @@ function createClient(options = {}) {
|
|
157
178
|
},
|
158
179
|
}
|
159
180
|
});
|
181
|
+
apolloClient.Provider = function Provider({ children }) {
|
182
|
+
return (0, jsx_runtime_1.jsx)(client_1.ApolloProvider, { client: apolloClient, children: children });
|
183
|
+
};
|
184
|
+
return apolloClient;
|
160
185
|
}
|
161
186
|
// Default client instance
|
162
187
|
let clientInstance = null;
|
@@ -167,7 +192,7 @@ let clientInstance = null;
|
|
167
192
|
*/
|
168
193
|
function getClient(options = {}) {
|
169
194
|
if (!clientInstance) {
|
170
|
-
clientInstance =
|
195
|
+
clientInstance = createApolloClient(options);
|
171
196
|
}
|
172
197
|
return clientInstance;
|
173
198
|
}
|
@@ -175,10 +200,19 @@ function getClient(options = {}) {
|
|
175
200
|
* React hook to get Apollo client instance
|
176
201
|
* @returns Apollo client instance
|
177
202
|
*/
|
178
|
-
function
|
179
|
-
return (0, react_1.useMemo)(() =>
|
203
|
+
function useCreateApolloClient(options) {
|
204
|
+
return (0, react_1.useMemo)(() => createApolloClient(options), [options]);
|
180
205
|
}
|
181
|
-
|
206
|
+
exports.CHECK_CONNECTION_SUBSCRIPTION = (0, client_1.gql) `
|
207
|
+
subscription CheckConnection {
|
208
|
+
__schema {
|
209
|
+
queryType {
|
210
|
+
name
|
211
|
+
}
|
212
|
+
}
|
213
|
+
}
|
214
|
+
`;
|
215
|
+
exports.CHECK_CONNECTION_QUERY = (0, client_1.gql) `
|
182
216
|
query CheckConnection {
|
183
217
|
__schema {
|
184
218
|
queryType {
|
@@ -194,13 +228,16 @@ query CheckConnection {
|
|
194
228
|
function checkConnection() {
|
195
229
|
return __awaiter(this, arguments, void 0, function* (client = getClient()) {
|
196
230
|
var _a, _b, _c;
|
197
|
-
const result = yield client.query({ query:
|
231
|
+
const result = yield client.query({ query: exports.CHECK_CONNECTION_QUERY });
|
198
232
|
return !!((_c = (_b = (_a = result.data) === null || _a === void 0 ? void 0 : _a.__schema) === null || _b === void 0 ? void 0 : _b.queryType) === null || _c === void 0 ? void 0 : _c.name);
|
199
233
|
});
|
200
234
|
}
|
235
|
+
const errorLink = (0, error_1.onError)(({ graphQLErrors, networkError, operation, forward }) => {
|
236
|
+
// Handle errors
|
237
|
+
});
|
201
238
|
exports.default = {
|
202
|
-
|
239
|
+
createApolloClient,
|
203
240
|
getClient,
|
204
|
-
getJwtSecret:
|
241
|
+
getJwtSecret: jwt_1.getJwtSecret,
|
205
242
|
checkConnection
|
206
243
|
};
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import { NextRequest } from "next/server";
|
2
|
+
import { IncomingMessage } from "http";
|
3
|
+
import { JWT } from 'next-auth/jwt';
|
4
|
+
import WebSocket from "ws";
|
5
|
+
export declare function getTokenFromRequest(request: NextRequest): Promise<JWT | null>;
|
6
|
+
export declare function WsClientsManager(route?: string): {
|
7
|
+
Client: (client: WebSocket) => string;
|
8
|
+
getToken(request: IncomingMessage, clientId: string): Promise<string | JWT | null>;
|
9
|
+
parseUser(request: IncomingMessage, clientId: string): Promise<any>;
|
10
|
+
delete(clientId: string): void;
|
11
|
+
getClient(clientId: string): {
|
12
|
+
ws: WebSocket;
|
13
|
+
userId?: string;
|
14
|
+
user?: any;
|
15
|
+
} | undefined;
|
16
|
+
};
|
package/dist/lib/auth.js
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
9
|
+
});
|
10
|
+
};
|
11
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
12
|
+
var t = {};
|
13
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
14
|
+
t[p] = s[p];
|
15
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
16
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
17
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
18
|
+
t[p[i]] = s[p[i]];
|
19
|
+
}
|
20
|
+
return t;
|
21
|
+
};
|
22
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
23
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
24
|
+
};
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
26
|
+
exports.getTokenFromRequest = getTokenFromRequest;
|
27
|
+
exports.WsClientsManager = WsClientsManager;
|
28
|
+
const debug_1 = __importDefault(require("@/lib/debug"));
|
29
|
+
const jwt_1 = require("next-auth/jwt");
|
30
|
+
const uuid_1 = require("uuid");
|
31
|
+
const debug = (0, debug_1.default)('auth');
|
32
|
+
function getTokenFromRequest(request) {
|
33
|
+
return __awaiter(this, void 0, void 0, function* () {
|
34
|
+
const secureCookie = request.url.startsWith('https');
|
35
|
+
const cookieName = secureCookie
|
36
|
+
? '__Secure-next-auth.session-token'
|
37
|
+
: 'next-auth.session-token';
|
38
|
+
debug(`GET /api/auth: Using cookie name: ${cookieName}, secure: ${secureCookie}`);
|
39
|
+
const token = yield (0, jwt_1.getToken)({
|
40
|
+
req: request, // Cast to any to satisfy getToken, NextRequest works
|
41
|
+
secret: process.env.NEXTAUTH_SECRET,
|
42
|
+
cookieName: cookieName,
|
43
|
+
});
|
44
|
+
return token;
|
45
|
+
});
|
46
|
+
}
|
47
|
+
function WsClientsManager(route = '') {
|
48
|
+
const clientManagerId = route + (0, uuid_1.v4)();
|
49
|
+
debug(`(${clientManagerId}): New WebSocket clients manager established.`);
|
50
|
+
const clients = new Map();
|
51
|
+
return {
|
52
|
+
Client: (client) => {
|
53
|
+
const clientId = (0, uuid_1.v4)();
|
54
|
+
clients.set(clientId, { ws: client });
|
55
|
+
debug(`(${clientManagerId}): New client (${clientId}) connected.`);
|
56
|
+
return clientId;
|
57
|
+
},
|
58
|
+
getToken(request, clientId) {
|
59
|
+
return __awaiter(this, void 0, void 0, function* () {
|
60
|
+
var _a;
|
61
|
+
const cookieHeader = request.headers.cookie;
|
62
|
+
const userAgent = request.headers['user-agent'];
|
63
|
+
const forwardedProto = request.headers['x-forwarded-proto'];
|
64
|
+
const connectionEncrypted = (_a = request.connection) === null || _a === void 0 ? void 0 : _a.encrypted;
|
65
|
+
debug(`${clientManagerId}: (${clientId}): Incoming request details - URL: ${request.url}, Method: ${request.method}, User-Agent: ${userAgent}`);
|
66
|
+
debug(`${clientManagerId}: (${clientId}): Incoming headers:`, request.headers);
|
67
|
+
debug(`${clientManagerId}: (${clientId}): Connection encrypted: ${connectionEncrypted}`);
|
68
|
+
debug(`${clientManagerId}: (${clientId}): X-Forwarded-Proto: ${forwardedProto}`);
|
69
|
+
debug(`${clientManagerId}: (${clientId}): Full cookie header:`, cookieHeader || 'No cookies header');
|
70
|
+
// Determine secure context and cookie name
|
71
|
+
const isSecure = forwardedProto === 'https' || connectionEncrypted;
|
72
|
+
const sessionCookieName = isSecure
|
73
|
+
? '__Secure-next-auth.session-token'
|
74
|
+
: 'next-auth.session-token';
|
75
|
+
debug(`${clientManagerId}: (${clientId}): Determined secure context: ${isSecure}`);
|
76
|
+
debug(`${clientManagerId}: (${clientId}): Expecting session cookie name: ${sessionCookieName}`);
|
77
|
+
let token = null;
|
78
|
+
let payload = null;
|
79
|
+
let userId = null;
|
80
|
+
const rawToken = false; // Keep false
|
81
|
+
try {
|
82
|
+
debug(`SOCKET /api/auth (${clientId}): Preparing adapted request for getToken (raw: ${rawToken})...`);
|
83
|
+
const parsedCookies = request.headers.cookie ?
|
84
|
+
Object.fromEntries(request.headers.cookie.split('; ').map(c => {
|
85
|
+
const [key, ...val] = c.split('=');
|
86
|
+
return [key, decodeURIComponent(val.join('='))];
|
87
|
+
}))
|
88
|
+
: {};
|
89
|
+
debug(`SOCKET /api/auth (${clientId}): Parsed cookies object:`, parsedCookies);
|
90
|
+
const adaptedReq = {
|
91
|
+
headers: request.headers,
|
92
|
+
cookies: parsedCookies,
|
93
|
+
url: request.url || '',
|
94
|
+
method: request.method || 'GET',
|
95
|
+
};
|
96
|
+
debug(`SOCKET /api/auth (${clientId}): Final adapted request object for getToken:`, adaptedReq);
|
97
|
+
const getTokenParams = {
|
98
|
+
req: adaptedReq,
|
99
|
+
secret: process.env.NEXTAUTH_SECRET,
|
100
|
+
cookieName: sessionCookieName,
|
101
|
+
raw: rawToken, // Should be false now
|
102
|
+
};
|
103
|
+
debug(`${clientManagerId}: (${clientId}): Calling getToken with params:`, {
|
104
|
+
cookieName: getTokenParams.cookieName,
|
105
|
+
raw: getTokenParams.raw,
|
106
|
+
secretProvided: !!getTokenParams.secret,
|
107
|
+
});
|
108
|
+
token = yield (0, jwt_1.getToken)(getTokenParams);
|
109
|
+
debug(`${clientManagerId}: (${clientId}): getToken result received.`);
|
110
|
+
debug(`${clientManagerId}: (${clientId}): Decoded token value from getToken:`, token);
|
111
|
+
debug(`${clientManagerId}: (${clientId}): getToken result type: ${typeof token}, isNull: ${token === null}`);
|
112
|
+
if (token && typeof token === 'object' && token.sub) {
|
113
|
+
payload = token;
|
114
|
+
userId = payload.sub;
|
115
|
+
debug(`${clientManagerId}: (${clientId}): User ${userId} authenticated via decoded token from getToken.`);
|
116
|
+
}
|
117
|
+
else {
|
118
|
+
debug(`${clientManagerId}: (${clientId}): No valid token found or token is not an object with sub property.`);
|
119
|
+
}
|
120
|
+
return token;
|
121
|
+
}
|
122
|
+
catch (error) {
|
123
|
+
debug(`${clientManagerId}: (${clientId}): Error preparing adapted request for getToken:`, error);
|
124
|
+
throw error;
|
125
|
+
}
|
126
|
+
});
|
127
|
+
},
|
128
|
+
parseUser(request, clientId) {
|
129
|
+
return __awaiter(this, void 0, void 0, function* () {
|
130
|
+
const token = yield this.getToken(request, clientId);
|
131
|
+
if (token && typeof token === 'object' && token.sub) {
|
132
|
+
const _a = token, { accessToken } = _a, user = __rest(_a, ["accessToken"]);
|
133
|
+
const client = clients.get(clientId);
|
134
|
+
if (client) {
|
135
|
+
client.userId = token.sub;
|
136
|
+
client.user = user;
|
137
|
+
clients.set(clientId, client);
|
138
|
+
debug(`${clientManagerId}: (${clientId}): Client parsed and updated.`);
|
139
|
+
}
|
140
|
+
else {
|
141
|
+
debug(`${clientManagerId}: (${clientId}): No client found in clients map.`);
|
142
|
+
}
|
143
|
+
return user;
|
144
|
+
}
|
145
|
+
else {
|
146
|
+
debug(`${clientManagerId}: (${clientId}): No valid token found or token is not an object with sub property.`);
|
147
|
+
}
|
148
|
+
return null;
|
149
|
+
});
|
150
|
+
},
|
151
|
+
delete(clientId) {
|
152
|
+
clients.delete(clientId);
|
153
|
+
debug(`${clientManagerId}: (${clientId}): Client deleted from clients map.`);
|
154
|
+
},
|
155
|
+
getClient(clientId) {
|
156
|
+
return clients.get(clientId);
|
157
|
+
}
|
158
|
+
};
|
159
|
+
}
|
@@ -0,0 +1,48 @@
|
|
1
|
+
import { Client } from 'nextjs-hasura-auth';
|
2
|
+
/**
|
3
|
+
* Hashes a password using bcrypt.
|
4
|
+
* @param password The plain text password.
|
5
|
+
* @returns The hashed password.
|
6
|
+
*/
|
7
|
+
export declare function hashPassword(password: string): Promise<string>;
|
8
|
+
/**
|
9
|
+
* Compares a plain text password with a hash.
|
10
|
+
* @param password The plain text password.
|
11
|
+
* @param hash The hash to compare against.
|
12
|
+
* @returns True if the password matches the hash, false otherwise.
|
13
|
+
*/
|
14
|
+
export declare function comparePassword(password: string, hash: string): Promise<boolean>;
|
15
|
+
interface UserProfileFromProvider {
|
16
|
+
name?: string | null;
|
17
|
+
email?: string | null;
|
18
|
+
image?: string | null;
|
19
|
+
}
|
20
|
+
export interface HasuraUser {
|
21
|
+
id: string;
|
22
|
+
name?: string | null;
|
23
|
+
email?: string | null;
|
24
|
+
email_verified?: string | null;
|
25
|
+
image?: string | null;
|
26
|
+
password?: string | null;
|
27
|
+
created_at: string;
|
28
|
+
updated_at: string;
|
29
|
+
is_admin?: boolean | null;
|
30
|
+
hasura_role?: string | null;
|
31
|
+
accounts?: {
|
32
|
+
provider: string;
|
33
|
+
provider_account_id: string;
|
34
|
+
}[];
|
35
|
+
}
|
36
|
+
/**
|
37
|
+
* Finds or creates a user and their associated account based on provider information.
|
38
|
+
* This function handles the core logic of linking OAuth/Credentials logins to Hasura users.
|
39
|
+
*
|
40
|
+
* @param client The initialized NHA Client instance.
|
41
|
+
* @param provider The OAuth provider name (e.g., 'google', 'credentials').
|
42
|
+
* @param providerAccountId The user's unique ID from the provider.
|
43
|
+
* @param profile Optional profile information from the provider (name, email, image).
|
44
|
+
* @returns The Hasura user object associated with the account.
|
45
|
+
* @throws Error if user/account processing fails.
|
46
|
+
*/
|
47
|
+
export declare function getOrCreateUserAndAccount(client: Client, provider: string, providerAccountId: string, profile?: UserProfileFromProvider | null): Promise<HasuraUser>;
|
48
|
+
export {};
|