@dereekb/firebase-server 13.32.0 → 13.34.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.cjs.default.js +1 -0
- package/calcom/index.cjs.js +1451 -0
- package/calcom/index.cjs.mjs +2 -0
- package/calcom/index.d.ts +1 -0
- package/calcom/index.esm.js +1437 -0
- package/calcom/package.json +29 -0
- package/calcom/src/index.d.ts +1 -0
- package/calcom/src/lib/calcom.oauth.connection.cache.d.ts +49 -0
- package/calcom/src/lib/calcom.oauth.connection.config.d.ts +75 -0
- package/calcom/src/lib/calcom.oauth.connection.context.d.ts +84 -0
- package/calcom/src/lib/calcom.oauth.connection.controller.d.ts +18 -0
- package/calcom/src/lib/calcom.oauth.connection.module.d.ts +55 -0
- package/calcom/src/lib/calcom.oauth.connection.service.d.ts +33 -0
- package/calcom/src/lib/index.d.ts +6 -0
- package/discord/index.cjs.default.js +1 -0
- package/discord/index.cjs.js +761 -0
- package/discord/index.cjs.mjs +2 -0
- package/discord/index.d.ts +1 -0
- package/discord/index.esm.js +753 -0
- package/discord/package.json +29 -0
- package/discord/src/index.d.ts +1 -0
- package/discord/src/lib/discord.oauth.connection.config.d.ts +69 -0
- package/discord/src/lib/discord.oauth.connection.controller.d.ts +18 -0
- package/discord/src/lib/discord.oauth.connection.module.d.ts +39 -0
- package/discord/src/lib/discord.oauth.connection.service.d.ts +43 -0
- package/discord/src/lib/index.d.ts +4 -0
- package/index.cjs.js +42 -9
- package/index.esm.js +42 -9
- package/mailgun/package.json +9 -9
- package/mcp/package.json +11 -11
- package/model/index.cjs.js +4243 -855
- package/model/index.esm.js +4183 -862
- package/model/package.json +10 -9
- package/model/src/lib/index.d.ts +2 -0
- package/model/src/lib/system/index.d.ts +2 -0
- package/model/src/lib/system/system.private.d.ts +63 -0
- package/model/src/lib/system/system.private.module.d.ts +70 -0
- package/model/src/lib/userexternalconnection/index.d.ts +8 -0
- package/model/src/lib/userexternalconnection/oauth/index.d.ts +7 -0
- package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.config.d.ts +110 -0
- package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.controller.d.ts +68 -0
- package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.error.d.ts +29 -0
- package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.refresh.d.ts +24 -0
- package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.registry.d.ts +54 -0
- package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.service.d.ts +216 -0
- package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.state.d.ts +114 -0
- package/model/src/lib/userexternalconnection/userexternalconnection.accessor.service.d.ts +111 -0
- package/model/src/lib/userexternalconnection/userexternalconnection.action.server.d.ts +172 -0
- package/model/src/lib/userexternalconnection/userexternalconnection.error.d.ts +44 -0
- package/model/src/lib/userexternalconnection/userexternalconnection.module.d.ts +129 -0
- package/model/src/lib/userexternalconnection/userexternalconnection.private.d.ts +192 -0
- package/model/src/lib/userexternalconnection/userexternalconnection.reader.service.d.ts +157 -0
- package/model/src/lib/userexternalconnection/userexternalconnection.refresh.service.d.ts +46 -0
- package/oidc/index.cjs.js +104 -78
- package/oidc/index.esm.js +104 -78
- package/oidc/package.json +10 -10
- package/package.json +24 -10
- package/src/lib/env/env.config.d.ts +15 -0
- package/src/lib/env/env.service.d.ts +7 -0
- package/src/lib/firestore/snapshot/snapshot.field.encrypt.d.ts +21 -2
- package/src/lib/nest/env/env.service.d.ts +1 -0
- package/test/index.cjs.js +14 -2
- package/test/index.esm.js +15 -3
- package/test/package.json +11 -11
- package/test/src/lib/firebase/firebase.admin.auth.d.ts +1 -1
- package/twilio/package.json +8 -8
- package/zoho/README.md +38 -0
- package/zoho/index.cjs.js +1418 -64
- package/zoho/index.esm.js +1401 -67
- package/zoho/package.json +13 -9
- package/zoho/src/lib/index.d.ts +6 -0
- package/zoho/src/lib/zoho.accounts.firebase.d.ts +10 -3
- package/zoho/src/lib/zoho.accounts.firebase.module.d.ts +51 -0
- package/zoho/src/lib/zoho.accounts.firebase.system.d.ts +51 -8
- package/zoho/src/lib/zoho.oauth.connection.cache.d.ts +45 -0
- package/zoho/src/lib/zoho.oauth.connection.config.d.ts +80 -0
- package/zoho/src/lib/zoho.oauth.connection.controller.d.ts +18 -0
- package/zoho/src/lib/zoho.oauth.connection.module.d.ts +43 -0
- package/zoho/src/lib/zoho.oauth.connection.service.d.ts +107 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { Logger } from '@nestjs/common';
|
|
2
|
+
import { type Request } from 'express';
|
|
3
|
+
import { type FirebaseAuthUserId, type UserExternalConnectionProviderType } from '@dereekb/firebase';
|
|
4
|
+
import { type Maybe, type WebsiteUrl } from '@dereekb/util';
|
|
5
|
+
import { type UserExternalConnectionCredentials } from '../userexternalconnection.private';
|
|
6
|
+
import { type UserExternalConnectionAccessor } from '../userexternalconnection.accessor.service';
|
|
7
|
+
import { type UserExternalConnectionServerActions } from '../userexternalconnection.action.server';
|
|
8
|
+
import { type UserExternalConnectionStateCoder } from './userexternalconnection.oauth.state';
|
|
9
|
+
import { type UserExternalConnectionOAuthServiceConfig } from './userexternalconnection.oauth.config';
|
|
10
|
+
/**
|
|
11
|
+
* The `state` value carried through the authorization-code handoff.
|
|
12
|
+
*
|
|
13
|
+
* Opaque to the provider: only {@link UserExternalConnectionStateCoder} can interpret it.
|
|
14
|
+
*/
|
|
15
|
+
export type UserExternalConnectionOAuthState = string;
|
|
16
|
+
/**
|
|
17
|
+
* Identifies who a handoff belongs to, as resolved from a verified `state`.
|
|
18
|
+
*/
|
|
19
|
+
export interface UserExternalConnectionOAuthActor {
|
|
20
|
+
readonly uid: FirebaseAuthUserId;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The raw callback query, as the provider sent it.
|
|
24
|
+
*
|
|
25
|
+
* Kept open rather than narrowed to the four RFC 6749 parameters, because providers send more than
|
|
26
|
+
* those and some of the extras are load-bearing: Zoho's `accounts-server` names the datacenter that
|
|
27
|
+
* issued the code, and an exchange sent to the wrong one fails. Nest's keyless `@Query()` already
|
|
28
|
+
* receives every parameter — only the typed view was dropping them.
|
|
29
|
+
*
|
|
30
|
+
* Declared here rather than beside the controller's typed view so the service does not have to
|
|
31
|
+
* import from the controller that imports it.
|
|
32
|
+
*/
|
|
33
|
+
export type UserExternalConnectionOAuthCallbackQueryValues = Record<string, Maybe<string>>;
|
|
34
|
+
export interface UserExternalConnectionOAuthExchangeInput {
|
|
35
|
+
/**
|
|
36
|
+
* The authorization code the provider issued.
|
|
37
|
+
*/
|
|
38
|
+
readonly code: string;
|
|
39
|
+
/**
|
|
40
|
+
* The redirect URI the code was issued against. Sent on the exchange because providers require it
|
|
41
|
+
* to match the one used on the authorize request.
|
|
42
|
+
*/
|
|
43
|
+
readonly redirectUri: WebsiteUrl;
|
|
44
|
+
/**
|
|
45
|
+
* The raw callback query, for a provider whose exchange needs a parameter beyond `code`.
|
|
46
|
+
*
|
|
47
|
+
* Optional, and most providers ignore it. Anything read from here arrived on a redirect the user's
|
|
48
|
+
* browser followed, so treat it as untrusted input — in particular, never use a value from here as
|
|
49
|
+
* a request target without checking it against an allowlist first.
|
|
50
|
+
*/
|
|
51
|
+
readonly query?: Maybe<UserExternalConnectionOAuthCallbackQueryValues>;
|
|
52
|
+
}
|
|
53
|
+
export interface UserExternalConnectionOAuthHandleCallbackInput {
|
|
54
|
+
/**
|
|
55
|
+
* The authorization code, present when the provider approved the request.
|
|
56
|
+
*/
|
|
57
|
+
readonly code?: Maybe<string>;
|
|
58
|
+
/**
|
|
59
|
+
* The state echoed back, identifying who is connecting.
|
|
60
|
+
*/
|
|
61
|
+
readonly state?: Maybe<UserExternalConnectionOAuthState>;
|
|
62
|
+
/**
|
|
63
|
+
* The OAuth error code, present when the provider refused instead of issuing a code.
|
|
64
|
+
*/
|
|
65
|
+
readonly error?: Maybe<string>;
|
|
66
|
+
/**
|
|
67
|
+
* The provider's explanation of the refusal.
|
|
68
|
+
*/
|
|
69
|
+
readonly errorDescription?: Maybe<string>;
|
|
70
|
+
/**
|
|
71
|
+
* The raw callback query, passed through to the exchange unchanged.
|
|
72
|
+
*/
|
|
73
|
+
readonly query?: Maybe<UserExternalConnectionOAuthCallbackQueryValues>;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Input for {@link AbstractUserExternalConnectionOAuthService.credentialsRetainingStoredRefreshToken}.
|
|
77
|
+
*/
|
|
78
|
+
export interface UserExternalConnectionOAuthRetainRefreshTokenInput {
|
|
79
|
+
readonly uid: FirebaseAuthUserId;
|
|
80
|
+
/**
|
|
81
|
+
* The credentials the exchange produced.
|
|
82
|
+
*/
|
|
83
|
+
readonly credentials: UserExternalConnectionCredentials;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Input for {@link AbstractUserExternalConnectionOAuthService.refreshCredentials}.
|
|
87
|
+
*
|
|
88
|
+
* Carries no `providerType` — the service already knows its own, and taking one would create a
|
|
89
|
+
* parameter that could disagree with it.
|
|
90
|
+
*/
|
|
91
|
+
export interface UserExternalConnectionOAuthRefreshCredentialsInput {
|
|
92
|
+
readonly uid: FirebaseAuthUserId;
|
|
93
|
+
/**
|
|
94
|
+
* The credentials currently stored for this provider, carrying the refresh token and any
|
|
95
|
+
* provider-specific `extra` the exchange needs.
|
|
96
|
+
*/
|
|
97
|
+
readonly credentials: UserExternalConnectionCredentials;
|
|
98
|
+
}
|
|
99
|
+
export interface UserExternalConnectionOAuthCallbackResult {
|
|
100
|
+
readonly success: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* The URL the user should be redirected to.
|
|
103
|
+
*/
|
|
104
|
+
readonly redirectUrl: WebsiteUrl;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Reads the `state` an authorize request should carry to the provider.
|
|
108
|
+
*
|
|
109
|
+
* A top-level browser navigation carries no credentials, so the state must have been minted by a
|
|
110
|
+
* prior authenticated `read:authorizeState` call and arrive here as the `state` query parameter.
|
|
111
|
+
*
|
|
112
|
+
* @param request - The incoming authorize request.
|
|
113
|
+
* @returns The state, when present.
|
|
114
|
+
*/
|
|
115
|
+
export declare function userExternalConnectionOAuthStateForRequest(request: Request): Maybe<UserExternalConnectionOAuthState>;
|
|
116
|
+
/**
|
|
117
|
+
* Drives a provider's authorization-code handoff into a user's UserExternalConnection.
|
|
118
|
+
*
|
|
119
|
+
* Everything except the two abstract members is identical for every OAuth 2.0 provider: resolving
|
|
120
|
+
* who is connecting from the signed `state`, surfacing a provider-side refusal, persisting the
|
|
121
|
+
* credentials, recording the failure code, and choosing the redirect. A provider adapter extends
|
|
122
|
+
* this and supplies only the OAuth mechanics its service actually differs on.
|
|
123
|
+
*
|
|
124
|
+
* Subclasses expose `config`, `stateCoder`, `userExternalConnectionActions`, and
|
|
125
|
+
* `userExternalConnectionAccessor` as injected constructor properties.
|
|
126
|
+
*/
|
|
127
|
+
export declare abstract class AbstractUserExternalConnectionOAuthService {
|
|
128
|
+
abstract readonly config: UserExternalConnectionOAuthServiceConfig;
|
|
129
|
+
abstract readonly stateCoder: UserExternalConnectionStateCoder;
|
|
130
|
+
abstract readonly userExternalConnectionActions: UserExternalConnectionServerActions;
|
|
131
|
+
/**
|
|
132
|
+
* The read half of the pair.
|
|
133
|
+
*
|
|
134
|
+
* Deliberately the accessor rather than `UserExternalConnectionReader`: the reader can refresh, and
|
|
135
|
+
* it finds its refresh path through the registry these services are registered in — so depending on
|
|
136
|
+
* it here would be a cycle. This service needs only the raw read.
|
|
137
|
+
*/
|
|
138
|
+
abstract readonly userExternalConnectionAccessor: UserExternalConnectionAccessor;
|
|
139
|
+
private readonly _logger;
|
|
140
|
+
protected get logger(): Logger;
|
|
141
|
+
get providerType(): UserExternalConnectionProviderType;
|
|
142
|
+
get redirectUri(): WebsiteUrl;
|
|
143
|
+
get successUrl(): WebsiteUrl;
|
|
144
|
+
get failureUrl(): WebsiteUrl;
|
|
145
|
+
/**
|
|
146
|
+
* PROVIDER: builds the provider's consent-screen URL carrying the minted state.
|
|
147
|
+
*
|
|
148
|
+
* @param state - The signed state to echo back on the callback.
|
|
149
|
+
* @returns The authorize URL to redirect the user's browser to.
|
|
150
|
+
*/
|
|
151
|
+
protected abstract authorizeUrlForState(state: UserExternalConnectionOAuthState): WebsiteUrl;
|
|
152
|
+
/**
|
|
153
|
+
* PROVIDER: exchanges the authorization code and maps the token response to credentials.
|
|
154
|
+
*
|
|
155
|
+
* Both halves are the provider's own: token endpoints differ in body encoding and client
|
|
156
|
+
* authentication, and only the provider knows how its response maps onto
|
|
157
|
+
* {@link UserExternalConnectionCredentials}. When a provider rotates its refresh token, the
|
|
158
|
+
* rotated one must be the one returned here — the token the exchange started with is spent.
|
|
159
|
+
*
|
|
160
|
+
* @param input - The authorization code, the redirect URI it was issued against, and the raw
|
|
161
|
+
* callback query.
|
|
162
|
+
* @returns The credentials to persist.
|
|
163
|
+
*/
|
|
164
|
+
protected abstract credentialsForAuthorizationCode(input: UserExternalConnectionOAuthExchangeInput): Promise<UserExternalConnectionCredentials>;
|
|
165
|
+
/**
|
|
166
|
+
* PROVIDER (optional): exchanges the stored refresh token for new credentials.
|
|
167
|
+
*
|
|
168
|
+
* Optional because not every provider has a refresh path worth wiring — and because a provider that
|
|
169
|
+
* does not implement this stays correct rather than silently broken: `UserExternalConnectionReader`
|
|
170
|
+
* treats its absence as "cannot renew" and makes the user reconnect.
|
|
171
|
+
*
|
|
172
|
+
* PUBLIC, unlike the two abstract members above, because the reader reaches it through the provider
|
|
173
|
+
* registry rather than through a subclass.
|
|
174
|
+
*
|
|
175
|
+
* Implementations return what the provider issued and do NOT need to carry forward values the
|
|
176
|
+
* response omitted — the reader merges every result over the stored credentials.
|
|
177
|
+
*
|
|
178
|
+
* @param input - The acting user and the credentials currently stored.
|
|
179
|
+
* @returns The refreshed credentials.
|
|
180
|
+
*/
|
|
181
|
+
refreshCredentials?(input: UserExternalConnectionOAuthRefreshCredentialsInput): Promise<UserExternalConnectionCredentials>;
|
|
182
|
+
/**
|
|
183
|
+
* Carries the stored refresh token forward when a provider's exchange returned none.
|
|
184
|
+
*
|
|
185
|
+
* The paired write replaces a provider's credentials wholesale, so persisting an exchange that
|
|
186
|
+
* omitted `refresh_token` would DESTROY a working one while leaving the entry `connected` — a
|
|
187
|
+
* connection that can never be refreshed again and does not look broken. Providers that do not
|
|
188
|
+
* rotate their refresh token (Zoho, and others that issue one only on first consent) hit this on
|
|
189
|
+
* every reconnect; a rotating provider never reaches the read.
|
|
190
|
+
*
|
|
191
|
+
* A read failure is deliberately allowed to propagate: failing the handoff loudly is strictly
|
|
192
|
+
* better than clobbering the stored token.
|
|
193
|
+
*
|
|
194
|
+
* @param input - The acting user and the credentials the exchange produced.
|
|
195
|
+
* @returns The credentials to persist, with a stored refresh token retained when the exchange
|
|
196
|
+
* returned none.
|
|
197
|
+
*/
|
|
198
|
+
protected credentialsRetainingStoredRefreshToken(input: UserExternalConnectionOAuthRetainRefreshTokenInput): Promise<UserExternalConnectionCredentials>;
|
|
199
|
+
/**
|
|
200
|
+
* Builds the authorize URL to redirect an incoming `/authorize` request to.
|
|
201
|
+
*
|
|
202
|
+
* @param request - The incoming authorize request, which the state is read from.
|
|
203
|
+
* @returns The authorize URL, or null when the request carried no state.
|
|
204
|
+
*/
|
|
205
|
+
authorizeUrlForRequest(request: Request): Maybe<WebsiteUrl>;
|
|
206
|
+
/**
|
|
207
|
+
* Verifies the returned state, exchanges the authorization code, and persists the credentials.
|
|
208
|
+
*
|
|
209
|
+
* A refusal reported by the provider (`error` / `error_description`) is surfaced as the failure
|
|
210
|
+
* reason, so a rejected scope or a denied consent is not misreported as a missing code.
|
|
211
|
+
*
|
|
212
|
+
* @param input - The query parameters the provider redirected back with.
|
|
213
|
+
* @returns Where to redirect the user, and whether the handoff succeeded.
|
|
214
|
+
*/
|
|
215
|
+
handleCallback(input: UserExternalConnectionOAuthHandleCallbackInput): Promise<UserExternalConnectionOAuthCallbackResult>;
|
|
216
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { type ConfigService } from '@nestjs/config';
|
|
2
|
+
import { type AES256GCMEncryptionSecret } from '@dereekb/nestjs';
|
|
3
|
+
import { type FirebaseServerEnvService } from '@dereekb/firebase-server';
|
|
4
|
+
import { type FirebaseAuthUserId, type UserExternalConnectionProviderType } from '@dereekb/firebase';
|
|
5
|
+
import { type Maybe, type Milliseconds } from '@dereekb/util';
|
|
6
|
+
/**
|
|
7
|
+
* Secret the external-connection OAuth `state` is encrypted with.
|
|
8
|
+
*
|
|
9
|
+
* Provider-agnostic on purpose: `state` is part of the OAuth 2.0 authorization-code flow itself
|
|
10
|
+
* (RFC 6749 4.1.1) and every provider echoes it back opaquely, so one secret serves the whole
|
|
11
|
+
* registry no matter how many providers are registered.
|
|
12
|
+
*
|
|
13
|
+
* Deliberately NOT the credentials secret. `USER_EXTERNAL_CONNECTION_ENCRYPTION_SECRET` is
|
|
14
|
+
* write-once — rotating it makes every stored `uecp` credential permanently undecryptable — whereas
|
|
15
|
+
* this one is freely rotatable, since a state lives for minutes and rotating it only invalidates
|
|
16
|
+
* handoffs that are mid-flight.
|
|
17
|
+
*/
|
|
18
|
+
export declare const USER_EXTERNAL_CONNECTION_STATE_SECRET_CONFIG_KEY = "USER_EXTERNAL_CONNECTION_STATE_SECRET";
|
|
19
|
+
/**
|
|
20
|
+
* Deterministic secret used when running in a testing environment and no real secret is configured,
|
|
21
|
+
* so specs never need a live credential.
|
|
22
|
+
*/
|
|
23
|
+
export declare const TESTING_USER_EXTERNAL_CONNECTION_STATE_SECRET: AES256GCMEncryptionSecret;
|
|
24
|
+
/**
|
|
25
|
+
* How long a minted `state` stays valid.
|
|
26
|
+
*
|
|
27
|
+
* Long enough for a user to work through a provider's consent screen, short enough that a leaked
|
|
28
|
+
* state is not reusable later.
|
|
29
|
+
*/
|
|
30
|
+
export declare const DEFAULT_USER_EXTERNAL_CONNECTION_STATE_EXPIRATION: Milliseconds;
|
|
31
|
+
/**
|
|
32
|
+
* The payload carried inside an encrypted external-connection OAuth `state`.
|
|
33
|
+
*/
|
|
34
|
+
export interface UserExternalConnectionStatePayload {
|
|
35
|
+
/**
|
|
36
|
+
* The user the handoff belongs to.
|
|
37
|
+
*/
|
|
38
|
+
readonly uid: FirebaseAuthUserId;
|
|
39
|
+
/**
|
|
40
|
+
* The provider the handoff was started for.
|
|
41
|
+
*
|
|
42
|
+
* Verified on the way back, so a state minted to connect one provider cannot be replayed against
|
|
43
|
+
* another provider's callback.
|
|
44
|
+
*/
|
|
45
|
+
readonly providerType: UserExternalConnectionProviderType;
|
|
46
|
+
/**
|
|
47
|
+
* Epoch milliseconds after which the state is rejected.
|
|
48
|
+
*/
|
|
49
|
+
readonly exp: number;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Who a verified state belongs to.
|
|
53
|
+
*/
|
|
54
|
+
export interface UserExternalConnectionStateActor {
|
|
55
|
+
readonly uid: FirebaseAuthUserId;
|
|
56
|
+
}
|
|
57
|
+
export interface MintUserExternalConnectionStateInput {
|
|
58
|
+
readonly uid: FirebaseAuthUserId;
|
|
59
|
+
readonly providerType: UserExternalConnectionProviderType;
|
|
60
|
+
}
|
|
61
|
+
export interface VerifyUserExternalConnectionStateInput {
|
|
62
|
+
readonly state: Maybe<string>;
|
|
63
|
+
/**
|
|
64
|
+
* The provider whose callback is verifying. A state minted for a different provider is rejected.
|
|
65
|
+
*/
|
|
66
|
+
readonly providerType: UserExternalConnectionProviderType;
|
|
67
|
+
}
|
|
68
|
+
export interface UserExternalConnectionStateCoderConfig {
|
|
69
|
+
readonly secret: AES256GCMEncryptionSecret;
|
|
70
|
+
/**
|
|
71
|
+
* How long a minted state stays valid. Defaults to {@link DEFAULT_USER_EXTERNAL_CONNECTION_STATE_EXPIRATION}.
|
|
72
|
+
*/
|
|
73
|
+
readonly expiresIn?: Maybe<Milliseconds>;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Mints and verifies the OAuth `state` for external-connection handoffs.
|
|
77
|
+
*
|
|
78
|
+
* Declared as an abstract class so it is its own injection token, matching
|
|
79
|
+
* `UserExternalConnectionModuleConfig`. One coder is shared by every registered provider.
|
|
80
|
+
*/
|
|
81
|
+
export declare abstract class UserExternalConnectionStateCoder {
|
|
82
|
+
/**
|
|
83
|
+
* Mints a short-lived state for a user's connect handoff with a provider.
|
|
84
|
+
*/
|
|
85
|
+
abstract readonly mintState: (input: MintUserExternalConnectionStateInput) => string;
|
|
86
|
+
/**
|
|
87
|
+
* Resolves the user a state belongs to, or null when it is absent, tampered with, expired, or was
|
|
88
|
+
* minted for a different provider.
|
|
89
|
+
*/
|
|
90
|
+
abstract readonly verifyState: (input: VerifyUserExternalConnectionStateInput) => Maybe<UserExternalConnectionStateActor>;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Creates the coder that mints and verifies the OAuth `state` for external-connection handoffs.
|
|
94
|
+
*
|
|
95
|
+
* The state is what lets a provider's redirect back to us be attributed to a user: the authorize
|
|
96
|
+
* request is a top-level browser navigation and carries no credentials of its own. Tamper-evidence
|
|
97
|
+
* is the requirement; AES-256-GCM is used because its auth tag provides that and additionally keeps
|
|
98
|
+
* the uid opaque to the browser.
|
|
99
|
+
*
|
|
100
|
+
* @param config - The encryption secret and optional expiration.
|
|
101
|
+
* @returns The state coder.
|
|
102
|
+
*
|
|
103
|
+
* @__NO_SIDE_EFFECTS__
|
|
104
|
+
*/
|
|
105
|
+
export declare function userExternalConnectionStateCoder(config: UserExternalConnectionStateCoderConfig): UserExternalConnectionStateCoder;
|
|
106
|
+
/**
|
|
107
|
+
* Builds the external-connection state coder from the environment.
|
|
108
|
+
*
|
|
109
|
+
* @param configService - The Nest config service used to read the state secret.
|
|
110
|
+
* @param envService - Used to detect a testing environment for the secret fallback.
|
|
111
|
+
* @returns The state coder.
|
|
112
|
+
* @throws {Error} When the configured secret is invalid outside a testing environment.
|
|
113
|
+
*/
|
|
114
|
+
export declare function userExternalConnectionStateCoderFactory(configService: ConfigService, envService: FirebaseServerEnvService): UserExternalConnectionStateCoder;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { type FactoryWithRequiredInput, type Maybe } from '@dereekb/util';
|
|
2
|
+
import { type FirebaseAuthUserId, type FirebaseAuthUserIdRef, type UserExternalConnectionEntry, type UserExternalConnectionFirestoreCollections, type UserExternalConnectionProviderType } from '@dereekb/firebase';
|
|
3
|
+
import { type UserExternalConnectionCredentials, type UserExternalConnectionServerFirestoreCollections } from './userexternalconnection.private';
|
|
4
|
+
/**
|
|
5
|
+
* Context required by {@link userExternalConnectionAccessor}.
|
|
6
|
+
*
|
|
7
|
+
* Carries both halves of the pair, the same as the server actions context. Unlike that context there
|
|
8
|
+
* is no `FirestoreContextReference` here: every read is a plain document read, so nothing in this
|
|
9
|
+
* file needs to start a transaction.
|
|
10
|
+
*/
|
|
11
|
+
export interface UserExternalConnectionAccessorContext extends UserExternalConnectionFirestoreCollections, UserExternalConnectionServerFirestoreCollections {
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Identifies the one provider entry a read is about.
|
|
15
|
+
*/
|
|
16
|
+
export interface UserExternalConnectionReadParams {
|
|
17
|
+
readonly uid: FirebaseAuthUserId;
|
|
18
|
+
readonly providerType: UserExternalConnectionProviderType;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Both halves of a user's connection state for a single provider.
|
|
22
|
+
*
|
|
23
|
+
* The public entry and the private credentials are returned together because a caller deciding
|
|
24
|
+
* whether it can act as this user needs both: the credentials alone cannot say whether the
|
|
25
|
+
* connection is `connected` or `error`, and the entry alone cannot be used to call anything.
|
|
26
|
+
*
|
|
27
|
+
* Either side may be null. A user with no connection document at all reads as both null.
|
|
28
|
+
*/
|
|
29
|
+
export interface UserExternalConnectionForProvider {
|
|
30
|
+
readonly uid: FirebaseAuthUserId;
|
|
31
|
+
readonly providerType: UserExternalConnectionProviderType;
|
|
32
|
+
/**
|
|
33
|
+
* The provider's entry on the client-readable document, when the user has one.
|
|
34
|
+
*/
|
|
35
|
+
readonly entry: Maybe<UserExternalConnectionEntry>;
|
|
36
|
+
/**
|
|
37
|
+
* The provider's stored credentials in plaintext, when the user has any.
|
|
38
|
+
*/
|
|
39
|
+
readonly credentials: Maybe<UserExternalConnectionCredentials>;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Input identifying the user a {@link UserExternalConnectionAccessorUserInstance} reads for.
|
|
43
|
+
*/
|
|
44
|
+
export interface UserExternalConnectionAccessorUserInput extends FirebaseAuthUserIdRef {
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* A {@link UserExternalConnectionAccessor} narrowed to ONE user and ONE provider.
|
|
48
|
+
*
|
|
49
|
+
* The accessor's entire read surface with `{ uid, providerType }` already applied.
|
|
50
|
+
*/
|
|
51
|
+
export interface UserExternalConnectionAccessorProviderInstance {
|
|
52
|
+
readonly uid: FirebaseAuthUserId;
|
|
53
|
+
readonly providerType: UserExternalConnectionProviderType;
|
|
54
|
+
/**
|
|
55
|
+
* Loads both halves of the pair.
|
|
56
|
+
*/
|
|
57
|
+
readUserExternalConnectionForProvider(): Promise<UserExternalConnectionForProvider>;
|
|
58
|
+
/**
|
|
59
|
+
* Loads only the stored credentials.
|
|
60
|
+
*/
|
|
61
|
+
readUserExternalConnectionCredentials(): Promise<Maybe<UserExternalConnectionCredentials>>;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* A {@link UserExternalConnectionAccessor} narrowed to one user, awaiting the provider to target.
|
|
65
|
+
*/
|
|
66
|
+
export type UserExternalConnectionAccessorUserInstance = FactoryWithRequiredInput<UserExternalConnectionAccessorProviderInstance, UserExternalConnectionProviderType>;
|
|
67
|
+
/**
|
|
68
|
+
* Server-only read surface for the UserExternalConnection document pair.
|
|
69
|
+
*
|
|
70
|
+
* Deliberately the whole read surface and nothing more: no expiration policy, no refresh, no
|
|
71
|
+
* assertions. That keeps this usable by the OAuth provider services themselves — they need to read
|
|
72
|
+
* the credentials they are about to replace, and a tier that could refresh would have to know about
|
|
73
|
+
* the provider registry those services are registered in.
|
|
74
|
+
*
|
|
75
|
+
* {@link UserExternalConnectionReader} wraps this and adds the policy.
|
|
76
|
+
*/
|
|
77
|
+
export declare abstract class UserExternalConnectionAccessor {
|
|
78
|
+
/**
|
|
79
|
+
* Narrows this accessor to one user, returning a factory that narrows it further to one provider.
|
|
80
|
+
*
|
|
81
|
+
* The accessor's only entry point, and the same two levels
|
|
82
|
+
* {@link UserExternalConnectionReader.readerForUser} has, so a caller holding either states the user
|
|
83
|
+
* and provider it is reading for once:
|
|
84
|
+
*
|
|
85
|
+
* ```ts
|
|
86
|
+
* const credentials = await accessor.accessorForUser({ uid })(CALCOM).readUserExternalConnectionCredentials();
|
|
87
|
+
* ```
|
|
88
|
+
*
|
|
89
|
+
* @param input - The user to read for.
|
|
90
|
+
* @returns A factory producing an accessor for whichever of that user's providers is needed.
|
|
91
|
+
*/
|
|
92
|
+
abstract accessorForUser(input: UserExternalConnectionAccessorUserInput): UserExternalConnectionAccessorUserInstance;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Reference to a {@link UserExternalConnectionAccessor} instance.
|
|
96
|
+
*/
|
|
97
|
+
export interface UserExternalConnectionAccessorRef {
|
|
98
|
+
readonly userExternalConnectionAccessor: UserExternalConnectionAccessor;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Creates a {@link UserExternalConnectionAccessor} bound to the given context.
|
|
102
|
+
*
|
|
103
|
+
* Reads are NOT paired the way writes are. The pairing is a write invariant — the two documents are
|
|
104
|
+
* only ever written together, so a read of one cannot observe a state the other contradicts, and
|
|
105
|
+
* reading them in a transaction would buy nothing. Server paths load both halves; the client can only
|
|
106
|
+
* ever load the public one.
|
|
107
|
+
*
|
|
108
|
+
* @param context - The context carrying both halves of the pair.
|
|
109
|
+
* @returns A concrete UserExternalConnectionAccessor implementation.
|
|
110
|
+
*/
|
|
111
|
+
export declare function userExternalConnectionAccessor(context: UserExternalConnectionAccessorContext): UserExternalConnectionAccessor;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { type Maybe } from '@dereekb/util';
|
|
2
|
+
import { type FirebaseAuthUserId, type FirestoreContextReference, type UserExternalConnectionDocument, type UserExternalConnectionEntryStatus, type UserExternalConnectionErrorCode, type UserExternalConnectionFirestoreCollections, type UserExternalConnectionProviderType } from '@dereekb/firebase';
|
|
3
|
+
import { type UserExternalConnectionCredentials, type UserExternalConnectionServerFirestoreCollections } from './userexternalconnection.private';
|
|
4
|
+
/**
|
|
5
|
+
* Context required by {@link userExternalConnectionServerActions}.
|
|
6
|
+
*
|
|
7
|
+
* Carries BOTH halves of the pair. Nothing else in the workspace should hold the private collection.
|
|
8
|
+
*/
|
|
9
|
+
export interface UserExternalConnectionServerActionsContext extends FirestoreContextReference, UserExternalConnectionFirestoreCollections, UserExternalConnectionServerFirestoreCollections {
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Reference to a {@link UserExternalConnectionServerActions} instance.
|
|
13
|
+
*/
|
|
14
|
+
export interface UserExternalConnectionServerActionsRef {
|
|
15
|
+
readonly userExternalConnectionActions: UserExternalConnectionServerActions;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Parameters for connecting a user to a provider.
|
|
19
|
+
*
|
|
20
|
+
* NOTE what is absent: there is no parameter for `status`, `scopes`, `externalAccountId`,
|
|
21
|
+
* `expiresAt`, `connectedAt`, `updatedAt`, or the connected-provider array. Every one of those is
|
|
22
|
+
* derived from `credentials`, so a caller has no way to submit a summary that contradicts the
|
|
23
|
+
* credentials it summarizes. `label` rides on the credentials because it is a fact about the grant.
|
|
24
|
+
*/
|
|
25
|
+
export interface UserExternalConnectionConnectParams {
|
|
26
|
+
readonly uid: FirebaseAuthUserId;
|
|
27
|
+
readonly providerType: UserExternalConnectionProviderType;
|
|
28
|
+
readonly credentials: UserExternalConnectionCredentials;
|
|
29
|
+
/**
|
|
30
|
+
* Optional instant to apply the change at. Defaults to now.
|
|
31
|
+
*/
|
|
32
|
+
readonly now?: Maybe<Date>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Parameters for replacing a provider's credentials after a token refresh.
|
|
36
|
+
*/
|
|
37
|
+
export type UserExternalConnectionRefreshCredentialsParams = UserExternalConnectionConnectParams;
|
|
38
|
+
/**
|
|
39
|
+
* Parameters for marking a provider's connection as errored.
|
|
40
|
+
*
|
|
41
|
+
* The stored credentials are retained so the connection can be repaired without a full reconnect.
|
|
42
|
+
*/
|
|
43
|
+
export interface UserExternalConnectionMarkErrorParams {
|
|
44
|
+
readonly uid: FirebaseAuthUserId;
|
|
45
|
+
readonly providerType: UserExternalConnectionProviderType;
|
|
46
|
+
readonly error?: Maybe<UserExternalConnectionErrorCode>;
|
|
47
|
+
readonly now?: Maybe<Date>;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Parameters for disconnecting a user from a provider.
|
|
51
|
+
*/
|
|
52
|
+
export interface UserExternalConnectionDisconnectParams {
|
|
53
|
+
readonly uid: FirebaseAuthUserId;
|
|
54
|
+
readonly providerType: UserExternalConnectionProviderType;
|
|
55
|
+
/**
|
|
56
|
+
* Whether to retain a `disconnected` history entry on the public document rather than removing the
|
|
57
|
+
* provider's key. The credentials are removed either way. Defaults to false.
|
|
58
|
+
*/
|
|
59
|
+
readonly retainEntry?: Maybe<boolean>;
|
|
60
|
+
readonly now?: Maybe<Date>;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Parameters for creating a user's connection document.
|
|
64
|
+
*/
|
|
65
|
+
export interface UserExternalConnectionCreateParams {
|
|
66
|
+
readonly uid: FirebaseAuthUserId;
|
|
67
|
+
/**
|
|
68
|
+
* Optional instant to stamp the new document with. Defaults to now.
|
|
69
|
+
*/
|
|
70
|
+
readonly now?: Maybe<Date>;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Parameters for deleting a user's entire connection pair.
|
|
74
|
+
*/
|
|
75
|
+
export interface UserExternalConnectionDeleteAllParams {
|
|
76
|
+
readonly uid: FirebaseAuthUserId;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Server-only actions for the UserExternalConnection document pair.
|
|
80
|
+
*
|
|
81
|
+
* This is the ENTIRE write surface, and ONLY the write surface. The two collections are never exposed
|
|
82
|
+
* for independent mutation, so there is no way for a caller to write one document without the other —
|
|
83
|
+
* and therefore no sync, reconciliation, or drift-detection process to maintain.
|
|
84
|
+
*
|
|
85
|
+
* Reading is `UserExternalConnectionAccessor` (raw) or `UserExternalConnectionReader` (the one a
|
|
86
|
+
* consumer wants). A read used to live here too, which meant every path that only needed to look at a
|
|
87
|
+
* user's credentials had to hold the write surface to do it.
|
|
88
|
+
*/
|
|
89
|
+
export declare abstract class UserExternalConnectionServerActions {
|
|
90
|
+
abstract createUserExternalConnection(params: UserExternalConnectionCreateParams): Promise<UserExternalConnectionDocument>;
|
|
91
|
+
abstract connectUserExternalConnection(params: UserExternalConnectionConnectParams): Promise<UserExternalConnectionDocument>;
|
|
92
|
+
abstract refreshUserExternalConnectionCredentials(params: UserExternalConnectionRefreshCredentialsParams): Promise<UserExternalConnectionDocument>;
|
|
93
|
+
abstract markUserExternalConnectionError(params: UserExternalConnectionMarkErrorParams): Promise<UserExternalConnectionDocument>;
|
|
94
|
+
abstract disconnectUserExternalConnection(params: UserExternalConnectionDisconnectParams): Promise<UserExternalConnectionDocument>;
|
|
95
|
+
abstract deleteAllUserExternalConnectionsForUser(params: UserExternalConnectionDeleteAllParams): Promise<void>;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* The single write a per-user token cache needs: persisting credentials the provider just issued.
|
|
99
|
+
*
|
|
100
|
+
* Narrower than {@link UserExternalConnectionServerActions} on purpose. A token cache has no business
|
|
101
|
+
* connecting, disconnecting, or deleting anything, and the resolved document is of no use to it — hence
|
|
102
|
+
* the unconstrained result, which also means a caller can satisfy this without producing a document it
|
|
103
|
+
* would only throw away.
|
|
104
|
+
*/
|
|
105
|
+
export interface UserExternalConnectionCredentialsWriter {
|
|
106
|
+
refreshUserExternalConnectionCredentials(params: UserExternalConnectionRefreshCredentialsParams): Promise<unknown>;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* The two writes a reader performs: persisting a refresh, and recording that a provider rejected the
|
|
110
|
+
* credentials.
|
|
111
|
+
*
|
|
112
|
+
* Also narrower than {@link UserExternalConnectionServerActions} on purpose — a read surface has no
|
|
113
|
+
* business creating or deleting a connection — and for the same reason unconstrained in its results.
|
|
114
|
+
*/
|
|
115
|
+
export interface UserExternalConnectionCredentialsAndFailureWriter extends UserExternalConnectionCredentialsWriter {
|
|
116
|
+
markUserExternalConnectionError(params: UserExternalConnectionMarkErrorParams): Promise<unknown>;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Creates a {@link UserExternalConnectionServerActions} bound to the given context.
|
|
120
|
+
*
|
|
121
|
+
* @param context - The context carrying both halves of the connection pair.
|
|
122
|
+
* @returns A concrete UserExternalConnectionServerActions implementation.
|
|
123
|
+
*/
|
|
124
|
+
export declare function userExternalConnectionServerActions(context: UserExternalConnectionServerActionsContext): UserExternalConnectionServerActions;
|
|
125
|
+
/**
|
|
126
|
+
* Creates a function that creates a user's connection document.
|
|
127
|
+
*
|
|
128
|
+
* Only the public half is written: the private half exists to hold credentials, and the paired write
|
|
129
|
+
* creates it on the first connect. Creation runs in a transaction so two concurrent calls cannot both
|
|
130
|
+
* see an absent document and both write one.
|
|
131
|
+
*
|
|
132
|
+
* @param context - The context carrying both halves of the pair.
|
|
133
|
+
* @returns A function that creates the document for a uid, throwing if it already exists.
|
|
134
|
+
*/
|
|
135
|
+
export declare function createUserExternalConnectionFactory(context: UserExternalConnectionServerActionsContext): (params: UserExternalConnectionCreateParams) => Promise<UserExternalConnectionDocument>;
|
|
136
|
+
/**
|
|
137
|
+
* Parameters for the paired write.
|
|
138
|
+
*/
|
|
139
|
+
export interface WriteUserExternalConnectionPairParams {
|
|
140
|
+
readonly uid: FirebaseAuthUserId;
|
|
141
|
+
readonly providerType: UserExternalConnectionProviderType;
|
|
142
|
+
/**
|
|
143
|
+
* The outcome the operation produced. Drives BOTH sides of the pair.
|
|
144
|
+
*/
|
|
145
|
+
readonly outcome: UserExternalConnectionEntryStatus;
|
|
146
|
+
/**
|
|
147
|
+
* The credentials the outcome produced. Required for a `connected` outcome; ignored for a
|
|
148
|
+
* `disconnected` one (which always removes the stored credentials).
|
|
149
|
+
*/
|
|
150
|
+
readonly credentials?: Maybe<UserExternalConnectionCredentials>;
|
|
151
|
+
readonly error?: Maybe<UserExternalConnectionErrorCode>;
|
|
152
|
+
readonly retainEntry?: Maybe<boolean>;
|
|
153
|
+
readonly now?: Maybe<Date>;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Creates the single function through which every mutation of the connection pair flows.
|
|
157
|
+
*
|
|
158
|
+
* Both documents are loaded from the same transaction, all reads happen before any write (a
|
|
159
|
+
* Firestore transaction requirement), and both are written with the COMPLETE next value derived from
|
|
160
|
+
* one input. A failure at any point leaves neither document changed.
|
|
161
|
+
*
|
|
162
|
+
* @param context - The context carrying both halves of the pair.
|
|
163
|
+
* @returns A function that applies one provider's outcome to both documents atomically.
|
|
164
|
+
*/
|
|
165
|
+
export declare function writeUserExternalConnectionPairInTransactionFactory(context: UserExternalConnectionServerActionsContext): (params: WriteUserExternalConnectionPairParams) => Promise<UserExternalConnectionDocument>;
|
|
166
|
+
/**
|
|
167
|
+
* Creates a function that deletes a user's entire connection pair in one transaction.
|
|
168
|
+
*
|
|
169
|
+
* @param context - The context carrying both halves of the pair.
|
|
170
|
+
* @returns A function that removes both documents for a uid.
|
|
171
|
+
*/
|
|
172
|
+
export declare function deleteAllUserExternalConnectionsForUserFactory(context: UserExternalConnectionServerActionsContext): (params: UserExternalConnectionDeleteAllParams) => Promise<void>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type FirebaseAuthUserId, type UserExternalConnectionProviderType } from '@dereekb/firebase';
|
|
2
|
+
export declare const USER_EXTERNAL_CONNECTION_PROVIDER_NOT_CONNECTED_ERROR_CODE = "USER_EXTERNAL_CONNECTION_PROVIDER_NOT_CONNECTED";
|
|
3
|
+
export declare const USER_EXTERNAL_CONNECTION_PROVIDER_NOT_ALLOWED_ERROR_CODE = "USER_EXTERNAL_CONNECTION_PROVIDER_NOT_ALLOWED";
|
|
4
|
+
export declare const USER_EXTERNAL_CONNECTION_ALREADY_EXISTS_ERROR_CODE = "USER_EXTERNAL_CONNECTION_ALREADY_EXISTS";
|
|
5
|
+
export declare const USER_EXTERNAL_CONNECTION_CREDENTIALS_EXPIRED_ERROR_CODE = "USER_EXTERNAL_CONNECTION_CREDENTIALS_EXPIRED";
|
|
6
|
+
/**
|
|
7
|
+
* Creates an error indicating the user already has a connection document.
|
|
8
|
+
*
|
|
9
|
+
* There is exactly one per user, so creating a second is a caller mistake rather than a conflict to
|
|
10
|
+
* resolve. Clients that create on page load are expected to skip the call when the document is
|
|
11
|
+
* already loaded, and to treat this code as success when two of them race.
|
|
12
|
+
*
|
|
13
|
+
* @param uid - The user whose document already exists.
|
|
14
|
+
* @returns A precondition-conflict HttpsError.
|
|
15
|
+
*/
|
|
16
|
+
export declare function userExternalConnectionAlreadyExistsError(uid: FirebaseAuthUserId): import("firebase-functions/https").HttpsError;
|
|
17
|
+
/**
|
|
18
|
+
* Creates an error indicating the user has no connection to the requested provider.
|
|
19
|
+
*
|
|
20
|
+
* @param providerType - The provider that was requested.
|
|
21
|
+
* @returns A precondition-conflict HttpsError.
|
|
22
|
+
*/
|
|
23
|
+
export declare function userExternalConnectionProviderNotConnectedError(providerType: UserExternalConnectionProviderType): import("firebase-functions/https").HttpsError;
|
|
24
|
+
/**
|
|
25
|
+
* Creates an error indicating the user's credentials for a provider have expired and could not be
|
|
26
|
+
* renewed.
|
|
27
|
+
*
|
|
28
|
+
* Distinct from {@link userExternalConnectionProviderNotConnectedError}: the user IS connected and the
|
|
29
|
+
* credentials are still stored, they just cannot be used right now. Either no refresher was configured,
|
|
30
|
+
* the provider has no refresh path, or the refresh itself failed. The remedy for the last of those is a
|
|
31
|
+
* reconnect; for the first two it is a configuration change, so the code is deliberately the same and
|
|
32
|
+
* the distinction is left to the server logs.
|
|
33
|
+
*
|
|
34
|
+
* @param providerType - The provider whose credentials expired.
|
|
35
|
+
* @returns A precondition-conflict HttpsError.
|
|
36
|
+
*/
|
|
37
|
+
export declare function userExternalConnectionCredentialsExpiredError(providerType: UserExternalConnectionProviderType): import("firebase-functions/https").HttpsError;
|
|
38
|
+
/**
|
|
39
|
+
* Creates an error indicating the requested provider is not one this app allows connecting to.
|
|
40
|
+
*
|
|
41
|
+
* @param providerType - The provider that was requested.
|
|
42
|
+
* @returns A precondition-conflict HttpsError.
|
|
43
|
+
*/
|
|
44
|
+
export declare function userExternalConnectionProviderNotAllowedError(providerType: UserExternalConnectionProviderType): import("firebase-functions/https").HttpsError;
|