Skip to content

Commit 9e25843

Browse files
authored
Merge branch 'v14' into lm-drop-ns
2 parents f0b9743 + c3d58e4 commit 9e25843

8 files changed

Lines changed: 383 additions & 41 deletions

File tree

etc/firebase-admin.auth.api.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,8 +232,15 @@ export interface CreatePhoneMultiFactorInfoRequest extends BaseCreateMultiFactor
232232
}
233233

234234
// @public
235-
export interface CreateRequest extends UpdateRequest {
235+
export interface CreateRequest {
236+
disabled?: boolean;
237+
displayName?: string;
238+
email?: string;
239+
emailVerified?: boolean;
236240
multiFactor?: MultiFactorCreateSettings;
241+
password?: string;
242+
phoneNumber?: string;
243+
photoURL?: string;
237244
uid?: string;
238245
}
239246

src/auth/auth-api-request.ts

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -127,14 +127,15 @@ class AuthResourceUrlBuilder {
127127
/**
128128
* The resource URL builder constructor.
129129
*
130-
* @param projectId - The resource project ID.
130+
* @param app - The app for this URL builder.
131131
* @param version - The endpoint API version.
132+
* @param emulatorHost - Optional emulator host captured at init time.
132133
* @constructor
133134
*/
134-
constructor(protected app: App, protected version: string = 'v1') {
135-
if (useEmulator()) {
135+
constructor(protected app: App, protected version: string = 'v1', emHost?: string) {
136+
if (emHost) {
136137
this.urlFormat = utils.formatString(FIREBASE_AUTH_EMULATOR_BASE_URL_FORMAT, {
137-
host: emulatorHost()
138+
host: emHost
138139
});
139140
} else {
140141
this.urlFormat = FIREBASE_AUTH_BASE_URL_FORMAT;
@@ -191,16 +192,17 @@ class TenantAwareAuthResourceUrlBuilder extends AuthResourceUrlBuilder {
191192
/**
192193
* The tenant aware resource URL builder constructor.
193194
*
194-
* @param projectId - The resource project ID.
195+
* @param app - The app for this URL builder.
195196
* @param version - The endpoint API version.
196197
* @param tenantId - The tenant ID.
198+
* @param emHost - Optional emulator host captured at init time.
197199
* @constructor
198200
*/
199-
constructor(protected app: App, protected version: string, protected tenantId: string) {
200-
super(app, version);
201-
if (useEmulator()) {
201+
constructor(protected app: App, protected version: string, protected tenantId: string, emHost?: string) {
202+
super(app, version, emHost);
203+
if (emHost) {
202204
this.urlFormat = utils.formatString(FIREBASE_AUTH_EMULATOR_TENANT_URL_FORMAT, {
203-
host: emulatorHost()
205+
host: emHost
204206
});
205207
} else {
206208
this.urlFormat = FIREBASE_AUTH_TENANT_URL_FORMAT;
@@ -229,8 +231,15 @@ class TenantAwareAuthResourceUrlBuilder extends AuthResourceUrlBuilder {
229231
*/
230232
class AuthHttpClient extends AuthorizedHttpClient {
231233

234+
private readonly isEmulator: boolean;
235+
236+
constructor(app: FirebaseApp, isEmulator: boolean) {
237+
super(app);
238+
this.isEmulator = isEmulator;
239+
}
240+
232241
protected getToken(): Promise<string> {
233-
if (useEmulator()) {
242+
if (this.isEmulator) {
234243
return Promise.resolve('owner');
235244
}
236245

@@ -1048,6 +1057,7 @@ const LIST_INBOUND_SAML_CONFIGS = new ApiSettings('/inboundSamlConfigs', 'GET')
10481057
export abstract class AbstractAuthRequestHandler {
10491058

10501059
protected readonly httpClient: AuthorizedHttpClient;
1060+
public readonly emulatorHostValue: string | undefined;
10511061
private authUrlBuilder: AuthResourceUrlBuilder;
10521062
private projectConfigUrlBuilder: AuthResourceUrlBuilder;
10531063

@@ -1102,17 +1112,21 @@ export abstract class AbstractAuthRequestHandler {
11021112

11031113
/**
11041114
* @param app - The app used to fetch access tokens to sign API requests.
1115+
* @param emHost - Optional emulator host override. When provided (including
1116+
* null for explicitly no emulator), this value is used instead of reading
1117+
* from the FIREBASE_AUTH_EMULATOR_HOST environment variable.
11051118
* @constructor
11061119
*/
1107-
constructor(protected readonly app: App) {
1120+
constructor(protected readonly app: App, emHost?: string | null) {
11081121
if (typeof app !== 'object' || app === null || !('options' in app)) {
11091122
throw new FirebaseAuthError(
11101123
authClientErrorCode.INVALID_ARGUMENT,
11111124
'First argument passed to admin.auth() must be a valid Firebase app instance.',
11121125
);
11131126
}
11141127

1115-
this.httpClient = new AuthHttpClient(app as FirebaseApp);
1128+
this.emulatorHostValue = emHost !== undefined ? (emHost || undefined) : emulatorHost();
1129+
this.httpClient = new AuthHttpClient(app as FirebaseApp, !!this.emulatorHostValue);
11161130
}
11171131

11181132
/**
@@ -2021,6 +2035,11 @@ export abstract class AbstractAuthRequestHandler {
20212035
/** Instantiates the getConfig endpoint settings. */
20222036
const GET_PROJECT_CONFIG = new ApiSettings('/config', 'GET')
20232037
.setResponseValidator((response: RequestResponse) => {
2038+
// The Auth emulator does not populate the resource `name` field on the
2039+
// project config response, so skip the assertion when running against it.
2040+
if (useEmulator()) {
2041+
return;
2042+
}
20242043
const data = response.data;
20252044
// Response should always contain at least the config name.
20262045
if (!validator.isNonEmptyString(data?.name)) {
@@ -2035,6 +2054,11 @@ const GET_PROJECT_CONFIG = new ApiSettings('/config', 'GET')
20352054
/** Instantiates the updateConfig endpoint settings. */
20362055
const UPDATE_PROJECT_CONFIG = new ApiSettings('/config?updateMask={updateMask}', 'PATCH')
20372056
.setResponseValidator((response: RequestResponse) => {
2057+
// The Auth emulator does not populate the resource `name` field on the
2058+
// project config response, so skip the assertion when running against it.
2059+
if (useEmulator()) {
2060+
return;
2061+
}
20382062
const data = response.data;
20392063
// Response should always contain at least the config name.
20402064
if (!validator.isNonEmptyString(data?.name)) {
@@ -2135,21 +2159,21 @@ export class AuthRequestHandler extends AbstractAuthRequestHandler {
21352159
*/
21362160
constructor(app: App) {
21372161
super(app);
2138-
this.authResourceUrlBuilder = new AuthResourceUrlBuilder(app, 'v2');
2162+
this.authResourceUrlBuilder = new AuthResourceUrlBuilder(app, 'v2', this.emulatorHostValue);
21392163
}
21402164

21412165
/**
21422166
* @returns A new Auth user management resource URL builder instance.
21432167
*/
21442168
protected newAuthUrlBuilder(): AuthResourceUrlBuilder {
2145-
return new AuthResourceUrlBuilder(this.app, 'v1');
2169+
return new AuthResourceUrlBuilder(this.app, 'v1', this.emulatorHostValue);
21462170
}
21472171

21482172
/**
21492173
* @returns A new project config resource URL builder instance.
21502174
*/
21512175
protected newProjectConfigUrlBuilder(): AuthResourceUrlBuilder {
2152-
return new AuthResourceUrlBuilder(this.app, 'v2');
2176+
return new AuthResourceUrlBuilder(this.app, 'v2', this.emulatorHostValue);
21532177
}
21542178

21552179
/**
@@ -2306,24 +2330,25 @@ export class TenantAwareAuthRequestHandler extends AbstractAuthRequestHandler {
23062330
*
23072331
* @param app - The app used to fetch access tokens to sign API requests.
23082332
* @param tenantId - The request handler's tenant ID.
2333+
* @param emHost - Optional emulator host override captured at init time.
23092334
* @constructor
23102335
*/
2311-
constructor(app: App, private readonly tenantId: string) {
2312-
super(app);
2336+
constructor(app: App, private readonly tenantId: string, emHost?: string | null) {
2337+
super(app, emHost);
23132338
}
23142339

23152340
/**
23162341
* @returns A new Auth user management resource URL builder instance.
23172342
*/
23182343
protected newAuthUrlBuilder(): AuthResourceUrlBuilder {
2319-
return new TenantAwareAuthResourceUrlBuilder(this.app, 'v1', this.tenantId);
2344+
return new TenantAwareAuthResourceUrlBuilder(this.app, 'v1', this.tenantId, this.emulatorHostValue);
23202345
}
23212346

23222347
/**
23232348
* @returns A new project config resource URL builder instance.
23242349
*/
23252350
protected newProjectConfigUrlBuilder(): AuthResourceUrlBuilder {
2326-
return new TenantAwareAuthResourceUrlBuilder(this.app, 'v2', this.tenantId);
2351+
return new TenantAwareAuthResourceUrlBuilder(this.app, 'v2', this.tenantId, this.emulatorHostValue);
23272352
}
23282353

23292354
/**

src/auth/auth-config.ts

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,43 @@ export interface UserProvider {
231231
* Interface representing the properties to set on a new user record to be
232232
* created.
233233
*/
234-
export interface CreateRequest extends UpdateRequest {
234+
export interface CreateRequest {
235+
236+
/**
237+
* Whether or not the user is disabled: `true` for disabled;
238+
* `false` for enabled.
239+
*/
240+
disabled?: boolean;
241+
242+
/**
243+
* The user's display name.
244+
*/
245+
displayName?: string;
246+
247+
/**
248+
* The user's primary email.
249+
*/
250+
email?: string;
251+
252+
/**
253+
* Whether or not the user's primary email is verified.
254+
*/
255+
emailVerified?: boolean;
256+
257+
/**
258+
* The user's unhashed password.
259+
*/
260+
password?: string;
261+
262+
/**
263+
* The user's primary phone number.
264+
*/
265+
phoneNumber?: string;
266+
267+
/**
268+
* The user's photo URL.
269+
*/
270+
photoURL?: string;
235271

236272
/**
237273
* The user's `uid`.

src/auth/base-auth.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,10 @@ export interface SessionCookieOptions {
117117
* @internal
118118
*/
119119
export function createFirebaseTokenGenerator(app: App,
120-
tenantId?: string): FirebaseTokenGenerator {
120+
tenantId?: string, isEmulator?: boolean): FirebaseTokenGenerator {
121121
try {
122-
const signer = useEmulator() ? new EmulatedSigner() : cryptoSignerFromApp(app);
122+
const shouldEmulate = isEmulator !== undefined ? isEmulator : useEmulator();
123+
const signer = shouldEmulate ? new EmulatedSigner() : cryptoSignerFromApp(app);
123124
return new FirebaseTokenGenerator(signer, tenantId);
124125
} catch (err) {
125126
throw handleCryptoSignerError(err);
@@ -139,6 +140,7 @@ export abstract class BaseAuth {
139140
protected readonly authBlockingTokenVerifier: FirebaseTokenVerifier;
140141
/** @internal */
141142
protected readonly sessionCookieVerifier: FirebaseTokenVerifier;
143+
private readonly emulatorMode: boolean;
142144

143145
/**
144146
* The BaseAuth class constructor.
@@ -155,6 +157,8 @@ export abstract class BaseAuth {
155157
app: App,
156158
/** @internal */ protected readonly authRequestHandler: AbstractAuthRequestHandler,
157159
tokenGenerator?: FirebaseTokenGenerator) {
160+
this.emulatorMode = !!this.authRequestHandler.emulatorHostValue;
161+
158162
if (tokenGenerator) {
159163
this.tokenGenerator = tokenGenerator;
160164
} else {
@@ -211,7 +215,7 @@ export abstract class BaseAuth {
211215
* promise.
212216
*/
213217
public verifyIdToken(idToken: string, checkRevoked = false): Promise<DecodedIdToken> {
214-
const isEmulator = useEmulator();
218+
const isEmulator = this.emulatorMode;
215219
return this.idTokenVerifier.verifyJWT(idToken, isEmulator)
216220
.then((decodedIdToken: DecodedIdToken) => {
217221
// Whether to check if the token was revoked.
@@ -717,7 +721,7 @@ export abstract class BaseAuth {
717721
*/
718722
public verifySessionCookie(
719723
sessionCookie: string, checkRevoked = false): Promise<DecodedIdToken> {
720-
const isEmulator = useEmulator();
724+
const isEmulator = this.emulatorMode;
721725
return this.sessionCookieVerifier.verifyJWT(sessionCookie, isEmulator)
722726
.then((decodedIdToken: DecodedIdToken) => {
723727
// Whether to check if the token was revoked.
@@ -1095,10 +1099,10 @@ export abstract class BaseAuth {
10951099
/** @alpha */
10961100
// eslint-disable-next-line @typescript-eslint/naming-convention
10971101
public _verifyAuthBlockingToken(
1098-
token: string,
1102+
token: string,
10991103
audience?: string
11001104
): Promise<DecodedAuthBlockingToken> {
1101-
const isEmulator = useEmulator();
1105+
const isEmulator = this.emulatorMode;
11021106
return this.authBlockingTokenVerifier._verifyAuthBlockingToken(token, isEmulator, audience)
11031107
.then((decodedAuthBlockingToken: DecodedAuthBlockingToken) => {
11041108
return decodedAuthBlockingToken;

src/auth/tenant-manager.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,15 @@ export class TenantAwareAuth extends BaseAuth {
7676
*
7777
* @param app - The app that created this tenant.
7878
* @param tenantId - The corresponding tenant ID.
79+
* @param emHost - Optional emulator host captured at init time.
7980
* @constructor
8081
* @internal
8182
*/
82-
constructor(app: App, tenantId: string) {
83+
constructor(app: App, tenantId: string, emHost?: string | null) {
84+
const emIsSet = emHost !== undefined;
8385
super(app, new TenantAwareAuthRequestHandler(
84-
app, tenantId), createFirebaseTokenGenerator(app, tenantId));
86+
app, tenantId, emHost), createFirebaseTokenGenerator(
87+
app, tenantId, emIsSet ? !!emHost : undefined));
8588
utils.addReadonlyGetter(this, 'tenantId', tenantId);
8689
}
8790

@@ -148,6 +151,7 @@ export class TenantAwareAuth extends BaseAuth {
148151
export class TenantManager {
149152
private readonly authRequestHandler: AuthRequestHandler;
150153
private readonly tenantsMap: {[key: string]: TenantAwareAuth};
154+
private readonly emulatorHost: string | undefined;
151155

152156
/**
153157
* Initializes a TenantManager instance for a specified FirebaseApp.
@@ -159,6 +163,7 @@ export class TenantManager {
159163
*/
160164
constructor(private readonly app: App) {
161165
this.authRequestHandler = new AuthRequestHandler(app);
166+
this.emulatorHost = this.authRequestHandler.emulatorHostValue;
162167
this.tenantsMap = {};
163168
}
164169

@@ -174,7 +179,7 @@ export class TenantManager {
174179
throw new FirebaseAuthError(authClientErrorCode.INVALID_TENANT_ID);
175180
}
176181
if (typeof this.tenantsMap[tenantId] === 'undefined') {
177-
this.tenantsMap[tenantId] = new TenantAwareAuth(this.app, tenantId);
182+
this.tenantsMap[tenantId] = new TenantAwareAuth(this.app, tenantId, this.emulatorHost ?? null);
178183
}
179184
return this.tenantsMap[tenantId];
180185
}

0 commit comments

Comments
 (0)