@solvapay/auth 1.0.0-preview.8 → 1.0.1-preview.1
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.md +21 -0
- package/README.md +147 -33
- package/dist/adapter-Lx7F0MH7.d.cts +64 -0
- package/dist/adapter-Lx7F0MH7.d.ts +64 -0
- package/dist/{chunk-B4VVTQWS.js → chunk-IOLE5BMD.js} +6 -8
- package/dist/index.cjs +129 -8
- package/dist/index.d.cts +68 -1
- package/dist/index.d.ts +68 -1
- package/dist/index.js +122 -1
- package/dist/mock.d.cts +1 -1
- package/dist/mock.d.ts +1 -1
- package/dist/next-utils.cjs +6 -8
- package/dist/next-utils.d.cts +91 -16
- package/dist/next-utils.d.ts +91 -16
- package/dist/next-utils.js +1 -1
- package/dist/supabase.d.cts +1 -1
- package/dist/supabase.d.ts +1 -1
- package/package.json +6 -5
- package/dist/adapter-4HTpALyc.d.cts +0 -32
- package/dist/adapter-4HTpALyc.d.ts +0 -32
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,70 @@
|
|
|
1
|
-
|
|
1
|
+
import { A as AuthAdapter, R as RequestLike } from './adapter-Lx7F0MH7.js';
|
|
2
2
|
export { MockAuthAdapter, MockAuthAdapter as MockAuthAdapterType } from './mock.js';
|
|
3
3
|
export { getUserEmailFromRequest, getUserIdFromRequest, getUserNameFromRequest, requireUserId } from './next-utils.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* SolvaPay Auth Adapter
|
|
7
|
+
*
|
|
8
|
+
* Validates SolvaPay OAuth tokens by calling the userinfo endpoint.
|
|
9
|
+
* Suitable for validating opaque tokens issued by SolvaPay's hosted OAuth service.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
interface SolvapayAuthAdapterConfig {
|
|
13
|
+
/**
|
|
14
|
+
* SolvaPay API Base URL (e.g. https://api.solvapay.com)
|
|
15
|
+
*/
|
|
16
|
+
apiBaseUrl: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* SolvaPay authentication adapter
|
|
20
|
+
*
|
|
21
|
+
* Validates tokens by calling the SolvaPay userinfo endpoint.
|
|
22
|
+
* This is required for opaque tokens which cannot be verified offline.
|
|
23
|
+
*/
|
|
24
|
+
declare class SolvapayAuthAdapter implements AuthAdapter {
|
|
25
|
+
private apiBaseUrl;
|
|
26
|
+
constructor(config: SolvapayAuthAdapterConfig);
|
|
27
|
+
getUserIdFromRequest(req: Request | RequestLike): Promise<string | null>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* SolvaPay OAuth Client Helpers
|
|
31
|
+
*/
|
|
32
|
+
interface SolvapayOAuthConfig {
|
|
33
|
+
clientId: string;
|
|
34
|
+
clientSecret?: string;
|
|
35
|
+
authUrl: string;
|
|
36
|
+
tokenUrl: string;
|
|
37
|
+
redirectUri: string;
|
|
38
|
+
}
|
|
39
|
+
interface TokenResponse {
|
|
40
|
+
access_token: string;
|
|
41
|
+
token_type: string;
|
|
42
|
+
expires_in: number;
|
|
43
|
+
refresh_token?: string;
|
|
44
|
+
scope?: string;
|
|
45
|
+
}
|
|
46
|
+
declare class SolvapayOAuthClient {
|
|
47
|
+
private config;
|
|
48
|
+
constructor(config: SolvapayOAuthConfig);
|
|
49
|
+
/**
|
|
50
|
+
* Get the URL to redirect the user to for login
|
|
51
|
+
*/
|
|
52
|
+
getAuthorizationUrl(options?: {
|
|
53
|
+
state?: string;
|
|
54
|
+
scope?: string;
|
|
55
|
+
}): string;
|
|
56
|
+
/**
|
|
57
|
+
* Exchange an authorization code for an access token
|
|
58
|
+
*/
|
|
59
|
+
exchangeCodeForToken(code: string): Promise<TokenResponse>;
|
|
60
|
+
/**
|
|
61
|
+
* Revoke a token (Sign Out)
|
|
62
|
+
*/
|
|
63
|
+
revokeToken(token: string): Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Get user info using access token
|
|
66
|
+
*/
|
|
67
|
+
getUserInfo(accessToken: string, userInfoUrl?: string): Promise<Record<string, unknown>>;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export { AuthAdapter, RequestLike, SolvapayAuthAdapter, type SolvapayAuthAdapterConfig, SolvapayOAuthClient, type SolvapayOAuthConfig, type TokenResponse };
|
package/dist/index.js
CHANGED
|
@@ -6,9 +6,130 @@ import {
|
|
|
6
6
|
getUserIdFromRequest,
|
|
7
7
|
getUserNameFromRequest,
|
|
8
8
|
requireUserId
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-IOLE5BMD.js";
|
|
10
|
+
|
|
11
|
+
// src/solvapay.ts
|
|
12
|
+
var SolvapayAuthAdapter = class {
|
|
13
|
+
apiBaseUrl;
|
|
14
|
+
constructor(config) {
|
|
15
|
+
this.apiBaseUrl = config.apiBaseUrl.replace(/\/$/, "");
|
|
16
|
+
}
|
|
17
|
+
async getUserIdFromRequest(req) {
|
|
18
|
+
try {
|
|
19
|
+
const headers = "headers" in req ? req.headers : req;
|
|
20
|
+
const authHeader = headers.get("authorization");
|
|
21
|
+
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const token = authHeader.slice(7);
|
|
25
|
+
if (!token) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const response = await fetch(`${this.apiBaseUrl}/v1/customer/auth/userinfo`, {
|
|
29
|
+
method: "GET",
|
|
30
|
+
headers: {
|
|
31
|
+
Authorization: `Bearer ${token}`,
|
|
32
|
+
"Content-Type": "application/json"
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
if (!response.ok) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const userInfo = await response.json();
|
|
39
|
+
return userInfo.sub || userInfo.id || userInfo.customerRef || null;
|
|
40
|
+
} catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
var SolvapayOAuthClient = class {
|
|
46
|
+
constructor(config) {
|
|
47
|
+
this.config = config;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Get the URL to redirect the user to for login
|
|
51
|
+
*/
|
|
52
|
+
getAuthorizationUrl(options = {}) {
|
|
53
|
+
const params = new URLSearchParams({
|
|
54
|
+
response_type: "code",
|
|
55
|
+
client_id: this.config.clientId,
|
|
56
|
+
redirect_uri: this.config.redirectUri
|
|
57
|
+
});
|
|
58
|
+
if (options.state) params.append("state", options.state);
|
|
59
|
+
if (options.scope) params.append("scope", options.scope);
|
|
60
|
+
return `${this.config.authUrl}?${params.toString()}`;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Exchange an authorization code for an access token
|
|
64
|
+
*/
|
|
65
|
+
async exchangeCodeForToken(code) {
|
|
66
|
+
const body = new URLSearchParams({
|
|
67
|
+
grant_type: "authorization_code",
|
|
68
|
+
code,
|
|
69
|
+
client_id: this.config.clientId,
|
|
70
|
+
redirect_uri: this.config.redirectUri
|
|
71
|
+
});
|
|
72
|
+
if (this.config.clientSecret) {
|
|
73
|
+
body.append("client_secret", this.config.clientSecret);
|
|
74
|
+
}
|
|
75
|
+
const response = await fetch(this.config.tokenUrl, {
|
|
76
|
+
method: "POST",
|
|
77
|
+
headers: {
|
|
78
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
79
|
+
Accept: "application/json"
|
|
80
|
+
},
|
|
81
|
+
body: body.toString()
|
|
82
|
+
});
|
|
83
|
+
if (!response.ok) {
|
|
84
|
+
const text = await response.text();
|
|
85
|
+
throw new Error(`Failed to exchange code: ${response.status} ${text}`);
|
|
86
|
+
}
|
|
87
|
+
return response.json();
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Revoke a token (Sign Out)
|
|
91
|
+
*/
|
|
92
|
+
async revokeToken(token) {
|
|
93
|
+
const revokeUrl = this.config.tokenUrl.replace("/token", "/revoke");
|
|
94
|
+
const body = new URLSearchParams({
|
|
95
|
+
token,
|
|
96
|
+
client_id: this.config.clientId
|
|
97
|
+
});
|
|
98
|
+
if (this.config.clientSecret) {
|
|
99
|
+
body.append("client_secret", this.config.clientSecret);
|
|
100
|
+
}
|
|
101
|
+
await fetch(revokeUrl, {
|
|
102
|
+
method: "POST",
|
|
103
|
+
headers: {
|
|
104
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
105
|
+
},
|
|
106
|
+
body: body.toString()
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Get user info using access token
|
|
111
|
+
*/
|
|
112
|
+
async getUserInfo(accessToken, userInfoUrl) {
|
|
113
|
+
if (!userInfoUrl) {
|
|
114
|
+
throw new Error("userInfoUrl is required");
|
|
115
|
+
}
|
|
116
|
+
const response = await fetch(userInfoUrl, {
|
|
117
|
+
method: "GET",
|
|
118
|
+
headers: {
|
|
119
|
+
Authorization: `Bearer ${accessToken}`,
|
|
120
|
+
Accept: "application/json"
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
if (!response.ok) {
|
|
124
|
+
throw new Error(`Failed to fetch user info: ${response.status}`);
|
|
125
|
+
}
|
|
126
|
+
return response.json();
|
|
127
|
+
}
|
|
128
|
+
};
|
|
10
129
|
export {
|
|
11
130
|
MockAuthAdapter,
|
|
131
|
+
SolvapayAuthAdapter,
|
|
132
|
+
SolvapayOAuthClient,
|
|
12
133
|
getUserEmailFromRequest,
|
|
13
134
|
getUserIdFromRequest,
|
|
14
135
|
getUserNameFromRequest,
|
package/dist/mock.d.cts
CHANGED
package/dist/mock.d.ts
CHANGED
package/dist/next-utils.cjs
CHANGED
|
@@ -83,7 +83,8 @@ async function getUserNameFromRequest(request, options) {
|
|
|
83
83
|
const { payload } = await jwtVerify(token, secret, {
|
|
84
84
|
algorithms: ["HS256"]
|
|
85
85
|
});
|
|
86
|
-
const
|
|
86
|
+
const payloadWithMetadata = payload;
|
|
87
|
+
const name = payloadWithMetadata.user_metadata?.full_name || payloadWithMetadata.user_metadata?.name || payloadWithMetadata.name || null;
|
|
87
88
|
return name ? String(name) : null;
|
|
88
89
|
} catch {
|
|
89
90
|
return null;
|
|
@@ -95,13 +96,10 @@ function requireUserId(request, options) {
|
|
|
95
96
|
const errorDetails = options?.errorDetails || "User ID not found. Ensure middleware is configured.";
|
|
96
97
|
const userId = request.headers.get(headerName);
|
|
97
98
|
if (!userId) {
|
|
98
|
-
return new Response(
|
|
99
|
-
|
|
100
|
-
{
|
|
101
|
-
|
|
102
|
-
headers: { "Content-Type": "application/json" }
|
|
103
|
-
}
|
|
104
|
-
);
|
|
99
|
+
return new Response(JSON.stringify({ error: errorMessage, details: errorDetails }), {
|
|
100
|
+
status: 401,
|
|
101
|
+
headers: { "Content-Type": "application/json" }
|
|
102
|
+
});
|
|
105
103
|
}
|
|
106
104
|
return userId;
|
|
107
105
|
}
|
package/dist/next-utils.d.cts
CHANGED
|
@@ -10,10 +10,14 @@
|
|
|
10
10
|
*/
|
|
11
11
|
/**
|
|
12
12
|
* Extract user ID from request headers.
|
|
13
|
-
*
|
|
13
|
+
*
|
|
14
|
+
* Checks for the 'x-user-id' header which is commonly set by authentication
|
|
15
|
+
* middleware after successful authentication. This header is typically set
|
|
16
|
+
* by Next.js middleware that validates JWT tokens or session cookies.
|
|
14
17
|
*
|
|
15
18
|
* @param request - Request object (works with NextRequest from next/server)
|
|
16
19
|
* @param options - Configuration options
|
|
20
|
+
* @param options.headerName - Custom header name (default: 'x-user-id')
|
|
17
21
|
* @returns User ID string or null if not found
|
|
18
22
|
*
|
|
19
23
|
* @example
|
|
@@ -21,60 +25,131 @@
|
|
|
21
25
|
* import { NextRequest, NextResponse } from 'next/server';
|
|
22
26
|
* import { getUserIdFromRequest } from '@solvapay/auth';
|
|
23
27
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
28
|
+
* export async function GET(request: NextRequest) {
|
|
29
|
+
* const userId = getUserIdFromRequest(request);
|
|
30
|
+
*
|
|
31
|
+
* if (!userId) {
|
|
32
|
+
* return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
33
|
+
* }
|
|
34
|
+
*
|
|
35
|
+
* // Use userId...
|
|
36
|
+
* return NextResponse.json({ userId });
|
|
27
37
|
* }
|
|
28
38
|
* ```
|
|
39
|
+
*
|
|
40
|
+
* @see {@link requireUserId} for a version that returns an error response
|
|
41
|
+
* @since 1.0.0
|
|
29
42
|
*/
|
|
30
43
|
declare function getUserIdFromRequest(request: Request, options?: {
|
|
31
44
|
headerName?: string;
|
|
32
45
|
}): string | null;
|
|
33
46
|
/**
|
|
34
47
|
* Extract user email from Supabase JWT token in Authorization header.
|
|
35
|
-
*
|
|
48
|
+
*
|
|
49
|
+
* Parses and validates a Supabase JWT token from the Authorization header
|
|
50
|
+
* and extracts the email claim. Returns null if the token is missing, invalid,
|
|
51
|
+
* or expired.
|
|
52
|
+
*
|
|
53
|
+
* Uses dynamic imports for Edge runtime compatibility.
|
|
36
54
|
*
|
|
37
55
|
* @param request - Request object (works with NextRequest from next/server)
|
|
38
56
|
* @param options - Configuration options
|
|
57
|
+
* @param options.jwtSecret - Supabase JWT secret (defaults to SUPABASE_JWT_SECRET env var)
|
|
39
58
|
* @returns User email string or null if not found
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* import { NextRequest, NextResponse } from 'next/server';
|
|
63
|
+
* import { getUserEmailFromRequest } from '@solvapay/auth';
|
|
64
|
+
*
|
|
65
|
+
* export async function GET(request: NextRequest) {
|
|
66
|
+
* const email = await getUserEmailFromRequest(request);
|
|
67
|
+
*
|
|
68
|
+
* if (!email) {
|
|
69
|
+
* return NextResponse.json({ error: 'Email not found' }, { status: 401 });
|
|
70
|
+
* }
|
|
71
|
+
*
|
|
72
|
+
* return NextResponse.json({ email });
|
|
73
|
+
* }
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* @see {@link getUserNameFromRequest} for extracting user name
|
|
77
|
+
* @since 1.0.0
|
|
40
78
|
*/
|
|
41
79
|
declare function getUserEmailFromRequest(request: Request, options?: {
|
|
42
80
|
jwtSecret?: string;
|
|
43
81
|
}): Promise<string | null>;
|
|
44
82
|
/**
|
|
45
83
|
* Extract user name from Supabase JWT token in Authorization header.
|
|
46
|
-
*
|
|
84
|
+
*
|
|
85
|
+
* Parses and validates a Supabase JWT token from the Authorization header
|
|
86
|
+
* and extracts the name from user metadata. Checks multiple possible locations:
|
|
87
|
+
* - `user_metadata.full_name`
|
|
88
|
+
* - `user_metadata.name`
|
|
89
|
+
* - `name` claim
|
|
90
|
+
*
|
|
91
|
+
* Returns null if the token is missing, invalid, or name is not found.
|
|
47
92
|
*
|
|
48
93
|
* @param request - Request object (works with NextRequest from next/server)
|
|
49
94
|
* @param options - Configuration options
|
|
95
|
+
* @param options.jwtSecret - Supabase JWT secret (defaults to SUPABASE_JWT_SECRET env var)
|
|
50
96
|
* @returns User name string or null if not found
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```typescript
|
|
100
|
+
* import { NextRequest, NextResponse } from 'next/server';
|
|
101
|
+
* import { getUserNameFromRequest } from '@solvapay/auth';
|
|
102
|
+
*
|
|
103
|
+
* export async function GET(request: NextRequest) {
|
|
104
|
+
* const name = await getUserNameFromRequest(request);
|
|
105
|
+
*
|
|
106
|
+
* return NextResponse.json({ name: name || 'Guest' });
|
|
107
|
+
* }
|
|
108
|
+
* ```
|
|
109
|
+
*
|
|
110
|
+
* @see {@link getUserEmailFromRequest} for extracting user email
|
|
111
|
+
* @since 1.0.0
|
|
51
112
|
*/
|
|
52
113
|
declare function getUserNameFromRequest(request: Request, options?: {
|
|
53
114
|
jwtSecret?: string;
|
|
54
115
|
}): Promise<string | null>;
|
|
55
116
|
/**
|
|
56
|
-
* Require user ID from request headers.
|
|
57
|
-
*
|
|
117
|
+
* Require user ID from request headers or return an error response.
|
|
118
|
+
*
|
|
119
|
+
* This is a convenience function that combines `getUserIdFromRequest()` with
|
|
120
|
+
* error handling. If the user ID is not found, it returns a Response object
|
|
121
|
+
* with a 401 status that can be directly returned from Next.js route handlers.
|
|
58
122
|
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
123
|
+
* Returns a standard Response object that works with Next.js (NextResponse
|
|
124
|
+
* extends Response, so this is fully compatible).
|
|
61
125
|
*
|
|
62
126
|
* @param request - Request object (works with NextRequest from next/server)
|
|
63
127
|
* @param options - Configuration options
|
|
64
|
-
* @
|
|
128
|
+
* @param options.headerName - Custom header name (default: 'x-user-id')
|
|
129
|
+
* @param options.errorMessage - Custom error message (default: 'Unauthorized')
|
|
130
|
+
* @param options.errorDetails - Custom error details (default: 'User ID not found. Ensure middleware is configured.')
|
|
131
|
+
* @returns Either the user ID string or a Response error object with 401 status
|
|
65
132
|
*
|
|
66
133
|
* @example
|
|
67
134
|
* ```typescript
|
|
68
135
|
* import { NextRequest, NextResponse } from 'next/server';
|
|
69
136
|
* import { requireUserId } from '@solvapay/auth';
|
|
70
137
|
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
138
|
+
* export async function GET(request: NextRequest) {
|
|
139
|
+
* const userIdOrError = requireUserId(request);
|
|
140
|
+
*
|
|
141
|
+
* if (userIdOrError instanceof Response) {
|
|
142
|
+
* return userIdOrError; // Returns 401 error
|
|
143
|
+
* }
|
|
144
|
+
*
|
|
145
|
+
* // userIdOrError is now a string
|
|
146
|
+
* const userId = userIdOrError;
|
|
147
|
+
* // Use userId...
|
|
74
148
|
* }
|
|
75
|
-
* // userIdOrError is now a string
|
|
76
|
-
* const userId = userIdOrError;
|
|
77
149
|
* ```
|
|
150
|
+
*
|
|
151
|
+
* @see {@link getUserIdFromRequest} for a version that returns null instead of error
|
|
152
|
+
* @since 1.0.0
|
|
78
153
|
*/
|
|
79
154
|
declare function requireUserId(request: Request, options?: {
|
|
80
155
|
headerName?: string;
|
package/dist/next-utils.d.ts
CHANGED
|
@@ -10,10 +10,14 @@
|
|
|
10
10
|
*/
|
|
11
11
|
/**
|
|
12
12
|
* Extract user ID from request headers.
|
|
13
|
-
*
|
|
13
|
+
*
|
|
14
|
+
* Checks for the 'x-user-id' header which is commonly set by authentication
|
|
15
|
+
* middleware after successful authentication. This header is typically set
|
|
16
|
+
* by Next.js middleware that validates JWT tokens or session cookies.
|
|
14
17
|
*
|
|
15
18
|
* @param request - Request object (works with NextRequest from next/server)
|
|
16
19
|
* @param options - Configuration options
|
|
20
|
+
* @param options.headerName - Custom header name (default: 'x-user-id')
|
|
17
21
|
* @returns User ID string or null if not found
|
|
18
22
|
*
|
|
19
23
|
* @example
|
|
@@ -21,60 +25,131 @@
|
|
|
21
25
|
* import { NextRequest, NextResponse } from 'next/server';
|
|
22
26
|
* import { getUserIdFromRequest } from '@solvapay/auth';
|
|
23
27
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
28
|
+
* export async function GET(request: NextRequest) {
|
|
29
|
+
* const userId = getUserIdFromRequest(request);
|
|
30
|
+
*
|
|
31
|
+
* if (!userId) {
|
|
32
|
+
* return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
33
|
+
* }
|
|
34
|
+
*
|
|
35
|
+
* // Use userId...
|
|
36
|
+
* return NextResponse.json({ userId });
|
|
27
37
|
* }
|
|
28
38
|
* ```
|
|
39
|
+
*
|
|
40
|
+
* @see {@link requireUserId} for a version that returns an error response
|
|
41
|
+
* @since 1.0.0
|
|
29
42
|
*/
|
|
30
43
|
declare function getUserIdFromRequest(request: Request, options?: {
|
|
31
44
|
headerName?: string;
|
|
32
45
|
}): string | null;
|
|
33
46
|
/**
|
|
34
47
|
* Extract user email from Supabase JWT token in Authorization header.
|
|
35
|
-
*
|
|
48
|
+
*
|
|
49
|
+
* Parses and validates a Supabase JWT token from the Authorization header
|
|
50
|
+
* and extracts the email claim. Returns null if the token is missing, invalid,
|
|
51
|
+
* or expired.
|
|
52
|
+
*
|
|
53
|
+
* Uses dynamic imports for Edge runtime compatibility.
|
|
36
54
|
*
|
|
37
55
|
* @param request - Request object (works with NextRequest from next/server)
|
|
38
56
|
* @param options - Configuration options
|
|
57
|
+
* @param options.jwtSecret - Supabase JWT secret (defaults to SUPABASE_JWT_SECRET env var)
|
|
39
58
|
* @returns User email string or null if not found
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* import { NextRequest, NextResponse } from 'next/server';
|
|
63
|
+
* import { getUserEmailFromRequest } from '@solvapay/auth';
|
|
64
|
+
*
|
|
65
|
+
* export async function GET(request: NextRequest) {
|
|
66
|
+
* const email = await getUserEmailFromRequest(request);
|
|
67
|
+
*
|
|
68
|
+
* if (!email) {
|
|
69
|
+
* return NextResponse.json({ error: 'Email not found' }, { status: 401 });
|
|
70
|
+
* }
|
|
71
|
+
*
|
|
72
|
+
* return NextResponse.json({ email });
|
|
73
|
+
* }
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* @see {@link getUserNameFromRequest} for extracting user name
|
|
77
|
+
* @since 1.0.0
|
|
40
78
|
*/
|
|
41
79
|
declare function getUserEmailFromRequest(request: Request, options?: {
|
|
42
80
|
jwtSecret?: string;
|
|
43
81
|
}): Promise<string | null>;
|
|
44
82
|
/**
|
|
45
83
|
* Extract user name from Supabase JWT token in Authorization header.
|
|
46
|
-
*
|
|
84
|
+
*
|
|
85
|
+
* Parses and validates a Supabase JWT token from the Authorization header
|
|
86
|
+
* and extracts the name from user metadata. Checks multiple possible locations:
|
|
87
|
+
* - `user_metadata.full_name`
|
|
88
|
+
* - `user_metadata.name`
|
|
89
|
+
* - `name` claim
|
|
90
|
+
*
|
|
91
|
+
* Returns null if the token is missing, invalid, or name is not found.
|
|
47
92
|
*
|
|
48
93
|
* @param request - Request object (works with NextRequest from next/server)
|
|
49
94
|
* @param options - Configuration options
|
|
95
|
+
* @param options.jwtSecret - Supabase JWT secret (defaults to SUPABASE_JWT_SECRET env var)
|
|
50
96
|
* @returns User name string or null if not found
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```typescript
|
|
100
|
+
* import { NextRequest, NextResponse } from 'next/server';
|
|
101
|
+
* import { getUserNameFromRequest } from '@solvapay/auth';
|
|
102
|
+
*
|
|
103
|
+
* export async function GET(request: NextRequest) {
|
|
104
|
+
* const name = await getUserNameFromRequest(request);
|
|
105
|
+
*
|
|
106
|
+
* return NextResponse.json({ name: name || 'Guest' });
|
|
107
|
+
* }
|
|
108
|
+
* ```
|
|
109
|
+
*
|
|
110
|
+
* @see {@link getUserEmailFromRequest} for extracting user email
|
|
111
|
+
* @since 1.0.0
|
|
51
112
|
*/
|
|
52
113
|
declare function getUserNameFromRequest(request: Request, options?: {
|
|
53
114
|
jwtSecret?: string;
|
|
54
115
|
}): Promise<string | null>;
|
|
55
116
|
/**
|
|
56
|
-
* Require user ID from request headers.
|
|
57
|
-
*
|
|
117
|
+
* Require user ID from request headers or return an error response.
|
|
118
|
+
*
|
|
119
|
+
* This is a convenience function that combines `getUserIdFromRequest()` with
|
|
120
|
+
* error handling. If the user ID is not found, it returns a Response object
|
|
121
|
+
* with a 401 status that can be directly returned from Next.js route handlers.
|
|
58
122
|
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
123
|
+
* Returns a standard Response object that works with Next.js (NextResponse
|
|
124
|
+
* extends Response, so this is fully compatible).
|
|
61
125
|
*
|
|
62
126
|
* @param request - Request object (works with NextRequest from next/server)
|
|
63
127
|
* @param options - Configuration options
|
|
64
|
-
* @
|
|
128
|
+
* @param options.headerName - Custom header name (default: 'x-user-id')
|
|
129
|
+
* @param options.errorMessage - Custom error message (default: 'Unauthorized')
|
|
130
|
+
* @param options.errorDetails - Custom error details (default: 'User ID not found. Ensure middleware is configured.')
|
|
131
|
+
* @returns Either the user ID string or a Response error object with 401 status
|
|
65
132
|
*
|
|
66
133
|
* @example
|
|
67
134
|
* ```typescript
|
|
68
135
|
* import { NextRequest, NextResponse } from 'next/server';
|
|
69
136
|
* import { requireUserId } from '@solvapay/auth';
|
|
70
137
|
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
138
|
+
* export async function GET(request: NextRequest) {
|
|
139
|
+
* const userIdOrError = requireUserId(request);
|
|
140
|
+
*
|
|
141
|
+
* if (userIdOrError instanceof Response) {
|
|
142
|
+
* return userIdOrError; // Returns 401 error
|
|
143
|
+
* }
|
|
144
|
+
*
|
|
145
|
+
* // userIdOrError is now a string
|
|
146
|
+
* const userId = userIdOrError;
|
|
147
|
+
* // Use userId...
|
|
74
148
|
* }
|
|
75
|
-
* // userIdOrError is now a string
|
|
76
|
-
* const userId = userIdOrError;
|
|
77
149
|
* ```
|
|
150
|
+
*
|
|
151
|
+
* @see {@link getUserIdFromRequest} for a version that returns null instead of error
|
|
152
|
+
* @since 1.0.0
|
|
78
153
|
*/
|
|
79
154
|
declare function requireUserId(request: Request, options?: {
|
|
80
155
|
headerName?: string;
|
package/dist/next-utils.js
CHANGED
package/dist/supabase.d.cts
CHANGED
package/dist/supabase.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solvapay/auth",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1-preview.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -42,14 +42,15 @@
|
|
|
42
42
|
"jose": "^5.0.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"tsup": "^8.
|
|
46
|
-
"typescript": "^5.
|
|
47
|
-
"vitest": "^
|
|
45
|
+
"tsup": "^8.5.1",
|
|
46
|
+
"typescript": "^5.9.3",
|
|
47
|
+
"vitest": "^4.1.2"
|
|
48
48
|
},
|
|
49
49
|
"scripts": {
|
|
50
50
|
"build": "tsup src/index.ts src/supabase.ts src/mock.ts src/next-utils.ts --format esm,cjs --dts --tsconfig tsconfig.build.json",
|
|
51
51
|
"test": "vitest run || exit 0",
|
|
52
52
|
"test:watch": "vitest",
|
|
53
|
-
"lint": "
|
|
53
|
+
"lint": "eslint src",
|
|
54
|
+
"lint:fix": "eslint src --fix"
|
|
54
55
|
}
|
|
55
56
|
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auth Adapter Interface
|
|
3
|
-
*
|
|
4
|
-
* Defines the contract for authentication adapters that extract user IDs from requests.
|
|
5
|
-
* Implementations should never throw - return null if authentication fails or is missing.
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* Request-like object that has headers
|
|
9
|
-
*/
|
|
10
|
-
interface RequestLike {
|
|
11
|
-
headers: Headers | {
|
|
12
|
-
get(name: string): string | null;
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Auth adapter interface for extracting user IDs from requests
|
|
17
|
-
*/
|
|
18
|
-
interface AuthAdapter {
|
|
19
|
-
/**
|
|
20
|
-
* Extract the authenticated user ID from a request
|
|
21
|
-
*
|
|
22
|
-
* @param req - Request object or object with headers
|
|
23
|
-
* @returns The user ID string if authenticated, null otherwise
|
|
24
|
-
*
|
|
25
|
-
* @remarks
|
|
26
|
-
* This method should never throw. If authentication fails or is missing,
|
|
27
|
-
* return null and let the caller decide how to handle unauthenticated requests.
|
|
28
|
-
*/
|
|
29
|
-
getUserIdFromRequest(req: Request | RequestLike): Promise<string | null>;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export type { AuthAdapter as A, RequestLike as R };
|