@dereekb/firebase-server 14.0.1 → 14.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/calcom/index.esm.js +3 -2
- package/calcom/package.json +10 -10
- package/calcom/src/lib/calcom.oauth.connection.service.d.ts +2 -2
- package/discord/index.esm.js +174 -19
- package/discord/package.json +10 -10
- package/discord/src/lib/discord.oauth.connection.config.d.ts +43 -2
- package/discord/src/lib/discord.oauth.connection.module.d.ts +18 -1
- package/discord/src/lib/discord.oauth.connection.service.d.ts +40 -3
- package/index.esm.js +9 -1
- package/mailgun/package.json +9 -9
- package/mcp/package.json +11 -11
- package/model/index.esm.js +5182 -2369
- package/model/package.json +9 -9
- package/model/src/lib/userexternalconnection/index.d.ts +2 -0
- package/model/src/lib/userexternalconnection/oauth/index.d.ts +1 -0
- package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.config.d.ts +51 -0
- package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.controller.d.ts +49 -0
- package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.refresh.d.ts +35 -0
- package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.service.d.ts +300 -7
- package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.state.d.ts +213 -12
- package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.throttle.d.ts +81 -0
- package/model/src/lib/userexternalconnection/userexternalconnection.action.server.d.ts +214 -1
- package/model/src/lib/userexternalconnection/userexternalconnection.error.d.ts +118 -5
- package/model/src/lib/userexternalconnection/userexternalconnection.module.d.ts +52 -2
- package/model/src/lib/userexternalconnection/userexternalconnection.policy.d.ts +117 -0
- package/model/src/lib/userexternalconnection/userexternalconnection.signin.d.ts +286 -0
- package/oidc/package.json +10 -10
- package/package.json +12 -12
- package/src/lib/auth/auth.service.d.ts +26 -0
- package/test/package.json +11 -11
- package/twilio/package.json +8 -8
- package/zoho/index.esm.js +3 -2
- package/zoho/package.json +10 -10
- package/zoho/src/lib/zoho.oauth.connection.service.d.ts +2 -2
package/model/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dereekb/firebase-server/model",
|
|
3
|
-
"version": "14.0
|
|
3
|
+
"version": "14.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"peerDependencies": {
|
|
6
|
-
"@dereekb/analytics": "14.0
|
|
7
|
-
"@dereekb/date": "14.0
|
|
8
|
-
"@dereekb/firebase": "14.0
|
|
9
|
-
"@dereekb/firebase-server": "14.0
|
|
10
|
-
"@dereekb/model": "14.0
|
|
11
|
-
"@dereekb/nestjs": "14.0
|
|
12
|
-
"@dereekb/rxjs": "14.0
|
|
13
|
-
"@dereekb/util": "14.0
|
|
6
|
+
"@dereekb/analytics": "14.1.0",
|
|
7
|
+
"@dereekb/date": "14.1.0",
|
|
8
|
+
"@dereekb/firebase": "14.1.0",
|
|
9
|
+
"@dereekb/firebase-server": "14.1.0",
|
|
10
|
+
"@dereekb/model": "14.1.0",
|
|
11
|
+
"@dereekb/nestjs": "14.1.0",
|
|
12
|
+
"@dereekb/rxjs": "14.1.0",
|
|
13
|
+
"@dereekb/util": "14.1.0",
|
|
14
14
|
"@nestjs/common": "^12.0.1",
|
|
15
15
|
"@nestjs/config": "^12.0.0",
|
|
16
16
|
"archiver": "^8.0.0",
|
|
@@ -4,5 +4,7 @@ export * from './userexternalconnection.accessor.service';
|
|
|
4
4
|
export * from './userexternalconnection.action.server';
|
|
5
5
|
export * from './userexternalconnection.error';
|
|
6
6
|
export * from './userexternalconnection.module';
|
|
7
|
+
export * from './userexternalconnection.policy';
|
|
8
|
+
export * from './userexternalconnection.signin';
|
|
7
9
|
export * from './userexternalconnection.reader.service';
|
|
8
10
|
export * from './userexternalconnection.refresh.service';
|
|
@@ -5,3 +5,4 @@ export * from './userexternalconnection.oauth.refresh';
|
|
|
5
5
|
export * from './userexternalconnection.oauth.registry';
|
|
6
6
|
export * from './userexternalconnection.oauth.service';
|
|
7
7
|
export * from './userexternalconnection.oauth.state';
|
|
8
|
+
export * from './userexternalconnection.oauth.throttle';
|
|
@@ -68,7 +68,46 @@ export interface UserExternalConnectionOAuthApiConfig {
|
|
|
68
68
|
* Where the user is sent after a connection fails. Defaults to the `successUrl`.
|
|
69
69
|
*/
|
|
70
70
|
readonly failureUrl?: Maybe<WebsiteUrl>;
|
|
71
|
+
/**
|
|
72
|
+
* Where the user is sent after a successful SIGN-IN, with the ticket appended. Defaults to the
|
|
73
|
+
* `successUrl`.
|
|
74
|
+
*
|
|
75
|
+
* Usually different from `successUrl`: a connect returns to a settings page, a sign-in returns to
|
|
76
|
+
* wherever a freshly signed-in user belongs.
|
|
77
|
+
*/
|
|
78
|
+
readonly signInSuccessUrl?: Maybe<WebsiteUrl>;
|
|
79
|
+
/**
|
|
80
|
+
* Where the user is sent after a FAILED sign-in, with the reason code appended. Defaults to the
|
|
81
|
+
* `failureUrl`.
|
|
82
|
+
*
|
|
83
|
+
* Usually different from `failureUrl`: a failed connect returns to the auth-gated settings page the
|
|
84
|
+
* connect was started from, while a failed sign-in has no signed-in user to show that page to — it
|
|
85
|
+
* belongs back on the login page, where the refusal can be explained and retried.
|
|
86
|
+
*/
|
|
87
|
+
readonly signInFailureUrl?: Maybe<WebsiteUrl>;
|
|
88
|
+
/**
|
|
89
|
+
* App paths a sign-in request may ask to return to.
|
|
90
|
+
*
|
|
91
|
+
* An UNVALIDATED return path is an open redirect, so a path absent from this list is dropped and
|
|
92
|
+
* the sign-in returns to {@link signInSuccessUrl} instead. Absent or empty means no request-supplied
|
|
93
|
+
* return path is honored at all, which is the safe default.
|
|
94
|
+
*/
|
|
95
|
+
readonly allowedReturnPaths?: Maybe<readonly string[]>;
|
|
71
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Returns whether a request-supplied return path may be honored.
|
|
99
|
+
*
|
|
100
|
+
* An exact match against the app's declared list — deliberately not a prefix or pattern match, since
|
|
101
|
+
* every "starts with /app" style check ever written has eventually been defeated by a path that also
|
|
102
|
+
* starts with it (`/app.evil.com`, `//evil.com/app`).
|
|
103
|
+
*
|
|
104
|
+
* @param config - The provider's OAuth config carrying the allowlist.
|
|
105
|
+
* @param returnPath - The path the request asked to return to.
|
|
106
|
+
* @returns True when the path is on the allowlist.
|
|
107
|
+
*
|
|
108
|
+
* @__NO_SIDE_EFFECTS__
|
|
109
|
+
*/
|
|
110
|
+
export declare function isAllowedUserExternalConnectionReturnPath(config: UserExternalConnectionOAuthApiConfig, returnPath: Maybe<string>): boolean;
|
|
72
111
|
/**
|
|
73
112
|
* Configuration for an {@link AbstractUserExternalConnectionOAuthService}.
|
|
74
113
|
*
|
|
@@ -94,6 +133,18 @@ export interface UserExternalConnectionOAuthServiceConfigFactoryConfig {
|
|
|
94
133
|
* Path on the app URL the user is returned to after a failed connect. Defaults to `successPath`.
|
|
95
134
|
*/
|
|
96
135
|
readonly failurePath?: Maybe<string>;
|
|
136
|
+
/**
|
|
137
|
+
* Path on the app URL a successful SIGN-IN returns to. Defaults to `successPath`.
|
|
138
|
+
*/
|
|
139
|
+
readonly signInSuccessPath?: Maybe<string>;
|
|
140
|
+
/**
|
|
141
|
+
* Path on the app URL a FAILED sign-in returns to, e.g. `/auth/login`. Defaults to `failurePath`.
|
|
142
|
+
*/
|
|
143
|
+
readonly signInFailurePath?: Maybe<string>;
|
|
144
|
+
/**
|
|
145
|
+
* App paths a sign-in request may ask to return to instead of {@link signInSuccessPath}.
|
|
146
|
+
*/
|
|
147
|
+
readonly allowedReturnPaths?: Maybe<readonly string[]>;
|
|
97
148
|
}
|
|
98
149
|
/**
|
|
99
150
|
* Builds a provider's OAuth configuration from the app's configured origins plus code-declared
|
package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.controller.d.ts
CHANGED
|
@@ -20,6 +20,32 @@ export interface UserExternalConnectionOAuthCallbackQuery extends UserExternalCo
|
|
|
20
20
|
readonly error?: Maybe<string>;
|
|
21
21
|
readonly error_description?: Maybe<string>;
|
|
22
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Body of a sign-in ticket exchange.
|
|
25
|
+
*/
|
|
26
|
+
export interface UserExternalConnectionOAuthTicketExchangeBody {
|
|
27
|
+
readonly ticket?: Maybe<string>;
|
|
28
|
+
/**
|
|
29
|
+
* The PKCE code verifier the browser retained in session storage.
|
|
30
|
+
*/
|
|
31
|
+
readonly verifier?: Maybe<string>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Response of a successful sign-in ticket exchange.
|
|
35
|
+
*/
|
|
36
|
+
export interface UserExternalConnectionOAuthTicketExchangeResponse {
|
|
37
|
+
/**
|
|
38
|
+
* The Firebase custom token to pass to `signInWithCustomToken`.
|
|
39
|
+
*/
|
|
40
|
+
readonly customToken: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* HTTP status returned when a sign-in ticket cannot be redeemed.
|
|
44
|
+
*
|
|
45
|
+
* A single status for every failure — expired, tampered with, wrong verifier, throttled — so the
|
|
46
|
+
* endpoint is not an oracle telling an attacker which part of a forged ticket was wrong.
|
|
47
|
+
*/
|
|
48
|
+
export declare const USER_EXTERNAL_CONNECTION_OAUTH_TICKET_REJECTED_STATUS = 401;
|
|
23
49
|
/**
|
|
24
50
|
* The two endpoints of an external-connection authorization-code handoff.
|
|
25
51
|
*
|
|
@@ -65,4 +91,27 @@ export declare abstract class AbstractUserExternalConnectionOAuthController {
|
|
|
65
91
|
* @param response - The response to issue the redirect on.
|
|
66
92
|
*/
|
|
67
93
|
callback(query: UserExternalConnectionOAuthCallbackQuery, response: Response): Promise<void>;
|
|
94
|
+
/**
|
|
95
|
+
* Begins a SIGN-IN handoff for an anonymous visitor.
|
|
96
|
+
*
|
|
97
|
+
* Unauthenticated by necessity: a user who is signing in has no credential to present yet. The
|
|
98
|
+
* state is minted here rather than by a prior authenticated call, bound to the `challenge` the
|
|
99
|
+
* browser supplies, and the whole route is refused unless the app's policy enabled sign-in for this
|
|
100
|
+
* provider.
|
|
101
|
+
*
|
|
102
|
+
* @param request - The incoming sign-in request, carrying `challenge` and an optional `returnPath`.
|
|
103
|
+
* @param response - The response to issue the redirect on.
|
|
104
|
+
*/
|
|
105
|
+
signIn(request: Request, response: Response): Promise<void>;
|
|
106
|
+
/**
|
|
107
|
+
* Redeems a sign-in ticket for the Firebase custom token it carries.
|
|
108
|
+
*
|
|
109
|
+
* Unauthenticated for the same reason as `signin`, and safe for the same reason the ticket is: it
|
|
110
|
+
* can only be redeemed by whoever holds the PKCE verifier the flow started with.
|
|
111
|
+
*
|
|
112
|
+
* @param body - The ticket from the redirect and the verifier the browser retained.
|
|
113
|
+
* @param request - The incoming request, read for the client IP the throttle keys on.
|
|
114
|
+
* @param response - The response to write the token or the rejection to.
|
|
115
|
+
*/
|
|
116
|
+
token(body: UserExternalConnectionOAuthTicketExchangeBody, request: Request, response: Response): Promise<void>;
|
|
68
117
|
}
|
package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.refresh.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { type FirebaseAuthUserId, type UserExternalConnectionProviderType } from '@dereekb/firebase';
|
|
2
|
+
import { type UserExternalConnectionCredentials } from '../userexternalconnection.private';
|
|
1
3
|
import { type UserExternalConnectionCredentialsRefresher } from '../userexternalconnection.refresh.service';
|
|
2
4
|
import { type UserExternalConnectionOAuthProviderRegistry } from './userexternalconnection.oauth.registry';
|
|
3
5
|
/**
|
|
@@ -22,3 +24,36 @@ export interface UserExternalConnectionOAuthRegistryCredentialsRefresherConfig {
|
|
|
22
24
|
* @__NO_SIDE_EFFECTS__
|
|
23
25
|
*/
|
|
24
26
|
export declare function userExternalConnectionOAuthRegistryCredentialsRefresher(config: UserExternalConnectionOAuthRegistryCredentialsRefresherConfig): UserExternalConnectionCredentialsRefresher;
|
|
27
|
+
/**
|
|
28
|
+
* Input for a {@link UserExternalConnectionCredentialsRevoker}.
|
|
29
|
+
*/
|
|
30
|
+
export interface UserExternalConnectionRevokeCredentialsInput {
|
|
31
|
+
readonly uid: FirebaseAuthUserId;
|
|
32
|
+
readonly providerType: UserExternalConnectionProviderType;
|
|
33
|
+
readonly credentials: UserExternalConnectionCredentials;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Ends a provider's grant before the credentials are forgotten.
|
|
37
|
+
*/
|
|
38
|
+
export declare abstract class UserExternalConnectionCredentialsRevoker {
|
|
39
|
+
abstract readonly revokeUserExternalConnectionCredentials: (input: UserExternalConnectionRevokeCredentialsInput) => Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Creates a {@link UserExternalConnectionCredentialsRevoker} that revokes through the app's
|
|
43
|
+
* registered OAuth provider services.
|
|
44
|
+
*
|
|
45
|
+
* The disconnect counterpart of {@link userExternalConnectionOAuthRegistryCredentialsRefresher}, and
|
|
46
|
+
* declared beside it for the same reason: the paired write knows the credentials are being discarded
|
|
47
|
+
* but nothing about providers, while a provider service knows how to revoke but nothing about who is
|
|
48
|
+
* asking.
|
|
49
|
+
*
|
|
50
|
+
* Call this BEFORE `disconnectUserExternalConnection`, which is the last moment the credentials
|
|
51
|
+
* still exist. A provider the app never registered — or one with no revocation endpoint — resolves to
|
|
52
|
+
* a no-op, which matches the pre-existing behavior of simply deleting the stored credentials.
|
|
53
|
+
*
|
|
54
|
+
* @param config - The provider registry to dispatch through.
|
|
55
|
+
* @returns A revoker backed by the registry.
|
|
56
|
+
*
|
|
57
|
+
* @__NO_SIDE_EFFECTS__
|
|
58
|
+
*/
|
|
59
|
+
export declare function userExternalConnectionOAuthRegistryCredentialsRevoker(config: UserExternalConnectionOAuthRegistryCredentialsRefresherConfig): UserExternalConnectionCredentialsRevoker;
|
package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.service.d.ts
CHANGED
|
@@ -5,8 +5,11 @@ import { type Maybe, type WebsiteUrl } from '@dereekb/util';
|
|
|
5
5
|
import { type UserExternalConnectionCredentials } from '../userexternalconnection.private';
|
|
6
6
|
import { type UserExternalConnectionAccessor } from '../userexternalconnection.accessor.service';
|
|
7
7
|
import { type UserExternalConnectionServerActions } from '../userexternalconnection.action.server';
|
|
8
|
-
import { type
|
|
8
|
+
import { type UserExternalConnectionSignInIdentity, type UserExternalConnectionSignInService } from '../userexternalconnection.signin';
|
|
9
|
+
import { type UserExternalConnectionProviderPolicyRegistry } from '../userexternalconnection.policy';
|
|
10
|
+
import { type UserExternalConnectionLinkStateActor, type UserExternalConnectionSignInStateActor, type UserExternalConnectionStateActor, type UserExternalConnectionStateCoder, type UserExternalConnectionStateMode } from './userexternalconnection.oauth.state';
|
|
9
11
|
import { type UserExternalConnectionOAuthServiceConfig } from './userexternalconnection.oauth.config';
|
|
12
|
+
import { type UserExternalConnectionSignInThrottle } from './userexternalconnection.oauth.throttle';
|
|
10
13
|
/**
|
|
11
14
|
* The `state` value carried through the authorization-code handoff.
|
|
12
15
|
*
|
|
@@ -14,11 +17,12 @@ import { type UserExternalConnectionOAuthServiceConfig } from './userexternalcon
|
|
|
14
17
|
*/
|
|
15
18
|
export type UserExternalConnectionOAuthState = string;
|
|
16
19
|
/**
|
|
17
|
-
* Identifies who a handoff belongs to, as resolved from a verified `state`.
|
|
20
|
+
* Identifies who (or what) a handoff belongs to, as resolved from a verified `state`.
|
|
21
|
+
*
|
|
22
|
+
* An alias of the state coder's own union rather than a second shape: the two would otherwise drift
|
|
23
|
+
* the moment a mode carried a new field.
|
|
18
24
|
*/
|
|
19
|
-
export
|
|
20
|
-
readonly uid: FirebaseAuthUserId;
|
|
21
|
-
}
|
|
25
|
+
export type UserExternalConnectionOAuthActor = UserExternalConnectionStateActor;
|
|
22
26
|
/**
|
|
23
27
|
* The raw callback query, as the provider sent it.
|
|
24
28
|
*
|
|
@@ -49,6 +53,14 @@ export interface UserExternalConnectionOAuthExchangeInput {
|
|
|
49
53
|
* a request target without checking it against an allowlist first.
|
|
50
54
|
*/
|
|
51
55
|
readonly query?: Maybe<UserExternalConnectionOAuthCallbackQueryValues>;
|
|
56
|
+
/**
|
|
57
|
+
* The PKCE code verifier whose challenge the authorize request carried, when it carried one.
|
|
58
|
+
*
|
|
59
|
+
* Present only for a sign-in, whose state is minted by this server and can therefore hold the
|
|
60
|
+
* verifier. A connect state is minted by the authenticated `read:authorizeState` call, which sends
|
|
61
|
+
* no challenge, so its exchange sends no verifier either.
|
|
62
|
+
*/
|
|
63
|
+
readonly codeVerifier?: Maybe<string>;
|
|
52
64
|
}
|
|
53
65
|
export interface UserExternalConnectionOAuthHandleCallbackInput {
|
|
54
66
|
/**
|
|
@@ -96,6 +108,16 @@ export interface UserExternalConnectionOAuthRefreshCredentialsInput {
|
|
|
96
108
|
*/
|
|
97
109
|
readonly credentials: UserExternalConnectionCredentials;
|
|
98
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* Input for {@link AbstractUserExternalConnectionOAuthService.revokeCredentials}.
|
|
113
|
+
*/
|
|
114
|
+
export interface UserExternalConnectionOAuthRevokeCredentialsInput {
|
|
115
|
+
readonly uid: FirebaseAuthUserId;
|
|
116
|
+
/**
|
|
117
|
+
* The credentials being discarded.
|
|
118
|
+
*/
|
|
119
|
+
readonly credentials: UserExternalConnectionCredentials;
|
|
120
|
+
}
|
|
99
121
|
export interface UserExternalConnectionOAuthCallbackResult {
|
|
100
122
|
readonly success: boolean;
|
|
101
123
|
/**
|
|
@@ -103,6 +125,133 @@ export interface UserExternalConnectionOAuthCallbackResult {
|
|
|
103
125
|
*/
|
|
104
126
|
readonly redirectUrl: WebsiteUrl;
|
|
105
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Input for {@link AbstractUserExternalConnectionOAuthService.authorizeUrlForState}.
|
|
130
|
+
*/
|
|
131
|
+
export interface UserExternalConnectionOAuthAuthorizeUrlInput {
|
|
132
|
+
readonly state: UserExternalConnectionOAuthState;
|
|
133
|
+
/**
|
|
134
|
+
* The PKCE code challenge to send to the provider, when the flow has one.
|
|
135
|
+
*
|
|
136
|
+
* Set for a sign-in, absent for a connect — see {@link UserExternalConnectionOAuthExchangeInput.codeVerifier}.
|
|
137
|
+
*/
|
|
138
|
+
readonly codeChallenge?: Maybe<string>;
|
|
139
|
+
/**
|
|
140
|
+
* Which direction the handoff runs in. Defaults to `connect`.
|
|
141
|
+
*
|
|
142
|
+
* This is how an adapter picks its SCOPE SET: the state is an opaque, encrypted envelope the adapter
|
|
143
|
+
* cannot read, so it cannot work the mode out for itself. `signin` and `link` both want the identity
|
|
144
|
+
* scopes; `connect` wants the data scopes, which are usually neither a superset nor a subset.
|
|
145
|
+
*/
|
|
146
|
+
readonly mode?: Maybe<UserExternalConnectionStateMode>;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Input for {@link AbstractUserExternalConnectionOAuthService.signInIdentityForCredentials}.
|
|
150
|
+
*/
|
|
151
|
+
export interface UserExternalConnectionOAuthSignInIdentityInput {
|
|
152
|
+
readonly credentials: UserExternalConnectionCredentials;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* The values a `/signin` request carries.
|
|
156
|
+
*/
|
|
157
|
+
export interface UserExternalConnectionOAuthSignInRequestValues {
|
|
158
|
+
/**
|
|
159
|
+
* The browser's PKCE challenge, which the eventual ticket is bound to.
|
|
160
|
+
*/
|
|
161
|
+
readonly challenge?: Maybe<string>;
|
|
162
|
+
/**
|
|
163
|
+
* Where in the app to return to. Validated against the config's allowlist before it is minted into
|
|
164
|
+
* the state — an unvalidated one is an open redirect.
|
|
165
|
+
*/
|
|
166
|
+
readonly returnPath?: Maybe<string>;
|
|
167
|
+
/**
|
|
168
|
+
* The caller's IP, for the throttle.
|
|
169
|
+
*/
|
|
170
|
+
readonly clientIp?: Maybe<string>;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Input for {@link AbstractUserExternalConnectionOAuthService.exchangeSignInTicket}.
|
|
174
|
+
*/
|
|
175
|
+
export interface UserExternalConnectionOAuthTicketExchangeInput {
|
|
176
|
+
readonly ticket?: Maybe<string>;
|
|
177
|
+
readonly verifier?: Maybe<string>;
|
|
178
|
+
readonly clientIp?: Maybe<string>;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* The custom token a redeemed ticket yields.
|
|
182
|
+
*/
|
|
183
|
+
export interface UserExternalConnectionOAuthTicketExchangeResult {
|
|
184
|
+
readonly customToken: string;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Reads the `/signin` request's values.
|
|
188
|
+
*
|
|
189
|
+
* @param request - The incoming sign-in request.
|
|
190
|
+
* @returns The challenge, return path, and client IP the request carried.
|
|
191
|
+
*/
|
|
192
|
+
/**
|
|
193
|
+
* The query parameter the sign-in ticket is returned on.
|
|
194
|
+
*/
|
|
195
|
+
export declare const USER_EXTERNAL_CONNECTION_SIGN_IN_TICKET_PARAM = "ticket";
|
|
196
|
+
export interface UserExternalConnectionSignInRedirectUrlInput {
|
|
197
|
+
/**
|
|
198
|
+
* The configured sign-in success URL.
|
|
199
|
+
*/
|
|
200
|
+
readonly baseUrl: WebsiteUrl;
|
|
201
|
+
/**
|
|
202
|
+
* The allowlisted return path, when the request named one.
|
|
203
|
+
*/
|
|
204
|
+
readonly returnPath?: Maybe<string>;
|
|
205
|
+
readonly ticket: string;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Builds the URL a completed sign-in redirects to.
|
|
209
|
+
*
|
|
210
|
+
* `returnPath` REPLACES the base URL's path rather than being appended to it, and has already been
|
|
211
|
+
* checked against the app's allowlist by the time it gets here — so the origin is always the
|
|
212
|
+
* configured one and this cannot become an open redirect.
|
|
213
|
+
*
|
|
214
|
+
* @param input - The base URL, the validated return path, and the ticket.
|
|
215
|
+
* @returns The redirect URL carrying the ticket.
|
|
216
|
+
*
|
|
217
|
+
* @__NO_SIDE_EFFECTS__
|
|
218
|
+
*/
|
|
219
|
+
export declare function userExternalConnectionSignInRedirectUrl(input: UserExternalConnectionSignInRedirectUrlInput): WebsiteUrl;
|
|
220
|
+
/**
|
|
221
|
+
* The query parameter a failed sign-in returns its reason code on.
|
|
222
|
+
*/
|
|
223
|
+
export declare const USER_EXTERNAL_CONNECTION_SIGN_IN_ERROR_PARAM = "signInError";
|
|
224
|
+
export interface UserExternalConnectionSignInFailureRedirectUrlInput {
|
|
225
|
+
/**
|
|
226
|
+
* The configured sign-in failure URL.
|
|
227
|
+
*/
|
|
228
|
+
readonly baseUrl: WebsiteUrl;
|
|
229
|
+
/**
|
|
230
|
+
* The allowlisted reason code, when the failure carried a reportable one.
|
|
231
|
+
*/
|
|
232
|
+
readonly errorCode?: Maybe<string>;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Builds the URL a failed sign-in redirects to.
|
|
236
|
+
*
|
|
237
|
+
* Mirrors {@link userExternalConnectionSignInRedirectUrl}, minus the return path: a refusal belongs
|
|
238
|
+
* on the page that can explain it, not wherever the sign-in was headed. The reason is a CODE the app
|
|
239
|
+
* maps to its own copy — a server message rendered verbatim in a browser is both an information leak
|
|
240
|
+
* and untranslatable.
|
|
241
|
+
*
|
|
242
|
+
* @param input - The base URL and the allowlisted reason code.
|
|
243
|
+
* @returns The redirect URL, carrying the reason when there was one.
|
|
244
|
+
*
|
|
245
|
+
* @__NO_SIDE_EFFECTS__
|
|
246
|
+
*/
|
|
247
|
+
export declare function userExternalConnectionSignInFailureRedirectUrl(input: UserExternalConnectionSignInFailureRedirectUrlInput): WebsiteUrl;
|
|
248
|
+
/**
|
|
249
|
+
* Reads the values a `/signin` request carries.
|
|
250
|
+
*
|
|
251
|
+
* @param request - The incoming sign-in request.
|
|
252
|
+
* @returns The challenge, return path, and client IP the request carried.
|
|
253
|
+
*/
|
|
254
|
+
export declare function userExternalConnectionOAuthSignInValuesForRequest(request: Request): UserExternalConnectionOAuthSignInRequestValues;
|
|
106
255
|
/**
|
|
107
256
|
* Reads the `state` an authorize request should carry to the provider.
|
|
108
257
|
*
|
|
@@ -136,7 +285,29 @@ export declare abstract class AbstractUserExternalConnectionOAuthService {
|
|
|
136
285
|
* it here would be a cycle. This service needs only the raw read.
|
|
137
286
|
*/
|
|
138
287
|
abstract readonly userExternalConnectionAccessor: UserExternalConnectionAccessor;
|
|
288
|
+
/**
|
|
289
|
+
* OPTIONAL: resolves a third-party identity to a Firebase uid and mints its custom token.
|
|
290
|
+
*
|
|
291
|
+
* Absent for an app that only ever CONNECTS providers — the sign-in routes then refuse every
|
|
292
|
+
* request, which is the correct behavior for an app that never asked for them. A provider adapter
|
|
293
|
+
* makes this available by taking it as an `@Optional()` injected constructor property.
|
|
294
|
+
*/
|
|
295
|
+
readonly userExternalConnectionSignInService?: Maybe<UserExternalConnectionSignInService>;
|
|
296
|
+
/**
|
|
297
|
+
* OPTIONAL: the app's per-provider policies. A missing registry means every provider takes the
|
|
298
|
+
* default policy, whose `signIn` is false.
|
|
299
|
+
*/
|
|
300
|
+
readonly userExternalConnectionProviderPolicyRegistry?: Maybe<UserExternalConnectionProviderPolicyRegistry>;
|
|
301
|
+
/**
|
|
302
|
+
* OPTIONAL: the rate limiter applied to the unauthenticated sign-in routes.
|
|
303
|
+
*
|
|
304
|
+
* When an app provides none, {@link memoryUserExternalConnectionSignInThrottle} is installed
|
|
305
|
+
* instead — an unthrottled account-creation endpoint is not an acceptable default, even though a
|
|
306
|
+
* per-process limiter is a weaker guarantee than a shared one.
|
|
307
|
+
*/
|
|
308
|
+
readonly userExternalConnectionSignInThrottle?: Maybe<UserExternalConnectionSignInThrottle>;
|
|
139
309
|
private readonly _logger;
|
|
310
|
+
private readonly _fallbackSignInThrottle;
|
|
140
311
|
protected get logger(): Logger;
|
|
141
312
|
get providerType(): UserExternalConnectionProviderType;
|
|
142
313
|
get redirectUri(): WebsiteUrl;
|
|
@@ -145,10 +316,26 @@ export declare abstract class AbstractUserExternalConnectionOAuthService {
|
|
|
145
316
|
/**
|
|
146
317
|
* PROVIDER: builds the provider's consent-screen URL carrying the minted state.
|
|
147
318
|
*
|
|
148
|
-
* @param
|
|
319
|
+
* @param input - The signed state to echo back on the callback, plus the PKCE challenge when the
|
|
320
|
+
* flow has one.
|
|
149
321
|
* @returns The authorize URL to redirect the user's browser to.
|
|
150
322
|
*/
|
|
151
|
-
protected abstract authorizeUrlForState(
|
|
323
|
+
protected abstract authorizeUrlForState(input: UserExternalConnectionOAuthAuthorizeUrlInput): WebsiteUrl;
|
|
324
|
+
/**
|
|
325
|
+
* PROVIDER (optional): reads the identity a SIGN-IN is attributed to.
|
|
326
|
+
*
|
|
327
|
+
* Optional because a connect needs no identity to succeed — an unlabeled connection is fully
|
|
328
|
+
* usable, which is why `credentialsForAuthorizationCode` treats the identity read as best-effort.
|
|
329
|
+
* A sign-in is the opposite: with no stable external id there is nothing to key the account on, so
|
|
330
|
+
* the default below fails hard rather than falling back to a mutable username or an email.
|
|
331
|
+
*
|
|
332
|
+
* Override it on a provider whose identity carries more than the exchange already captured — an
|
|
333
|
+
* email and its verified flag, which the account-linking rules depend on.
|
|
334
|
+
*
|
|
335
|
+
* @param input - The credentials the exchange produced.
|
|
336
|
+
* @returns The identity to sign in as.
|
|
337
|
+
*/
|
|
338
|
+
protected signInIdentityForCredentials(input: UserExternalConnectionOAuthSignInIdentityInput): Promise<UserExternalConnectionSignInIdentity>;
|
|
152
339
|
/**
|
|
153
340
|
* PROVIDER: exchanges the authorization code and maps the token response to credentials.
|
|
154
341
|
*
|
|
@@ -179,6 +366,21 @@ export declare abstract class AbstractUserExternalConnectionOAuthService {
|
|
|
179
366
|
* @returns The refreshed credentials.
|
|
180
367
|
*/
|
|
181
368
|
refreshCredentials?(input: UserExternalConnectionOAuthRefreshCredentialsInput): Promise<UserExternalConnectionCredentials>;
|
|
369
|
+
/**
|
|
370
|
+
* PROVIDER (optional): revokes the stored credentials at the provider.
|
|
371
|
+
*
|
|
372
|
+
* Deleting the stored credentials ends OUR ability to act as the user; it does not end the
|
|
373
|
+
* provider's grant, so a token captured before the disconnect stays usable until it expires — which
|
|
374
|
+
* for Discord is seven days. A provider implementing this closes that window.
|
|
375
|
+
*
|
|
376
|
+
* Optional and PUBLIC for the same reasons as `refreshCredentials`: not every provider exposes a
|
|
377
|
+
* revocation endpoint, and the caller reaches it through the registry rather than through a
|
|
378
|
+
* subclass. Implementations should not throw on an already-invalid token — a disconnect must
|
|
379
|
+
* succeed regardless of what the provider says about a credential it is about to forget.
|
|
380
|
+
*
|
|
381
|
+
* @param input - The acting user and the credentials being discarded.
|
|
382
|
+
*/
|
|
383
|
+
revokeCredentials?(input: UserExternalConnectionOAuthRevokeCredentialsInput): Promise<void>;
|
|
182
384
|
/**
|
|
183
385
|
* Carries the stored refresh token forward when a provider's exchange returned none.
|
|
184
386
|
*
|
|
@@ -203,6 +405,65 @@ export declare abstract class AbstractUserExternalConnectionOAuthService {
|
|
|
203
405
|
* @returns The authorize URL, or null when the request carried no state.
|
|
204
406
|
*/
|
|
205
407
|
authorizeUrlForRequest(request: Request): Maybe<WebsiteUrl>;
|
|
408
|
+
/**
|
|
409
|
+
* The provider's resolved policy.
|
|
410
|
+
*
|
|
411
|
+
* @returns The policy, with every optional field defaulted.
|
|
412
|
+
*/
|
|
413
|
+
get policy(): import("..").UserExternalConnectionResolvedProviderPolicy;
|
|
414
|
+
/**
|
|
415
|
+
* Whether this provider may be used to sign in.
|
|
416
|
+
*
|
|
417
|
+
* Requires BOTH the app's policy opt-in and a registered sign-in service: a policy that says yes
|
|
418
|
+
* with nothing able to resolve a uid would fail at the callback instead of at the front door.
|
|
419
|
+
*
|
|
420
|
+
* @returns True when a sign-in request for this provider may proceed.
|
|
421
|
+
*/
|
|
422
|
+
get signInEnabled(): boolean;
|
|
423
|
+
/**
|
|
424
|
+
* Where a sign-in returns to on success, before the ticket is appended.
|
|
425
|
+
*
|
|
426
|
+
* @returns The configured sign-in success url, falling back to the connect success url.
|
|
427
|
+
*/
|
|
428
|
+
get signInSuccessUrl(): WebsiteUrl;
|
|
429
|
+
/**
|
|
430
|
+
* Where a FAILED sign-in returns to, before the reason code is appended.
|
|
431
|
+
*
|
|
432
|
+
* Falls back to the connect failure url, which is the pre-existing behavior — but an app that
|
|
433
|
+
* configures one gets its login page instead of the auth-gated page a signed-out user cannot see.
|
|
434
|
+
*
|
|
435
|
+
* @returns The configured sign-in failure url, falling back to the connect failure url.
|
|
436
|
+
*/
|
|
437
|
+
get signInFailureUrl(): WebsiteUrl;
|
|
438
|
+
/**
|
|
439
|
+
* Builds the authorize URL for an unauthenticated SIGN-IN request.
|
|
440
|
+
*
|
|
441
|
+
* Unlike the connect direction, the state is minted HERE: there is no prior authenticated call to
|
|
442
|
+
* mint it, so the browser's PKCE challenge is what binds the flow instead of a uid. A provider PKCE
|
|
443
|
+
* verifier is generated at the same time and sealed into the same state, which is the only reason
|
|
444
|
+
* the exchange can answer a challenge without a server-side store.
|
|
445
|
+
*
|
|
446
|
+
* @param request - The incoming sign-in request.
|
|
447
|
+
* @returns The authorize URL, or null when the request must be bounced to the failure URL.
|
|
448
|
+
*/
|
|
449
|
+
signInUrlForRequest(request: Request): Promise<Maybe<WebsiteUrl>>;
|
|
450
|
+
/**
|
|
451
|
+
* Redeems a sign-in ticket for the custom token it carries.
|
|
452
|
+
*
|
|
453
|
+
* The token is handed back on a POST rather than in the redirect's query string: a URL-borne
|
|
454
|
+
* credential lands in browser history, the `Referer` header, and every proxy log on the way.
|
|
455
|
+
*
|
|
456
|
+
* @param input - The ticket and the verifier the browser retained.
|
|
457
|
+
* @returns The custom token, or null when the ticket cannot be redeemed.
|
|
458
|
+
*/
|
|
459
|
+
exchangeSignInTicket(input: UserExternalConnectionOAuthTicketExchangeInput): Promise<Maybe<UserExternalConnectionOAuthTicketExchangeResult>>;
|
|
460
|
+
/**
|
|
461
|
+
* Records a sign-in attempt against the throttle and returns whether it should be rejected.
|
|
462
|
+
*
|
|
463
|
+
* @param clientIp - The caller's IP, when one could be resolved.
|
|
464
|
+
* @returns True when the attempt is throttled.
|
|
465
|
+
*/
|
|
466
|
+
protected throttleSignInAttempt(clientIp: Maybe<string>): Promise<boolean>;
|
|
206
467
|
/**
|
|
207
468
|
* Verifies the returned state, exchanges the authorization code, and persists the credentials.
|
|
208
469
|
*
|
|
@@ -213,4 +474,36 @@ export declare abstract class AbstractUserExternalConnectionOAuthService {
|
|
|
213
474
|
* @returns Where to redirect the user, and whether the handoff succeeded.
|
|
214
475
|
*/
|
|
215
476
|
handleCallback(input: UserExternalConnectionOAuthHandleCallbackInput): Promise<UserExternalConnectionOAuthCallbackResult>;
|
|
477
|
+
/**
|
|
478
|
+
* Completes the SIGN-IN half of a callback: identity, uid, connection, custom token, ticket.
|
|
479
|
+
*
|
|
480
|
+
* The connection is written with the same paired write a connect uses, so a user who signed in
|
|
481
|
+
* through a provider is connected to it in exactly the same way — there is no second
|
|
482
|
+
* representation of "this user's Discord account" to keep in sync.
|
|
483
|
+
*
|
|
484
|
+
* @param actor - The verified sign-in state.
|
|
485
|
+
* @param exchanged - The credentials the code exchange produced.
|
|
486
|
+
* @returns The success URL, carrying the sign-in ticket.
|
|
487
|
+
*/
|
|
488
|
+
protected completeSignInCallback(actor: UserExternalConnectionSignInStateActor, exchanged: UserExternalConnectionCredentials): Promise<WebsiteUrl>;
|
|
489
|
+
/**
|
|
490
|
+
* Completes the LINK half of a callback: identity, login link, redirect.
|
|
491
|
+
*
|
|
492
|
+
* The narrowest of the three branches, and deliberately so. It stores NO credentials: the grant this
|
|
493
|
+
* round trip obtained carries the identity scopes, which are not the data scopes, so persisting it
|
|
494
|
+
* as the data connection would silently replace a broad grant with a narrow one.
|
|
495
|
+
*
|
|
496
|
+
* It also does NOT revoke anything. Re-authorizing the same OAuth client with narrower scopes may or
|
|
497
|
+
* may not invalidate the previously issued broad token depending on the provider — and on Discord a
|
|
498
|
+
* revoke drops the grant for the whole client, which would kill the data connection this link was
|
|
499
|
+
* meant to be independent of.
|
|
500
|
+
*
|
|
501
|
+
* Returns to the CONNECT success url rather than a link-specific one: the link is started from the
|
|
502
|
+
* settings page, which is where the user should land, and that is already what `successUrl` names.
|
|
503
|
+
*
|
|
504
|
+
* @param actor - The verified link state.
|
|
505
|
+
* @param exchanged - The credentials the code exchange produced.
|
|
506
|
+
* @returns The success URL.
|
|
507
|
+
*/
|
|
508
|
+
protected completeLinkCallback(actor: UserExternalConnectionLinkStateActor, exchanged: UserExternalConnectionCredentials): Promise<WebsiteUrl>;
|
|
216
509
|
}
|