RocketChat/Rocket.Chat · warning · Meteor.Error

CustomOAuth: emailPath is required

Error message

CustomOAuth: emailPath is required

What it means

getEmailFromPath() refuses to run when the strategy instance has no emailPath configured. In the current code normalizeIdentity() only invokes it under 'if (!identity.email && this.emailPath)', so a live hit means the method was called directly (subclass, fork, or an older unguarded call path) on an instance constructed without the emailPath option.

Solutions

  1. Pass emailPath in the CustomOAuth options (relative paths are auto-prefixed with serverURL), e.g. emailPath: '/api/v3/user/emails'
  2. Prefer emailField mapping when the e-mail is already present in the identity payload - then emailPath is unnecessary
  3. Do not call getEmailFromPath directly; go through the normal login flow so the guard applies

Example fix

// before
new CustomOAuth('gitea', { serverURL, tokenPath, identityPath });
// later: await strategy.getEmailFromPath(token) -> throws 'CustomOAuth: emailPath is required'

// after
new CustomOAuth('gitea', { serverURL, tokenPath, identityPath, emailPath: '/user/emails' });
Defensive patterns

Strategy: validation

Validate before calling

const hasEmailPath = (strategy: CustomOAuth): boolean =>
  typeof strategy.emailPath === 'string' && strategy.emailPath.length > 0;

if (!hasEmailPath(strategy)) {
  throw new Error('emailPath option is required before fetching e-mails from the provider');
}

Try / catch

try {
  email = await strategy.getEmailFromPath(accessToken);
} catch (error) {
  if (/emailPath is required/.test(error.message)) {
    email = identity.email; // fall back to whatever the identity payload already carries
  } else {
    throw error;
  }
}

Prevention

When it happens

Trigger: Calling strategy.getEmailFromPath(accessToken) directly without having passed emailPath in the constructor options; running code from an older Rocket.Chat branch where normalizeIdentity called getEmailFromPath whenever identity.email was missing, regardless of emailPath.

Common situations: Custom forks or Apps that subclass the deprecated CustomOAuth class to fetch e-mails; upgrades where a private branch kept the old unguarded call; unit tests exercising getEmailFromPath in isolation.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18). Data as JSON: /api/errors/d82bc7830cf53d0a. Report an issue: GitHub.

Appendix: source

Thrown at apps/meteor/server/lib/auth-providers/custom-oauth/custom_oauth_server.js:278

			identity.email = await this.getEmailFromPath(accessToken);
		}

		if (this.avatarField) {
			identity.avatarUrl = this.getAvatarUrl(identity);
		}

		if (this.nameField) {
			identity.name = this.getCustomName(identity);
		} else {
			identity.name = this.getName(identity);
		}

		return renameInvalidProperties(identity);
	}

	async getEmailFromPath(accessToken) {
		if (!this.emailPath) {
			throw new Meteor.Error('CustomOAuth: emailPath is required');
		}

		const params = {};
		const headers = {
			'User-Agent': this.userAgent,
			'Accept': 'application/json',
		};

		if (this.identityTokenSentVia === 'header') {
			headers.Authorization = `Bearer ${accessToken}`;
		} else {
			params[this.accessTokenParam] = accessToken;
		}

		try {
			// SECURITY: URL can only be configured by users with enough privileges. It's ok to disable this check here.
			const request = await fetch(`${this.emailPath}`, { method: 'GET', headers, params, ignoreSsrfValidation: true });

View on GitHub (pinned to b2c16d5842)