exisjs 0.5.9 → 0.5.11
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/dist/auth/index.d.ts +3 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +4 -1
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/oauth/core.d.ts +96 -0
- package/dist/auth/oauth/core.d.ts.map +1 -0
- package/dist/auth/oauth/core.js +203 -0
- package/dist/auth/oauth/core.js.map +1 -0
- package/dist/auth/oauth/index.d.ts +45 -0
- package/dist/auth/oauth/index.d.ts.map +1 -0
- package/dist/auth/oauth/index.js +64 -0
- package/dist/auth/oauth/index.js.map +1 -0
- package/dist/auth/oauth/middleware.d.ts +63 -0
- package/dist/auth/oauth/middleware.d.ts.map +1 -0
- package/dist/auth/oauth/middleware.js +164 -0
- package/dist/auth/oauth/middleware.js.map +1 -0
- package/dist/auth/oauth/providers/custom.d.ts +41 -0
- package/dist/auth/oauth/providers/custom.d.ts.map +1 -0
- package/dist/auth/oauth/providers/custom.js +204 -0
- package/dist/auth/oauth/providers/custom.js.map +1 -0
- package/dist/auth/oauth/providers/discord.d.ts +23 -0
- package/dist/auth/oauth/providers/discord.d.ts.map +1 -0
- package/dist/auth/oauth/providers/discord.js +130 -0
- package/dist/auth/oauth/providers/discord.js.map +1 -0
- package/dist/auth/oauth/providers/facebook.d.ts +28 -0
- package/dist/auth/oauth/providers/facebook.d.ts.map +1 -0
- package/dist/auth/oauth/providers/facebook.js +124 -0
- package/dist/auth/oauth/providers/facebook.js.map +1 -0
- package/dist/auth/oauth/providers/github.d.ts +25 -0
- package/dist/auth/oauth/providers/github.d.ts.map +1 -0
- package/dist/auth/oauth/providers/github.js +132 -0
- package/dist/auth/oauth/providers/github.js.map +1 -0
- package/dist/auth/oauth/providers/google.d.ts +23 -0
- package/dist/auth/oauth/providers/google.d.ts.map +1 -0
- package/dist/auth/oauth/providers/google.js +134 -0
- package/dist/auth/oauth/providers/google.js.map +1 -0
- package/dist/auth/oauth/providers/microsoft.d.ts +28 -0
- package/dist/auth/oauth/providers/microsoft.d.ts.map +1 -0
- package/dist/auth/oauth/providers/microsoft.js +136 -0
- package/dist/auth/oauth/providers/microsoft.js.map +1 -0
- package/dist/auth/oauth/types.d.ts +158 -0
- package/dist/auth/oauth/types.d.ts.map +1 -0
- package/dist/auth/oauth/types.js +4 -0
- package/dist/auth/oauth/types.js.map +1 -0
- package/dist/auth/session.d.ts +4 -1
- package/dist/auth/session.d.ts.map +1 -1
- package/dist/auth/session.js +33 -5
- package/dist/auth/session.js.map +1 -1
- package/dist/cache/store.d.ts +11 -3
- package/dist/cache/store.d.ts.map +1 -1
- package/dist/cache/store.js +87 -19
- package/dist/cache/store.js.map +1 -1
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/dev.js +4 -6
- package/dist/cli/commands/dev.js.map +1 -1
- package/dist/database/adapters/mongodb.d.ts +58 -0
- package/dist/database/adapters/mongodb.d.ts.map +1 -0
- package/dist/database/adapters/mongodb.js +264 -0
- package/dist/database/adapters/mongodb.js.map +1 -0
- package/dist/database/adapters/mysql.d.ts +27 -0
- package/dist/database/adapters/mysql.d.ts.map +1 -0
- package/dist/database/adapters/mysql.js +188 -0
- package/dist/database/adapters/mysql.js.map +1 -0
- package/dist/database/adapters/postgres.d.ts +28 -0
- package/dist/database/adapters/postgres.d.ts.map +1 -0
- package/dist/database/adapters/postgres.js +174 -0
- package/dist/database/adapters/postgres.js.map +1 -0
- package/dist/database/adapters/sqlite.d.ts +27 -0
- package/dist/database/adapters/sqlite.d.ts.map +1 -0
- package/dist/database/adapters/sqlite.js +149 -0
- package/dist/database/adapters/sqlite.js.map +1 -0
- package/dist/database/index.d.ts +42 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/index.js +58 -0
- package/dist/database/index.js.map +1 -0
- package/dist/database/manager.d.ts +114 -0
- package/dist/database/manager.d.ts.map +1 -0
- package/dist/database/manager.js +269 -0
- package/dist/database/manager.js.map +1 -0
- package/dist/database/migration.d.ts +57 -0
- package/dist/database/migration.d.ts.map +1 -0
- package/dist/database/migration.js +329 -0
- package/dist/database/migration.js.map +1 -0
- package/dist/database/query-builder.d.ts +89 -0
- package/dist/database/query-builder.d.ts.map +1 -0
- package/dist/database/query-builder.js +353 -0
- package/dist/database/query-builder.js.map +1 -0
- package/dist/database/types.d.ts +184 -0
- package/dist/database/types.d.ts.map +1 -0
- package/dist/database/types.js +4 -0
- package/dist/database/types.js.map +1 -0
- package/dist/docs/ARCHITECTURE.md +349 -0
- package/dist/docs/BENCHMARKS.md +36 -0
- package/dist/docs/README.md +34 -0
- package/dist/docs/content/README.md +44 -0
- package/dist/docs/content/adapters.mdx +199 -0
- package/dist/docs/content/cache.mdx +239 -0
- package/dist/docs/content/circuit-breaker.mdx +130 -0
- package/dist/docs/content/cli/commands.mdx +214 -0
- package/dist/docs/content/cli/overview.mdx +92 -0
- package/dist/docs/content/cli/usage.mdx +61 -0
- package/dist/docs/content/config.mdx +214 -0
- package/dist/docs/content/controllers.mdx +241 -0
- package/dist/docs/content/cron.mdx +109 -0
- package/dist/docs/content/database.mdx +209 -0
- package/dist/docs/content/dataloader.mdx +170 -0
- package/dist/docs/content/decorators.mdx +204 -0
- package/dist/docs/content/errors.mdx +344 -0
- package/dist/docs/content/gateways.mdx +376 -0
- package/dist/docs/content/installation.mdx +210 -0
- package/dist/docs/content/introduction.mdx +96 -0
- package/dist/docs/content/middleware.mdx +441 -0
- package/dist/docs/content/modules.mdx +144 -0
- package/dist/docs/content/oauth.mdx +179 -0
- package/dist/docs/content/providers.mdx +147 -0
- package/dist/docs/content/queues.mdx +177 -0
- package/dist/docs/content/requests.mdx +293 -0
- package/dist/docs/content/responses.mdx +271 -0
- package/dist/docs/content/routing.mdx +541 -0
- package/dist/docs/content/rpc.mdx +146 -0
- package/dist/docs/content/security.mdx +294 -0
- package/dist/docs/content/sse.mdx +159 -0
- package/dist/docs/content/structure.mdx +116 -0
- package/dist/docs/content/testing.mdx +139 -0
- package/dist/docs/content/validation.mdx +249 -0
- package/dist/docs/content/websockets.mdx +289 -0
- package/dist/docs/integrations/README.md +23 -0
- package/dist/docs/integrations/jwt.mdx +151 -0
- package/dist/docs/integrations/mongo.mdx +183 -0
- package/dist/docs/integrations/observability.mdx +125 -0
- package/dist/docs/integrations/openai.mdx +108 -0
- package/dist/docs/integrations/postgres.mdx +190 -0
- package/dist/docs/integrations/posthog.mdx +122 -0
- package/dist/docs/integrations/redis.mdx +141 -0
- package/dist/docs/integrations/resend.mdx +117 -0
- package/dist/docs/integrations/s3.mdx +122 -0
- package/dist/docs/integrations/swagger.mdx +113 -0
- package/dist/docs/reference/README.md +3 -0
- package/dist/docs/reference/adapters.mdx +130 -0
- package/dist/docs/reference/auth.mdx +183 -0
- package/dist/docs/reference/cache.mdx +132 -0
- package/dist/docs/reference/circuit-breaker.mdx +71 -0
- package/dist/docs/reference/config.mdx +118 -0
- package/dist/docs/reference/context.mdx +168 -0
- package/dist/docs/reference/dataloader.mdx +91 -0
- package/dist/docs/reference/decorators.mdx +293 -0
- package/dist/docs/reference/di.mdx +123 -0
- package/dist/docs/reference/error.mdx +170 -0
- package/dist/docs/reference/exis.mdx +124 -0
- package/dist/docs/reference/middleware.mdx +304 -0
- package/dist/docs/reference/plugin.mdx +113 -0
- package/dist/docs/reference/queue.mdx +155 -0
- package/dist/docs/reference/router.mdx +248 -0
- package/dist/docs/reference/sanitize.mdx +130 -0
- package/dist/docs/reference/storage.mdx +116 -0
- package/dist/docs/reference/swagger.mdx +132 -0
- package/dist/docs/reference/testing.mdx +145 -0
- package/dist/docs/reference/validator.mdx +186 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -1
- package/dist/index.js.map +1 -1
- package/dist/middleware/backpressure.d.ts.map +1 -1
- package/dist/middleware/backpressure.js +21 -12
- package/dist/middleware/backpressure.js.map +1 -1
- package/dist/middleware/cache.d.ts +6 -0
- package/dist/middleware/cache.d.ts.map +1 -1
- package/dist/middleware/cache.js +84 -28
- package/dist/middleware/cache.js.map +1 -1
- package/dist/middleware/idempotency.d.ts +4 -1
- package/dist/middleware/idempotency.d.ts.map +1 -1
- package/dist/middleware/idempotency.js +29 -4
- package/dist/middleware/idempotency.js.map +1 -1
- package/dist/middleware/ip-filter.d.ts.map +1 -1
- package/dist/middleware/ip-filter.js +16 -0
- package/dist/middleware/ip-filter.js.map +1 -1
- package/dist/middleware/rate-limit.d.ts.map +1 -1
- package/dist/middleware/rate-limit.js +29 -12
- package/dist/middleware/rate-limit.js.map +1 -1
- package/dist/queue/drivers/MemoryDriver.d.ts +6 -3
- package/dist/queue/drivers/MemoryDriver.d.ts.map +1 -1
- package/dist/queue/drivers/MemoryDriver.js +76 -23
- package/dist/queue/drivers/MemoryDriver.js.map +1 -1
- package/dist/server/bootstrapper.d.ts +3 -0
- package/dist/server/bootstrapper.d.ts.map +1 -1
- package/dist/server/bootstrapper.js +56 -8
- package/dist/server/bootstrapper.js.map +1 -1
- package/dist/server/bun-adapter.d.ts +2 -0
- package/dist/server/bun-adapter.d.ts.map +1 -1
- package/dist/server/bun-adapter.js +23 -12
- package/dist/server/bun-adapter.js.map +1 -1
- package/dist/server/request-handler.d.ts +0 -2
- package/dist/server/request-handler.d.ts.map +1 -1
- package/dist/server/request-handler.js +2 -24
- package/dist/server/request-handler.js.map +1 -1
- package/dist/server/request.d.ts.map +1 -1
- package/dist/server/request.js +24 -11
- package/dist/server/request.js.map +1 -1
- package/dist/server/uws-adapter.d.ts +80 -0
- package/dist/server/uws-adapter.d.ts.map +1 -0
- package/dist/server/uws-adapter.js +357 -0
- package/dist/server/uws-adapter.js.map +1 -0
- package/dist/server/ws-orchestrator.d.ts +1 -0
- package/dist/server/ws-orchestrator.d.ts.map +1 -1
- package/dist/server/ws-orchestrator.js +83 -0
- package/dist/server/ws-orchestrator.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/config.js.map +1 -1
- package/dist/validator/tex.d.ts +21 -16
- package/dist/validator/tex.d.ts.map +1 -1
- package/dist/validator/tex.js.map +1 -1
- package/package.json +11 -3
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* OAuth Middleware Helpers.
|
|
4
|
+
*
|
|
5
|
+
* Express-style middleware functions for handling OAuth redirects, callbacks,
|
|
6
|
+
* and authentication guards in ExisJS route handlers.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { oauthRedirect, oauthCallback, requireAuth } from 'exisjs/auth/oauth'
|
|
11
|
+
*
|
|
12
|
+
* app.get('/auth/google', oauthRedirect('google'))
|
|
13
|
+
* app.get('/auth/google/callback', oauthCallback('google', {
|
|
14
|
+
* onSuccess: async (req, res, profile, tokens) => {
|
|
15
|
+
* // Create or update user in your database
|
|
16
|
+
* req.session.userId = profile.id
|
|
17
|
+
* res.redirect('/dashboard')
|
|
18
|
+
* },
|
|
19
|
+
* }))
|
|
20
|
+
*
|
|
21
|
+
* // Protect routes
|
|
22
|
+
* app.get('/dashboard', requireAuth(), (req, res) => {
|
|
23
|
+
* res.json({ user: req.user })
|
|
24
|
+
* })
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
+
exports.oauthRedirect = oauthRedirect;
|
|
29
|
+
exports.oauthCallback = oauthCallback;
|
|
30
|
+
exports.requireAuth = requireAuth;
|
|
31
|
+
const errors_1 = require("../../utils/errors");
|
|
32
|
+
const core_1 = require("./core");
|
|
33
|
+
const DEFAULT_STATE_KEY = '_exis_oauth_state';
|
|
34
|
+
const STATE_MAX_AGE_MS = 10 * 60 * 1000; // 10 minutes
|
|
35
|
+
/**
|
|
36
|
+
* Middleware that redirects the user to an OAuth provider's login page.
|
|
37
|
+
* Stores the state and code verifier in the user's session for validation on callback.
|
|
38
|
+
*
|
|
39
|
+
* @param provider The OAuth provider name (e.g. 'google', 'github')
|
|
40
|
+
* @param options Optional settings like additional params or disabling PKCE
|
|
41
|
+
*/
|
|
42
|
+
function oauthRedirect(provider, options) {
|
|
43
|
+
return (req, res, _next) => {
|
|
44
|
+
const stateKey = options?.stateKey || DEFAULT_STATE_KEY;
|
|
45
|
+
const { url, flowState } = core_1.OAuth.getAuthUrl(provider, {
|
|
46
|
+
usePKCE: options?.usePKCE,
|
|
47
|
+
additionalParams: options?.additionalParams,
|
|
48
|
+
});
|
|
49
|
+
// Store the flow state in session
|
|
50
|
+
if (req.session) {
|
|
51
|
+
req.session[stateKey] = flowState;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
// If no session middleware, store in a signed cookie
|
|
55
|
+
res.cookie(stateKey, JSON.stringify(flowState), {
|
|
56
|
+
httpOnly: true,
|
|
57
|
+
secure: process.env.NODE_ENV === 'production',
|
|
58
|
+
sameSite: 'Lax',
|
|
59
|
+
maxAge: STATE_MAX_AGE_MS / 1000,
|
|
60
|
+
path: '/',
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
res.redirect(url);
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Middleware that handles the OAuth callback from a provider.
|
|
68
|
+
* Validates the state, exchanges the authorization code for tokens,
|
|
69
|
+
* fetches the user profile, and calls the onSuccess callback.
|
|
70
|
+
*
|
|
71
|
+
* @param provider The OAuth provider name
|
|
72
|
+
* @param options Callback options including onSuccess and onError handlers
|
|
73
|
+
*/
|
|
74
|
+
function oauthCallback(provider, options) {
|
|
75
|
+
const stateKey = options.stateKey || DEFAULT_STATE_KEY;
|
|
76
|
+
return async (req, res, next) => {
|
|
77
|
+
try {
|
|
78
|
+
// 1. Extract code and state from the callback query params
|
|
79
|
+
const code = req.query?.code;
|
|
80
|
+
const returnedState = req.query?.state;
|
|
81
|
+
const error = req.query?.error;
|
|
82
|
+
// Handle provider-side errors
|
|
83
|
+
if (error) {
|
|
84
|
+
const errorDesc = req.query?.error_description || error;
|
|
85
|
+
throw new Error(`OAuth error from ${provider}: ${errorDesc}`);
|
|
86
|
+
}
|
|
87
|
+
if (!code) {
|
|
88
|
+
throw errors_1.HttpError.badRequest('Missing authorization code in OAuth callback');
|
|
89
|
+
}
|
|
90
|
+
// 2. Retrieve and validate the stored state
|
|
91
|
+
let flowState;
|
|
92
|
+
if (req.session && req.session[stateKey]) {
|
|
93
|
+
flowState = req.session[stateKey];
|
|
94
|
+
// Clean up
|
|
95
|
+
delete req.session[stateKey];
|
|
96
|
+
}
|
|
97
|
+
else if (req.cookies?.[stateKey]) {
|
|
98
|
+
try {
|
|
99
|
+
flowState = JSON.parse(req.cookies[stateKey]);
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
// Invalid cookie
|
|
103
|
+
}
|
|
104
|
+
// Clear the cookie
|
|
105
|
+
res.cookie(stateKey, '', { maxAge: 0, path: '/' });
|
|
106
|
+
}
|
|
107
|
+
if (!flowState) {
|
|
108
|
+
throw errors_1.HttpError.badRequest('OAuth state not found. The session may have expired. Please try again.');
|
|
109
|
+
}
|
|
110
|
+
// Validate state matches
|
|
111
|
+
if (flowState.state !== returnedState) {
|
|
112
|
+
throw errors_1.HttpError.badRequest('OAuth state mismatch. This may be a CSRF attack. Please try again.');
|
|
113
|
+
}
|
|
114
|
+
// Validate state age
|
|
115
|
+
if (Date.now() - flowState.createdAt > STATE_MAX_AGE_MS) {
|
|
116
|
+
throw errors_1.HttpError.badRequest('OAuth state has expired. Please try again.');
|
|
117
|
+
}
|
|
118
|
+
// Validate provider
|
|
119
|
+
if (flowState.provider !== provider) {
|
|
120
|
+
throw errors_1.HttpError.badRequest(`OAuth provider mismatch. Expected '${flowState.provider}', got '${provider}'.`);
|
|
121
|
+
}
|
|
122
|
+
// 3. Exchange code for tokens and get the user profile
|
|
123
|
+
const { profile, tokens } = await core_1.OAuth.handleCallback(provider, code, flowState.codeVerifier);
|
|
124
|
+
// 4. Call the success handler
|
|
125
|
+
await options.onSuccess(req, res, profile, tokens);
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
if (options.onError) {
|
|
129
|
+
await options.onError(req, res, err instanceof Error ? err : new Error(String(err)));
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
next(err);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Guard middleware that ensures the user is authenticated.
|
|
139
|
+
* Checks for `req.user` or `req.session.userId` to determine authentication status.
|
|
140
|
+
*
|
|
141
|
+
* @param options Configuration options
|
|
142
|
+
*/
|
|
143
|
+
function requireAuth(options) {
|
|
144
|
+
return (req, res, next) => {
|
|
145
|
+
let authenticated;
|
|
146
|
+
if (options?.isAuthenticated) {
|
|
147
|
+
authenticated = options.isAuthenticated(req);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
// Default check: req.user exists or session has a userId
|
|
151
|
+
authenticated = !!(req.user ||
|
|
152
|
+
(req.session && req.session.userId));
|
|
153
|
+
}
|
|
154
|
+
if (authenticated) {
|
|
155
|
+
return next();
|
|
156
|
+
}
|
|
157
|
+
// Not authenticated
|
|
158
|
+
if (options?.redirectTo && req.headers.accept?.includes('text/html')) {
|
|
159
|
+
return res.redirect(options.redirectTo);
|
|
160
|
+
}
|
|
161
|
+
return next(errors_1.HttpError.unauthorized(options?.message || 'Authentication required'));
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../src/auth/oauth/middleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom OAuth Provider.
|
|
3
|
+
*
|
|
4
|
+
* A generic adapter for any OAuth 2.0 compliant provider that isn't
|
|
5
|
+
* built in. Configure with your own auth/token/userinfo URLs and
|
|
6
|
+
* an optional profile mapping function.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { OAuth } from 'exisjs/auth'
|
|
11
|
+
*
|
|
12
|
+
* OAuth.custom({
|
|
13
|
+
* name: 'keycloak',
|
|
14
|
+
* authUrl: 'https://keycloak.example.com/realms/main/protocol/openid-connect/auth',
|
|
15
|
+
* tokenUrl: 'https://keycloak.example.com/realms/main/protocol/openid-connect/token',
|
|
16
|
+
* userInfoUrl: 'https://keycloak.example.com/realms/main/protocol/openid-connect/userinfo',
|
|
17
|
+
* clientId: process.env.KC_CLIENT_ID!,
|
|
18
|
+
* clientSecret: process.env.KC_CLIENT_SECRET!,
|
|
19
|
+
* redirectUri: 'http://localhost:3000/auth/keycloak/callback',
|
|
20
|
+
* scopes: ['openid', 'profile', 'email'],
|
|
21
|
+
* mapProfile: (raw) => ({
|
|
22
|
+
* id: raw.sub as string,
|
|
23
|
+
* email: raw.email as string,
|
|
24
|
+
* emailVerified: raw.email_verified as boolean,
|
|
25
|
+
* name: raw.preferred_username as string,
|
|
26
|
+
* }),
|
|
27
|
+
* })
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
import type { OAuthProviderAdapter, OAuthTokens, OAuthUserProfile, CustomOAuthProviderConfig } from '../types';
|
|
31
|
+
export declare class CustomProvider implements OAuthProviderAdapter {
|
|
32
|
+
readonly name: string;
|
|
33
|
+
private config;
|
|
34
|
+
constructor(config: CustomOAuthProviderConfig);
|
|
35
|
+
getAuthorizationUrl(state: string, codeVerifier?: string): string;
|
|
36
|
+
exchangeCode(code: string, codeVerifier?: string): Promise<OAuthTokens>;
|
|
37
|
+
getUserProfile(tokens: OAuthTokens): Promise<OAuthUserProfile>;
|
|
38
|
+
refreshToken(refreshToken: string): Promise<OAuthTokens>;
|
|
39
|
+
revokeToken(token: string): Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=custom.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"custom.d.ts","sourceRoot":"","sources":["../../../../src/auth/oauth/providers/custom.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAGH,OAAO,KAAK,EACV,oBAAoB,EACpB,WAAW,EACX,gBAAgB,EAChB,yBAAyB,EAC1B,MAAM,UAAU,CAAA;AAEjB,qBAAa,cAAe,YAAW,oBAAoB;IACzD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAErB,OAAO,CAAC,MAAM,CAA2B;gBAE7B,MAAM,EAAE,yBAAyB;IAK7C,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM;IAwB3D,YAAY,CAChB,IAAI,EAAE,MAAM,EACZ,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,WAAW,CAAC;IAoDjB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA6C9D,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IA6CxD,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAoChD"}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Custom OAuth Provider.
|
|
4
|
+
*
|
|
5
|
+
* A generic adapter for any OAuth 2.0 compliant provider that isn't
|
|
6
|
+
* built in. Configure with your own auth/token/userinfo URLs and
|
|
7
|
+
* an optional profile mapping function.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { OAuth } from 'exisjs/auth'
|
|
12
|
+
*
|
|
13
|
+
* OAuth.custom({
|
|
14
|
+
* name: 'keycloak',
|
|
15
|
+
* authUrl: 'https://keycloak.example.com/realms/main/protocol/openid-connect/auth',
|
|
16
|
+
* tokenUrl: 'https://keycloak.example.com/realms/main/protocol/openid-connect/token',
|
|
17
|
+
* userInfoUrl: 'https://keycloak.example.com/realms/main/protocol/openid-connect/userinfo',
|
|
18
|
+
* clientId: process.env.KC_CLIENT_ID!,
|
|
19
|
+
* clientSecret: process.env.KC_CLIENT_SECRET!,
|
|
20
|
+
* redirectUri: 'http://localhost:3000/auth/keycloak/callback',
|
|
21
|
+
* scopes: ['openid', 'profile', 'email'],
|
|
22
|
+
* mapProfile: (raw) => ({
|
|
23
|
+
* id: raw.sub as string,
|
|
24
|
+
* email: raw.email as string,
|
|
25
|
+
* emailVerified: raw.email_verified as boolean,
|
|
26
|
+
* name: raw.preferred_username as string,
|
|
27
|
+
* }),
|
|
28
|
+
* })
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32
|
+
exports.CustomProvider = void 0;
|
|
33
|
+
const node_crypto_1 = require("node:crypto");
|
|
34
|
+
class CustomProvider {
|
|
35
|
+
constructor(config) {
|
|
36
|
+
this.name = config.name;
|
|
37
|
+
this.config = config;
|
|
38
|
+
}
|
|
39
|
+
getAuthorizationUrl(state, codeVerifier) {
|
|
40
|
+
const scopes = this.config.scopes || [];
|
|
41
|
+
const params = new URLSearchParams({
|
|
42
|
+
client_id: this.config.clientId,
|
|
43
|
+
redirect_uri: this.config.redirectUri,
|
|
44
|
+
response_type: 'code',
|
|
45
|
+
state,
|
|
46
|
+
});
|
|
47
|
+
if (scopes.length > 0) {
|
|
48
|
+
params.set('scope', scopes.join(' '));
|
|
49
|
+
}
|
|
50
|
+
if (codeVerifier) {
|
|
51
|
+
const challenge = (0, node_crypto_1.createHash)('sha256')
|
|
52
|
+
.update(codeVerifier)
|
|
53
|
+
.digest('base64url');
|
|
54
|
+
params.set('code_challenge', challenge);
|
|
55
|
+
params.set('code_challenge_method', 'S256');
|
|
56
|
+
}
|
|
57
|
+
return `${this.config.authUrl}?${params.toString()}`;
|
|
58
|
+
}
|
|
59
|
+
async exchangeCode(code, codeVerifier) {
|
|
60
|
+
const body = {
|
|
61
|
+
code,
|
|
62
|
+
grant_type: 'authorization_code',
|
|
63
|
+
redirect_uri: this.config.redirectUri,
|
|
64
|
+
};
|
|
65
|
+
if (codeVerifier) {
|
|
66
|
+
body.code_verifier = codeVerifier;
|
|
67
|
+
}
|
|
68
|
+
const headers = {
|
|
69
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
70
|
+
Accept: 'application/json',
|
|
71
|
+
};
|
|
72
|
+
if (this.config.authMethod === 'header') {
|
|
73
|
+
// Send client credentials as Basic auth header
|
|
74
|
+
headers.Authorization =
|
|
75
|
+
'Basic ' +
|
|
76
|
+
Buffer.from(`${this.config.clientId}:${this.config.clientSecret}`).toString('base64');
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// Send client credentials in the request body (default)
|
|
80
|
+
body.client_id = this.config.clientId;
|
|
81
|
+
body.client_secret = this.config.clientSecret;
|
|
82
|
+
}
|
|
83
|
+
const response = await fetch(this.config.tokenUrl, {
|
|
84
|
+
method: 'POST',
|
|
85
|
+
headers,
|
|
86
|
+
body: new URLSearchParams(body),
|
|
87
|
+
});
|
|
88
|
+
if (!response.ok) {
|
|
89
|
+
const error = await response.text();
|
|
90
|
+
throw new Error(`${this.name} token exchange failed: ${error}`);
|
|
91
|
+
}
|
|
92
|
+
const data = (await response.json());
|
|
93
|
+
return {
|
|
94
|
+
accessToken: data.access_token,
|
|
95
|
+
refreshToken: data.refresh_token,
|
|
96
|
+
expiresIn: data.expires_in,
|
|
97
|
+
tokenType: data.token_type || 'Bearer',
|
|
98
|
+
idToken: data.id_token,
|
|
99
|
+
scope: data.scope,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
async getUserProfile(tokens) {
|
|
103
|
+
const response = await fetch(this.config.userInfoUrl, {
|
|
104
|
+
headers: { Authorization: `Bearer ${tokens.accessToken}` },
|
|
105
|
+
});
|
|
106
|
+
if (!response.ok) {
|
|
107
|
+
throw new Error(`${this.name} user info request failed: ${response.statusText}`);
|
|
108
|
+
}
|
|
109
|
+
const raw = (await response.json());
|
|
110
|
+
// Use custom profile mapper if provided
|
|
111
|
+
if (this.config.mapProfile) {
|
|
112
|
+
const mapped = this.config.mapProfile(raw);
|
|
113
|
+
return {
|
|
114
|
+
...mapped,
|
|
115
|
+
emailVerified: mapped.emailVerified ?? false,
|
|
116
|
+
provider: this.name,
|
|
117
|
+
raw,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
// Best-effort field mapping for common OpenID Connect fields
|
|
121
|
+
return {
|
|
122
|
+
id: String(raw.sub || raw.id || raw.user_id || ''),
|
|
123
|
+
email: String(raw.email || ''),
|
|
124
|
+
emailVerified: raw.email_verified ?? false,
|
|
125
|
+
name: String(raw.name ||
|
|
126
|
+
raw.preferred_username ||
|
|
127
|
+
raw.username ||
|
|
128
|
+
raw.display_name ||
|
|
129
|
+
''),
|
|
130
|
+
firstName: raw.given_name,
|
|
131
|
+
lastName: raw.family_name,
|
|
132
|
+
avatar: (raw.picture || raw.avatar || raw.avatar_url),
|
|
133
|
+
provider: this.name,
|
|
134
|
+
raw,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
async refreshToken(refreshToken) {
|
|
138
|
+
const body = {
|
|
139
|
+
refresh_token: refreshToken,
|
|
140
|
+
grant_type: 'refresh_token',
|
|
141
|
+
};
|
|
142
|
+
const headers = {
|
|
143
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
144
|
+
Accept: 'application/json',
|
|
145
|
+
};
|
|
146
|
+
if (this.config.authMethod === 'header') {
|
|
147
|
+
headers.Authorization =
|
|
148
|
+
'Basic ' +
|
|
149
|
+
Buffer.from(`${this.config.clientId}:${this.config.clientSecret}`).toString('base64');
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
body.client_id = this.config.clientId;
|
|
153
|
+
body.client_secret = this.config.clientSecret;
|
|
154
|
+
}
|
|
155
|
+
const response = await fetch(this.config.tokenUrl, {
|
|
156
|
+
method: 'POST',
|
|
157
|
+
headers,
|
|
158
|
+
body: new URLSearchParams(body),
|
|
159
|
+
});
|
|
160
|
+
if (!response.ok) {
|
|
161
|
+
const error = await response.text();
|
|
162
|
+
throw new Error(`${this.name} token refresh failed: ${error}`);
|
|
163
|
+
}
|
|
164
|
+
const data = (await response.json());
|
|
165
|
+
return {
|
|
166
|
+
accessToken: data.access_token,
|
|
167
|
+
refreshToken: data.refresh_token || refreshToken,
|
|
168
|
+
expiresIn: data.expires_in,
|
|
169
|
+
tokenType: data.token_type || 'Bearer',
|
|
170
|
+
idToken: data.id_token,
|
|
171
|
+
scope: data.scope,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
async revokeToken(token) {
|
|
175
|
+
if (!this.config.revokeUrl) {
|
|
176
|
+
throw new Error(`${this.name} does not have a revocation endpoint configured. ` +
|
|
177
|
+
'Set revokeUrl in the provider config.');
|
|
178
|
+
}
|
|
179
|
+
const body = { token };
|
|
180
|
+
const headers = {
|
|
181
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
182
|
+
};
|
|
183
|
+
if (this.config.authMethod === 'header') {
|
|
184
|
+
headers.Authorization =
|
|
185
|
+
'Basic ' +
|
|
186
|
+
Buffer.from(`${this.config.clientId}:${this.config.clientSecret}`).toString('base64');
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
body.client_id = this.config.clientId;
|
|
190
|
+
body.client_secret = this.config.clientSecret;
|
|
191
|
+
}
|
|
192
|
+
const response = await fetch(this.config.revokeUrl, {
|
|
193
|
+
method: 'POST',
|
|
194
|
+
headers,
|
|
195
|
+
body: new URLSearchParams(body),
|
|
196
|
+
});
|
|
197
|
+
if (!response.ok) {
|
|
198
|
+
const error = await response.text();
|
|
199
|
+
throw new Error(`${this.name} token revocation failed: ${error}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
exports.CustomProvider = CustomProvider;
|
|
204
|
+
//# sourceMappingURL=custom.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"custom.js","sourceRoot":"","sources":["../../../../src/auth/oauth/providers/custom.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discord OAuth Provider.
|
|
3
|
+
*
|
|
4
|
+
* Endpoints:
|
|
5
|
+
* Auth: https://discord.com/api/oauth2/authorize
|
|
6
|
+
* Token: https://discord.com/api/oauth2/token
|
|
7
|
+
* UserInfo: https://discord.com/api/v10/users/@me
|
|
8
|
+
* Revoke: https://discord.com/api/oauth2/token/revoke
|
|
9
|
+
*
|
|
10
|
+
* Default scopes: identify, email
|
|
11
|
+
*/
|
|
12
|
+
import type { OAuthProviderAdapter, OAuthProviderConfig, OAuthTokens, OAuthUserProfile } from '../types';
|
|
13
|
+
export declare class DiscordProvider implements OAuthProviderAdapter {
|
|
14
|
+
readonly name: "discord";
|
|
15
|
+
private config;
|
|
16
|
+
constructor(config: OAuthProviderConfig);
|
|
17
|
+
getAuthorizationUrl(state: string, _codeVerifier?: string): string;
|
|
18
|
+
exchangeCode(code: string, _codeVerifier?: string): Promise<OAuthTokens>;
|
|
19
|
+
getUserProfile(tokens: OAuthTokens): Promise<OAuthUserProfile>;
|
|
20
|
+
refreshToken(refreshToken: string): Promise<OAuthTokens>;
|
|
21
|
+
revokeToken(token: string): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=discord.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discord.d.ts","sourceRoot":"","sources":["../../../../src/auth/oauth/providers/discord.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EACV,oBAAoB,EACpB,mBAAmB,EACnB,WAAW,EACX,gBAAgB,EACjB,MAAM,UAAU,CAAA;AASjB,qBAAa,eAAgB,YAAW,oBAAoB;IAC1D,QAAQ,CAAC,IAAI,EAAG,SAAS,CAAS;IAElC,OAAO,CAAC,MAAM,CAAqB;gBAEvB,MAAM,EAAE,mBAAmB;IAIvC,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM;IAa5D,YAAY,CAChB,IAAI,EAAE,MAAM,EACZ,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,WAAW,CAAC;IA6BjB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAoC9D,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IA4BxD,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAgBhD"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Discord OAuth Provider.
|
|
4
|
+
*
|
|
5
|
+
* Endpoints:
|
|
6
|
+
* Auth: https://discord.com/api/oauth2/authorize
|
|
7
|
+
* Token: https://discord.com/api/oauth2/token
|
|
8
|
+
* UserInfo: https://discord.com/api/v10/users/@me
|
|
9
|
+
* Revoke: https://discord.com/api/oauth2/token/revoke
|
|
10
|
+
*
|
|
11
|
+
* Default scopes: identify, email
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.DiscordProvider = void 0;
|
|
15
|
+
const AUTH_URL = 'https://discord.com/api/oauth2/authorize';
|
|
16
|
+
const TOKEN_URL = 'https://discord.com/api/oauth2/token';
|
|
17
|
+
const USERINFO_URL = 'https://discord.com/api/v10/users/@me';
|
|
18
|
+
const REVOKE_URL = 'https://discord.com/api/oauth2/token/revoke';
|
|
19
|
+
const DEFAULT_SCOPES = ['identify', 'email'];
|
|
20
|
+
class DiscordProvider {
|
|
21
|
+
constructor(config) {
|
|
22
|
+
this.name = 'discord';
|
|
23
|
+
this.config = config;
|
|
24
|
+
}
|
|
25
|
+
getAuthorizationUrl(state, _codeVerifier) {
|
|
26
|
+
const scopes = this.config.scopes || DEFAULT_SCOPES;
|
|
27
|
+
const params = new URLSearchParams({
|
|
28
|
+
client_id: this.config.clientId,
|
|
29
|
+
redirect_uri: this.config.redirectUri,
|
|
30
|
+
response_type: 'code',
|
|
31
|
+
scope: scopes.join(' '),
|
|
32
|
+
state,
|
|
33
|
+
});
|
|
34
|
+
return `${AUTH_URL}?${params.toString()}`;
|
|
35
|
+
}
|
|
36
|
+
async exchangeCode(code, _codeVerifier) {
|
|
37
|
+
const response = await fetch(TOKEN_URL, {
|
|
38
|
+
method: 'POST',
|
|
39
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
40
|
+
body: new URLSearchParams({
|
|
41
|
+
client_id: this.config.clientId,
|
|
42
|
+
client_secret: this.config.clientSecret,
|
|
43
|
+
code,
|
|
44
|
+
grant_type: 'authorization_code',
|
|
45
|
+
redirect_uri: this.config.redirectUri,
|
|
46
|
+
}),
|
|
47
|
+
});
|
|
48
|
+
if (!response.ok) {
|
|
49
|
+
const error = await response.text();
|
|
50
|
+
throw new Error(`Discord token exchange failed: ${error}`);
|
|
51
|
+
}
|
|
52
|
+
const data = (await response.json());
|
|
53
|
+
return {
|
|
54
|
+
accessToken: data.access_token,
|
|
55
|
+
refreshToken: data.refresh_token,
|
|
56
|
+
expiresIn: data.expires_in,
|
|
57
|
+
tokenType: data.token_type || 'Bearer',
|
|
58
|
+
scope: data.scope,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
async getUserProfile(tokens) {
|
|
62
|
+
const response = await fetch(USERINFO_URL, {
|
|
63
|
+
headers: { Authorization: `Bearer ${tokens.accessToken}` },
|
|
64
|
+
});
|
|
65
|
+
if (!response.ok) {
|
|
66
|
+
throw new Error(`Discord user info request failed: ${response.statusText}`);
|
|
67
|
+
}
|
|
68
|
+
const data = (await response.json());
|
|
69
|
+
// Build avatar URL
|
|
70
|
+
let avatar;
|
|
71
|
+
if (data.avatar) {
|
|
72
|
+
const ext = data.avatar.startsWith('a_') ? 'gif' : 'png';
|
|
73
|
+
avatar = `https://cdn.discordapp.com/avatars/${data.id}/${data.avatar}.${ext}`;
|
|
74
|
+
}
|
|
75
|
+
// Discord username: pre-2023 has discriminator, post-2023 uses display name
|
|
76
|
+
const displayName = data.global_name || data.username || '';
|
|
77
|
+
return {
|
|
78
|
+
id: data.id,
|
|
79
|
+
email: data.email || '',
|
|
80
|
+
emailVerified: data.verified ?? false,
|
|
81
|
+
name: displayName,
|
|
82
|
+
firstName: undefined,
|
|
83
|
+
lastName: undefined,
|
|
84
|
+
avatar,
|
|
85
|
+
provider: 'discord',
|
|
86
|
+
raw: data,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
async refreshToken(refreshToken) {
|
|
90
|
+
const response = await fetch(TOKEN_URL, {
|
|
91
|
+
method: 'POST',
|
|
92
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
93
|
+
body: new URLSearchParams({
|
|
94
|
+
client_id: this.config.clientId,
|
|
95
|
+
client_secret: this.config.clientSecret,
|
|
96
|
+
refresh_token: refreshToken,
|
|
97
|
+
grant_type: 'refresh_token',
|
|
98
|
+
}),
|
|
99
|
+
});
|
|
100
|
+
if (!response.ok) {
|
|
101
|
+
const error = await response.text();
|
|
102
|
+
throw new Error(`Discord token refresh failed: ${error}`);
|
|
103
|
+
}
|
|
104
|
+
const data = (await response.json());
|
|
105
|
+
return {
|
|
106
|
+
accessToken: data.access_token,
|
|
107
|
+
refreshToken: data.refresh_token || refreshToken,
|
|
108
|
+
expiresIn: data.expires_in,
|
|
109
|
+
tokenType: data.token_type || 'Bearer',
|
|
110
|
+
scope: data.scope,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
async revokeToken(token) {
|
|
114
|
+
const response = await fetch(REVOKE_URL, {
|
|
115
|
+
method: 'POST',
|
|
116
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
117
|
+
body: new URLSearchParams({
|
|
118
|
+
client_id: this.config.clientId,
|
|
119
|
+
client_secret: this.config.clientSecret,
|
|
120
|
+
token,
|
|
121
|
+
}),
|
|
122
|
+
});
|
|
123
|
+
if (!response.ok) {
|
|
124
|
+
const error = await response.text();
|
|
125
|
+
throw new Error(`Discord token revocation failed: ${error}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
exports.DiscordProvider = DiscordProvider;
|
|
130
|
+
//# sourceMappingURL=discord.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discord.js","sourceRoot":"","sources":["../../../../src/auth/oauth/providers/discord.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Facebook OAuth Provider.
|
|
3
|
+
*
|
|
4
|
+
* Endpoints:
|
|
5
|
+
* Auth: https://www.facebook.com/v19.0/dialog/oauth
|
|
6
|
+
* Token: https://graph.facebook.com/v19.0/oauth/access_token
|
|
7
|
+
* UserInfo: https://graph.facebook.com/v19.0/me
|
|
8
|
+
*
|
|
9
|
+
* Default scopes: email, public_profile
|
|
10
|
+
*
|
|
11
|
+
* Note: Facebook uses Graph API versioning. This implementation uses v19.0.
|
|
12
|
+
*/
|
|
13
|
+
import type { OAuthProviderAdapter, OAuthProviderConfig, OAuthTokens, OAuthUserProfile } from '../types';
|
|
14
|
+
export declare class FacebookProvider implements OAuthProviderAdapter {
|
|
15
|
+
readonly name: "facebook";
|
|
16
|
+
private config;
|
|
17
|
+
constructor(config: OAuthProviderConfig);
|
|
18
|
+
getAuthorizationUrl(state: string, _codeVerifier?: string): string;
|
|
19
|
+
exchangeCode(code: string, _codeVerifier?: string): Promise<OAuthTokens>;
|
|
20
|
+
getUserProfile(tokens: OAuthTokens): Promise<OAuthUserProfile>;
|
|
21
|
+
refreshToken(_refreshToken: string): Promise<OAuthTokens>;
|
|
22
|
+
/**
|
|
23
|
+
* Exchange a short-lived token for a long-lived token (~60 days).
|
|
24
|
+
*/
|
|
25
|
+
exchangeForLongLived(shortLivedToken: string): Promise<OAuthTokens>;
|
|
26
|
+
revokeToken(token: string): Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=facebook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facebook.d.ts","sourceRoot":"","sources":["../../../../src/auth/oauth/providers/facebook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EACV,oBAAoB,EACpB,mBAAmB,EACnB,WAAW,EACX,gBAAgB,EACjB,MAAM,UAAU,CAAA;AASjB,qBAAa,gBAAiB,YAAW,oBAAoB;IAC3D,QAAQ,CAAC,IAAI,EAAG,UAAU,CAAS;IAEnC,OAAO,CAAC,MAAM,CAAqB;gBAEvB,MAAM,EAAE,mBAAmB;IAIvC,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM;IAa5D,YAAY,CAChB,IAAI,EAAE,MAAM,EACZ,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,WAAW,CAAC;IAgCjB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAoC9D,YAAY,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAU/D;;OAEG;IACG,oBAAoB,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAwBnE,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAYhD"}
|