@serialsubscriptions/platform-integration 0.0.79
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 +1 -0
- package/lib/SSIProject.d.ts +343 -0
- package/lib/SSIProject.js +429 -0
- package/lib/SSIProjectApi.d.ts +384 -0
- package/lib/SSIProjectApi.js +534 -0
- package/lib/SSISubscribedFeatureApi.d.ts +387 -0
- package/lib/SSISubscribedFeatureApi.js +511 -0
- package/lib/SSISubscribedLimitApi.d.ts +384 -0
- package/lib/SSISubscribedLimitApi.js +534 -0
- package/lib/SSISubscribedPlanApi.d.ts +384 -0
- package/lib/SSISubscribedPlanApi.js +537 -0
- package/lib/SubscribedPlanManager.d.ts +380 -0
- package/lib/SubscribedPlanManager.js +288 -0
- package/lib/UsageApi.d.ts +128 -0
- package/lib/UsageApi.js +224 -0
- package/lib/auth.server.d.ts +192 -0
- package/lib/auth.server.js +579 -0
- package/lib/cache/SSICache.d.ts +40 -0
- package/lib/cache/SSICache.js +134 -0
- package/lib/cache/backends/MemoryCacheBackend.d.ts +15 -0
- package/lib/cache/backends/MemoryCacheBackend.js +46 -0
- package/lib/cache/backends/RedisCacheBackend.d.ts +27 -0
- package/lib/cache/backends/RedisCacheBackend.js +95 -0
- package/lib/cache/constants.d.ts +7 -0
- package/lib/cache/constants.js +10 -0
- package/lib/cache/types.d.ts +27 -0
- package/lib/cache/types.js +2 -0
- package/lib/frontend/index.d.ts +1 -0
- package/lib/frontend/index.js +6 -0
- package/lib/frontend/session/SessionClient.d.ts +24 -0
- package/lib/frontend/session/SessionClient.js +145 -0
- package/lib/index.d.ts +15 -0
- package/lib/index.js +38 -0
- package/lib/lib/session/SessionClient.d.ts +11 -0
- package/lib/lib/session/SessionClient.js +47 -0
- package/lib/lib/session/index.d.ts +3 -0
- package/lib/lib/session/index.js +3 -0
- package/lib/lib/session/stores/MemoryStore.d.ts +7 -0
- package/lib/lib/session/stores/MemoryStore.js +23 -0
- package/lib/lib/session/stores/index.d.ts +1 -0
- package/lib/lib/session/stores/index.js +1 -0
- package/lib/lib/session/types.d.ts +37 -0
- package/lib/lib/session/types.js +1 -0
- package/lib/session/SessionClient.d.ts +19 -0
- package/lib/session/SessionClient.js +132 -0
- package/lib/session/SessionManager.d.ts +139 -0
- package/lib/session/SessionManager.js +443 -0
- package/lib/stateStore.d.ts +5 -0
- package/lib/stateStore.js +9 -0
- package/lib/storage/SSIStorage.d.ts +24 -0
- package/lib/storage/SSIStorage.js +117 -0
- package/lib/storage/backends/MemoryBackend.d.ts +10 -0
- package/lib/storage/backends/MemoryBackend.js +44 -0
- package/lib/storage/backends/PostgresBackend.d.ts +24 -0
- package/lib/storage/backends/PostgresBackend.js +106 -0
- package/lib/storage/backends/RedisBackend.d.ts +19 -0
- package/lib/storage/backends/RedisBackend.js +78 -0
- package/lib/storage/types.d.ts +27 -0
- package/lib/storage/types.js +2 -0
- package/package.json +71 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Usage Reporting API Client
|
|
3
|
+
*
|
|
4
|
+
* Sends usage events to the subscription usage API endpoint.
|
|
5
|
+
* Requires a base URL and Bearer token for authentication.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Usage event data structure
|
|
9
|
+
*/
|
|
10
|
+
export interface UsageEvent {
|
|
11
|
+
/** The internal ID of the Limit entity this usage event applies to (required) */
|
|
12
|
+
limit_id: number;
|
|
13
|
+
/** Positive usage amount for this event (optional, default: 1.0) */
|
|
14
|
+
amount?: number;
|
|
15
|
+
/** Project entity ID when mode supports projects (optional) */
|
|
16
|
+
project_id?: number;
|
|
17
|
+
/** Aggregate/grouping identifier (e.g. campaign/job ID) (optional) */
|
|
18
|
+
aggregate_id?: number;
|
|
19
|
+
/** Human-readable name for the aggregate (not indexed) (optional) */
|
|
20
|
+
aggregate_name?: string;
|
|
21
|
+
/** Arbitrary JSON metadata from the client (optional) */
|
|
22
|
+
metadata?: Record<string, any> | string;
|
|
23
|
+
/** Unix timestamp (UTC seconds since epoch) for when the usage event occurred (optional) */
|
|
24
|
+
event_timestamp?: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* API response structure
|
|
28
|
+
*/
|
|
29
|
+
export interface UsageApiResponse {
|
|
30
|
+
/** Status of the response (always "recorded" on success) */
|
|
31
|
+
status: string;
|
|
32
|
+
/** Number of events successfully processed */
|
|
33
|
+
count: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* API error response structure
|
|
37
|
+
*/
|
|
38
|
+
export interface UsageApiError {
|
|
39
|
+
message: string;
|
|
40
|
+
status?: number;
|
|
41
|
+
statusText?: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Usage information structure
|
|
45
|
+
*/
|
|
46
|
+
export interface UsageInfo {
|
|
47
|
+
/** The internal ID of the Limit entity */
|
|
48
|
+
limit_id: number;
|
|
49
|
+
/** Total usage amount for this limit */
|
|
50
|
+
total_usage: number;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Project usage information structure
|
|
54
|
+
*/
|
|
55
|
+
export interface ProjectUsageInfo {
|
|
56
|
+
/** The internal ID of the Limit entity */
|
|
57
|
+
limit_id: number;
|
|
58
|
+
/** Total usage amount for this limit */
|
|
59
|
+
total_usage: number;
|
|
60
|
+
/** The project entity ID */
|
|
61
|
+
project_id: number;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Usage API client for reporting subscription usage events
|
|
65
|
+
*/
|
|
66
|
+
export declare class UsageApi {
|
|
67
|
+
private baseUrl;
|
|
68
|
+
private bearerToken;
|
|
69
|
+
private endpoint;
|
|
70
|
+
/**
|
|
71
|
+
* Creates a new UsageApi instance
|
|
72
|
+
*
|
|
73
|
+
* @param baseUrl - The base URL of the API (e.g., "https://account.serialsubscriptionsdev.com/")
|
|
74
|
+
* @param bearerToken - The Bearer token for authentication
|
|
75
|
+
*/
|
|
76
|
+
constructor(baseUrl: string, bearerToken: string);
|
|
77
|
+
/**
|
|
78
|
+
* Reports a single usage event
|
|
79
|
+
*
|
|
80
|
+
* @param event - The usage event to report
|
|
81
|
+
* @returns Promise resolving to the API response
|
|
82
|
+
* @throws {UsageApiError} If the request fails
|
|
83
|
+
*/
|
|
84
|
+
reportEvent(event: UsageEvent): Promise<UsageApiResponse>;
|
|
85
|
+
/**
|
|
86
|
+
* Reports multiple usage events in a single batch request
|
|
87
|
+
*
|
|
88
|
+
* All events in a batch are processed within a single database transaction.
|
|
89
|
+
* If any event fails validation, the entire batch is rolled back.
|
|
90
|
+
*
|
|
91
|
+
* @param events - Array of usage events to report
|
|
92
|
+
* @returns Promise resolving to the API response
|
|
93
|
+
* @throws {UsageApiError} If the request fails
|
|
94
|
+
*/
|
|
95
|
+
reportEvents(events: UsageEvent[]): Promise<UsageApiResponse>;
|
|
96
|
+
/**
|
|
97
|
+
* Gets usage information for all limits
|
|
98
|
+
*
|
|
99
|
+
* @returns Promise resolving to an array of usage information
|
|
100
|
+
* @throws {UsageApiError} If the request fails
|
|
101
|
+
*/
|
|
102
|
+
getUsageAll(): Promise<UsageInfo[]>;
|
|
103
|
+
/**
|
|
104
|
+
* Gets usage information for a specific limit
|
|
105
|
+
*
|
|
106
|
+
* @param limit_id - The limit ID to get usage for
|
|
107
|
+
* @returns Promise resolving to the total usage value, or undefined if not found
|
|
108
|
+
* @throws {UsageApiError} If the request fails
|
|
109
|
+
*/
|
|
110
|
+
getUsage(limit_id: number): Promise<number | undefined>;
|
|
111
|
+
/**
|
|
112
|
+
* Gets usage information for all limits for a specific project
|
|
113
|
+
*
|
|
114
|
+
* @param project_id - The project ID to get usage for
|
|
115
|
+
* @returns Promise resolving to an array of project usage information
|
|
116
|
+
* @throws {UsageApiError} If the request fails
|
|
117
|
+
*/
|
|
118
|
+
getProjectUsageAll(project_id: number): Promise<ProjectUsageInfo[]>;
|
|
119
|
+
/**
|
|
120
|
+
* Gets usage information for a specific limit within a project
|
|
121
|
+
*
|
|
122
|
+
* @param project_id - The project ID to get usage for
|
|
123
|
+
* @param limit_id - The limit ID to get usage for
|
|
124
|
+
* @returns Promise resolving to the total usage value, or undefined if not found
|
|
125
|
+
* @throws {UsageApiError} If the request fails
|
|
126
|
+
*/
|
|
127
|
+
getProjectUsage(project_id: number, limit_id: number): Promise<number | undefined>;
|
|
128
|
+
}
|
package/lib/UsageApi.js
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Usage Reporting API Client
|
|
4
|
+
*
|
|
5
|
+
* Sends usage events to the subscription usage API endpoint.
|
|
6
|
+
* Requires a base URL and Bearer token for authentication.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.UsageApi = void 0;
|
|
10
|
+
/**
|
|
11
|
+
* Usage API client for reporting subscription usage events
|
|
12
|
+
*/
|
|
13
|
+
class UsageApi {
|
|
14
|
+
/**
|
|
15
|
+
* Creates a new UsageApi instance
|
|
16
|
+
*
|
|
17
|
+
* @param baseUrl - The base URL of the API (e.g., "https://account.serialsubscriptionsdev.com/")
|
|
18
|
+
* @param bearerToken - The Bearer token for authentication
|
|
19
|
+
*/
|
|
20
|
+
constructor(baseUrl, bearerToken) {
|
|
21
|
+
this.endpoint = '/api/v1/usage/report';
|
|
22
|
+
// Normalize base URL: ensure it ends with a slash
|
|
23
|
+
this.baseUrl = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
|
|
24
|
+
this.bearerToken = bearerToken;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Reports a single usage event
|
|
28
|
+
*
|
|
29
|
+
* @param event - The usage event to report
|
|
30
|
+
* @returns Promise resolving to the API response
|
|
31
|
+
* @throws {UsageApiError} If the request fails
|
|
32
|
+
*/
|
|
33
|
+
async reportEvent(event) {
|
|
34
|
+
return this.reportEvents([event]);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Reports multiple usage events in a single batch request
|
|
38
|
+
*
|
|
39
|
+
* All events in a batch are processed within a single database transaction.
|
|
40
|
+
* If any event fails validation, the entire batch is rolled back.
|
|
41
|
+
*
|
|
42
|
+
* @param events - Array of usage events to report
|
|
43
|
+
* @returns Promise resolving to the API response
|
|
44
|
+
* @throws {UsageApiError} If the request fails
|
|
45
|
+
*/
|
|
46
|
+
async reportEvents(events) {
|
|
47
|
+
if (events.length === 0) {
|
|
48
|
+
throw {
|
|
49
|
+
message: 'At least one event is required',
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
// Normalize: if single event, send as object; if multiple, send as array
|
|
53
|
+
const payload = events.length === 1 ? events[0] : events;
|
|
54
|
+
const url = `${this.baseUrl}${this.endpoint.replace(/^\//, '')}`;
|
|
55
|
+
try {
|
|
56
|
+
const response = await fetch(url, {
|
|
57
|
+
method: 'POST',
|
|
58
|
+
headers: {
|
|
59
|
+
'Authorization': `Bearer ${this.bearerToken}`,
|
|
60
|
+
'Content-Type': 'application/json',
|
|
61
|
+
'Accept': 'application/json',
|
|
62
|
+
},
|
|
63
|
+
body: JSON.stringify(payload),
|
|
64
|
+
});
|
|
65
|
+
if (!response.ok) {
|
|
66
|
+
let errorMessage = `API request failed with status ${response.status}`;
|
|
67
|
+
try {
|
|
68
|
+
const errorData = await response.json();
|
|
69
|
+
if (errorData.message) {
|
|
70
|
+
errorMessage = errorData.message;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
// If response is not JSON, use the status text
|
|
75
|
+
errorMessage = response.statusText || errorMessage;
|
|
76
|
+
}
|
|
77
|
+
throw {
|
|
78
|
+
message: errorMessage,
|
|
79
|
+
status: response.status,
|
|
80
|
+
statusText: response.statusText,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
const data = await response.json();
|
|
84
|
+
return data;
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
if (error && typeof error === 'object' && 'status' in error) {
|
|
88
|
+
// Re-throw UsageApiError
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
// Handle network errors or other exceptions
|
|
92
|
+
throw {
|
|
93
|
+
message: error instanceof Error ? error.message : 'Unknown error occurred',
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Gets usage information for all limits
|
|
99
|
+
*
|
|
100
|
+
* @returns Promise resolving to an array of usage information
|
|
101
|
+
* @throws {UsageApiError} If the request fails
|
|
102
|
+
*/
|
|
103
|
+
async getUsageAll() {
|
|
104
|
+
const endpoint = '/api/v1/usage/get';
|
|
105
|
+
const url = `${this.baseUrl}${endpoint.replace(/^\//, '')}`;
|
|
106
|
+
try {
|
|
107
|
+
const response = await fetch(url, {
|
|
108
|
+
method: 'GET',
|
|
109
|
+
headers: {
|
|
110
|
+
'Authorization': `Bearer ${this.bearerToken}`,
|
|
111
|
+
'Accept': 'application/json',
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
if (!response.ok) {
|
|
115
|
+
let errorMessage = `API request failed with status ${response.status}`;
|
|
116
|
+
try {
|
|
117
|
+
const errorData = await response.json();
|
|
118
|
+
if (errorData.message) {
|
|
119
|
+
errorMessage = errorData.message;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
// If response is not JSON, use the status text
|
|
124
|
+
errorMessage = response.statusText || errorMessage;
|
|
125
|
+
}
|
|
126
|
+
throw {
|
|
127
|
+
message: errorMessage,
|
|
128
|
+
status: response.status,
|
|
129
|
+
statusText: response.statusText,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
const data = await response.json();
|
|
133
|
+
return data;
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
if (error && typeof error === 'object' && 'status' in error) {
|
|
137
|
+
// Re-throw UsageApiError
|
|
138
|
+
throw error;
|
|
139
|
+
}
|
|
140
|
+
// Handle network errors or other exceptions
|
|
141
|
+
throw {
|
|
142
|
+
message: error instanceof Error ? error.message : 'Unknown error occurred',
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Gets usage information for a specific limit
|
|
148
|
+
*
|
|
149
|
+
* @param limit_id - The limit ID to get usage for
|
|
150
|
+
* @returns Promise resolving to the total usage value, or undefined if not found
|
|
151
|
+
* @throws {UsageApiError} If the request fails
|
|
152
|
+
*/
|
|
153
|
+
async getUsage(limit_id) {
|
|
154
|
+
const allUsage = await this.getUsageAll();
|
|
155
|
+
const usageInfo = allUsage.find((info) => info.limit_id === limit_id);
|
|
156
|
+
return usageInfo?.total_usage;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Gets usage information for all limits for a specific project
|
|
160
|
+
*
|
|
161
|
+
* @param project_id - The project ID to get usage for
|
|
162
|
+
* @returns Promise resolving to an array of project usage information
|
|
163
|
+
* @throws {UsageApiError} If the request fails
|
|
164
|
+
*/
|
|
165
|
+
async getProjectUsageAll(project_id) {
|
|
166
|
+
const endpoint = '/api/v1/usage/get';
|
|
167
|
+
const url = `${this.baseUrl}${endpoint.replace(/^\//, '')}`;
|
|
168
|
+
try {
|
|
169
|
+
const response = await fetch(url, {
|
|
170
|
+
method: 'POST',
|
|
171
|
+
headers: {
|
|
172
|
+
'Authorization': `Bearer ${this.bearerToken}`,
|
|
173
|
+
'Content-Type': 'application/json',
|
|
174
|
+
'Accept': 'application/json',
|
|
175
|
+
},
|
|
176
|
+
body: JSON.stringify({ project_id }),
|
|
177
|
+
});
|
|
178
|
+
if (!response.ok) {
|
|
179
|
+
let errorMessage = `API request failed with status ${response.status}`;
|
|
180
|
+
try {
|
|
181
|
+
const errorData = await response.json();
|
|
182
|
+
if (errorData.message) {
|
|
183
|
+
errorMessage = errorData.message;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
// If response is not JSON, use the status text
|
|
188
|
+
errorMessage = response.statusText || errorMessage;
|
|
189
|
+
}
|
|
190
|
+
throw {
|
|
191
|
+
message: errorMessage,
|
|
192
|
+
status: response.status,
|
|
193
|
+
statusText: response.statusText,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
const data = await response.json();
|
|
197
|
+
return data;
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
if (error && typeof error === 'object' && 'status' in error) {
|
|
201
|
+
// Re-throw UsageApiError
|
|
202
|
+
throw error;
|
|
203
|
+
}
|
|
204
|
+
// Handle network errors or other exceptions
|
|
205
|
+
throw {
|
|
206
|
+
message: error instanceof Error ? error.message : 'Unknown error occurred',
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Gets usage information for a specific limit within a project
|
|
212
|
+
*
|
|
213
|
+
* @param project_id - The project ID to get usage for
|
|
214
|
+
* @param limit_id - The limit ID to get usage for
|
|
215
|
+
* @returns Promise resolving to the total usage value, or undefined if not found
|
|
216
|
+
* @throws {UsageApiError} If the request fails
|
|
217
|
+
*/
|
|
218
|
+
async getProjectUsage(project_id, limit_id) {
|
|
219
|
+
const allUsage = await this.getProjectUsageAll(project_id);
|
|
220
|
+
const usageInfo = allUsage.find((info) => info.limit_id === limit_id);
|
|
221
|
+
return usageInfo?.total_usage;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
exports.UsageApi = UsageApi;
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { SSIStorage } from "./storage/SSIStorage";
|
|
2
|
+
export declare const scopes: {
|
|
3
|
+
readonly defaultScopes: "openid profile email view_project create_project delete_project update_project view_subscribed_plan view_subscribed_feature view_subscribed_limit access_subscription_usage";
|
|
4
|
+
};
|
|
5
|
+
export type AuthConfig = {
|
|
6
|
+
issuerBaseUrl?: string;
|
|
7
|
+
authorizationEndpoint?: string;
|
|
8
|
+
tokenEndpoint?: string;
|
|
9
|
+
logoutEndpoint?: string;
|
|
10
|
+
jwksUri?: string;
|
|
11
|
+
jwksPath?: string;
|
|
12
|
+
jwks?: {
|
|
13
|
+
keys: Array<{
|
|
14
|
+
kty: string;
|
|
15
|
+
n: string;
|
|
16
|
+
e: string;
|
|
17
|
+
kid?: string;
|
|
18
|
+
}>;
|
|
19
|
+
};
|
|
20
|
+
clientId?: string;
|
|
21
|
+
clientSecret?: string;
|
|
22
|
+
redirectUri?: string;
|
|
23
|
+
scopes?: string | string[];
|
|
24
|
+
audience?: string;
|
|
25
|
+
storage?: SSIStorage;
|
|
26
|
+
};
|
|
27
|
+
export type LoginUrlOptions = {
|
|
28
|
+
stateKey?: string;
|
|
29
|
+
extraParams?: Record<string, string>;
|
|
30
|
+
stateTtlSeconds?: number;
|
|
31
|
+
};
|
|
32
|
+
export type CallbackParams = {
|
|
33
|
+
code?: string | null;
|
|
34
|
+
state?: string | null;
|
|
35
|
+
};
|
|
36
|
+
export type TokenResponse = {
|
|
37
|
+
access_token?: string;
|
|
38
|
+
id_token?: string;
|
|
39
|
+
token_type?: string;
|
|
40
|
+
refresh_token?: string;
|
|
41
|
+
expires_in?: number;
|
|
42
|
+
scope?: string;
|
|
43
|
+
raw: any;
|
|
44
|
+
id_claims?: Record<string, unknown>;
|
|
45
|
+
access_claims?: Record<string, unknown>;
|
|
46
|
+
};
|
|
47
|
+
export declare class AuthServer {
|
|
48
|
+
private cfg;
|
|
49
|
+
private stateStorage;
|
|
50
|
+
private jwksCache;
|
|
51
|
+
private lastTokens?;
|
|
52
|
+
constructor(config?: AuthConfig);
|
|
53
|
+
/**
|
|
54
|
+
* Build the authorization URL and persist a CSRF state for the callback.
|
|
55
|
+
* Returns: { url, stateKey, stateValue }
|
|
56
|
+
*/
|
|
57
|
+
getLoginUrl(opts?: LoginUrlOptions): Promise<{
|
|
58
|
+
url: string;
|
|
59
|
+
stateKey: string;
|
|
60
|
+
stateValue: `${string}-${string}-${string}-${string}-${string}`;
|
|
61
|
+
}>;
|
|
62
|
+
/**
|
|
63
|
+
* Build the logout URL for RP-initiated logout.
|
|
64
|
+
* Common params: id_token_hint, post_logout_redirect_uri
|
|
65
|
+
*/
|
|
66
|
+
getLogoutUrl(opts?: {
|
|
67
|
+
idTokenHint?: string;
|
|
68
|
+
postLogoutRedirectUri?: string;
|
|
69
|
+
extraParams?: Record<string, string>;
|
|
70
|
+
}): {
|
|
71
|
+
url: string;
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Handle the OAuth callback: validates state and exchanges the code for tokens.
|
|
75
|
+
* Returns TokenResponse (and includes raw for debugging).
|
|
76
|
+
*/
|
|
77
|
+
handleCallback(params: CallbackParams): Promise<TokenResponse>;
|
|
78
|
+
/**
|
|
79
|
+
* Exchange a refresh_token for new tokens.
|
|
80
|
+
* Verifies any returned JWTs and returns a TokenResponse.
|
|
81
|
+
*
|
|
82
|
+
* @param refreshToken - The refresh token to exchange for new tokens
|
|
83
|
+
* @param options - Optional parameters for the refresh request
|
|
84
|
+
* @param options.scope - Optional scope parameter (cannot exceed originally granted scope)
|
|
85
|
+
* @param options.useAuthHeader - Use Authorization header instead of client_secret in body
|
|
86
|
+
* @returns Promise<TokenResponse> - New tokens with verified claims
|
|
87
|
+
*/
|
|
88
|
+
refreshTokens(refreshToken: string, options?: {
|
|
89
|
+
scope?: string;
|
|
90
|
+
useAuthHeader?: boolean;
|
|
91
|
+
}): Promise<TokenResponse>;
|
|
92
|
+
/**
|
|
93
|
+
* Fetch and cache JWKS from the remote endpoint.
|
|
94
|
+
* Uses SSICache to cache the JWKS response.
|
|
95
|
+
* @private
|
|
96
|
+
*/
|
|
97
|
+
private fetchAndCacheJWKS;
|
|
98
|
+
/**
|
|
99
|
+
* Verify JWT signature and claims using jose library.
|
|
100
|
+
* Handles JWKS fetching, caching, kid selection, and algorithm validation.
|
|
101
|
+
* @private
|
|
102
|
+
*/
|
|
103
|
+
private verifyWithIssuer;
|
|
104
|
+
/**
|
|
105
|
+
* Public method to verify a JWT.
|
|
106
|
+
* Use this in middleware or anywhere you need to validate tokens.
|
|
107
|
+
*/
|
|
108
|
+
verifyJwt<T = unknown>(jwt: string): Promise<T>;
|
|
109
|
+
/**
|
|
110
|
+
* Verify and decode a JWT before returning its claims.
|
|
111
|
+
* Throws if the JWT is invalid, expired, or fails signature verification.
|
|
112
|
+
*
|
|
113
|
+
* This method is safe to use in middleware or debugging contexts when you
|
|
114
|
+
* simply need the decoded, verified claims from a JWT string.
|
|
115
|
+
*/
|
|
116
|
+
verifyAndDecodeJwt<T = unknown>(jwt?: string): Promise<T>;
|
|
117
|
+
/**
|
|
118
|
+
* Automatically refresh tokens if they are expired or about to expire.
|
|
119
|
+
* This is a convenience method that handles the refresh logic automatically.
|
|
120
|
+
*
|
|
121
|
+
* @param refreshToken - The refresh token to use for refreshing
|
|
122
|
+
* @param options - Optional parameters for the refresh request
|
|
123
|
+
* @param options.bufferSeconds - How many seconds before expiry to consider tokens as "about to expire" (default: 60)
|
|
124
|
+
* @param options.scope - Optional scope parameter
|
|
125
|
+
* @param options.useAuthHeader - Use Authorization header instead of client_secret in body
|
|
126
|
+
* @returns Promise<TokenResponse | null> - New tokens if refreshed, null if not needed
|
|
127
|
+
*/
|
|
128
|
+
autoRefreshTokens(refreshToken: string, options?: {
|
|
129
|
+
bufferSeconds?: number;
|
|
130
|
+
scope?: string;
|
|
131
|
+
useAuthHeader?: boolean;
|
|
132
|
+
}): Promise<TokenResponse | null>;
|
|
133
|
+
/**
|
|
134
|
+
* Check if the current tokens are expired or about to expire.
|
|
135
|
+
*
|
|
136
|
+
* @param bufferSeconds - How many seconds before expiry to consider tokens as "about to expire" (default: 60)
|
|
137
|
+
* @returns boolean - true if tokens need refreshing, false otherwise
|
|
138
|
+
*/
|
|
139
|
+
needsTokenRefresh(bufferSeconds?: number): boolean;
|
|
140
|
+
/**
|
|
141
|
+
* Get the time until the current access token expires.
|
|
142
|
+
*
|
|
143
|
+
* @returns number - Seconds until expiry, or 0 if no token or expired
|
|
144
|
+
*/
|
|
145
|
+
getTokenExpirySeconds(): number;
|
|
146
|
+
/** Returns the last TokenResponse produced by handleCallback/refreshTokens in this instance */
|
|
147
|
+
getLastTokenResponse(): TokenResponse | undefined;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* USAGE EXAMPLES
|
|
151
|
+
*
|
|
152
|
+
* // Basic token refresh
|
|
153
|
+
* const auth = new AuthServer(config);
|
|
154
|
+
* const newTokens = await auth.refreshTokens(refreshToken);
|
|
155
|
+
*
|
|
156
|
+
* // Refresh with Authorization header instead of client_secret in body
|
|
157
|
+
* const newTokens = await auth.refreshTokens(refreshToken, {
|
|
158
|
+
* useAuthHeader: true
|
|
159
|
+
* });
|
|
160
|
+
*
|
|
161
|
+
* // Refresh with specific scope (cannot exceed originally granted scope)
|
|
162
|
+
* const newTokens = await auth.refreshTokens(refreshToken, {
|
|
163
|
+
* scope: "openid profile email offline_access"
|
|
164
|
+
* });
|
|
165
|
+
*
|
|
166
|
+
* // Automatic refresh - only refreshes if tokens are expired or about to expire
|
|
167
|
+
* const newTokens = await auth.autoRefreshTokens(refreshToken, {
|
|
168
|
+
* bufferSeconds: 120, // Refresh if expires within 2 minutes
|
|
169
|
+
* useAuthHeader: true
|
|
170
|
+
* });
|
|
171
|
+
*
|
|
172
|
+
* // Check if tokens need refreshing
|
|
173
|
+
* if (auth.needsTokenRefresh(60)) {
|
|
174
|
+
* const newTokens = await auth.refreshTokens(refreshToken);
|
|
175
|
+
* }
|
|
176
|
+
*
|
|
177
|
+
* // Get time until token expires
|
|
178
|
+
* const secondsUntilExpiry = auth.getTokenExpirySeconds();
|
|
179
|
+
* console.log(`Token expires in ${secondsUntilExpiry} seconds`);
|
|
180
|
+
*
|
|
181
|
+
* // Error handling
|
|
182
|
+
* try {
|
|
183
|
+
* const newTokens = await auth.refreshTokens(refreshToken);
|
|
184
|
+
* // Use new tokens...
|
|
185
|
+
* } catch (error) {
|
|
186
|
+
* if (error.message.includes('invalid_grant')) {
|
|
187
|
+
* // Refresh token is invalid/expired - redirect to login
|
|
188
|
+
* return Response.redirect('/login');
|
|
189
|
+
* }
|
|
190
|
+
* // Handle other errors...
|
|
191
|
+
* }
|
|
192
|
+
*/
|