mongodb/node-mongodb-native · error · MongoMissingCredentialsError

User provided OIDC callbacks must return a valid object with

Error message

User provided OIDC callbacks must return a valid object with an accessToken.

What it means

Thrown by the shared OIDC callback workflow when a user-provided OIDC callback returns a value that fails validation: it must be a non-null object containing accessToken, and may only contain the allowed properties accessToken, expiresInSeconds, refreshToken (src/cmap/auth/mongodb_oidc/callback_workflow.ts:146 and isCallbackResultInvalid at line 184). Extra unknown properties also invalidate the result. Surfaced as a MongoMissingCredentialsError.

Source

Thrown at src/cmap/auth/mongodb_oidc/callback_workflow.ts:147

    token: string,
    conversationId?: number
  ): Promise<void> {
    await connection.command(
      ns(credentials.source),
      finishCommandDocument(token, conversationId),
      undefined
    );
  }

  /**
   * Executes the callback and validates the output.
   */
  protected async executeAndValidateCallback(params: OIDCCallbackParams): Promise<OIDCResponse> {
    const result = await this.callback(params);
    // Validate that the result returned by the callback is acceptable. If it is not
    // we must clear the token result from the cache.
    if (isCallbackResultInvalid(result)) {
      throw new MongoMissingCredentialsError(CALLBACK_RESULT_ERROR);
    }
    return result;
  }

  /**
   * Ensure the callback is only executed one at a time and throttles the calls
   * to every 100ms.
   */
  protected withLock(callback: OIDCCallbackFunction): OIDCCallbackFunction {
    let lock: Promise<any> = Promise.resolve();
    return async (params: OIDCCallbackParams): Promise<OIDCResponse> => {
      // We do this to ensure that we would never return the result of the
      // previous lock, only the current callback's value would get returned.
      await lock;
      lock = lock

        .catch(() => null)

View on GitHub (pinned to 3366c21a63)

Solutions

  1. Ensure the callback resolves to an object with at least { accessToken: '<jwt string>' }.
  2. Strip any fields other than accessToken, expiresInSeconds (number), and refreshToken (string) from the returned object.
  3. Handle errors inside the callback and re-throw a meaningful Error rather than returning undefined.
  4. Double-check the return path: e.g. return { accessToken } not return { token: jwt }.

Example fix

// before
const callback = async (params) => {
  const r = await fetch(idp);
  return await r.json(); // returns {access_token, token_type, scope, ...}
};

// after
const callback = async (params) => {
  const r = await fetch(idp);
  const body = await r.json();
  return {
    accessToken: body.access_token,
    expiresInSeconds: body.expires_in
  };
};
Defensive patterns

Strategy: validation

Validate before calling

function validateOidcCallbackResult(r: unknown): void {
  if (r == null || typeof r !== 'object') throw new Error('OIDC callback must return an object');
  const allowed = new Set(['accessToken', 'expiresInSeconds', 'refreshToken']);
  const obj = r as Record<string, unknown>;
  if (typeof obj.accessToken !== 'string') throw new Error('OIDC callback result missing string accessToken');
  for (const k of Object.keys(obj)) {
    if (!allowed.has(k)) throw new Error(`OIDC callback returned disallowed property: ${k}`);
  }
}

Type guard

function isOidcResponse(r: unknown): r is { accessToken: string; expiresInSeconds?: number; refreshToken?: string } {
  if (r == null || typeof r !== 'object') return false;
  const o = r as Record<string, unknown>;
  if (typeof o.accessToken !== 'string') return false;
  return Object.getOwnPropertyNames(o).every(k => ['accessToken','expiresInSeconds','refreshToken'].includes(k));
}

Try / catch

try {
  await client.connect();
} catch (e) {
  if (e instanceof MongoMissingCredentialsError && /OIDC callbacks must return/.test(e.message)) {
    throw new Error('OIDC callback returned an invalid shape - ensure { accessToken: string } and no extra fields.');
  }
  throw e;
}

Prevention

When it happens

Trigger: A custom OIDC callback (configured via MongoClient auth mechanism properties 'OIDC_CALLBACK' or through a human workflow) returns undefined/null, returns an object without accessToken, returns accessToken of non-string type, or returns an object containing properties outside the allow-list.

Common situations: Callback returns the raw IdP response object verbatim (which may have extra fields like 'scope', 'token_type'), returns a Promise that resolves to undefined on a code path, or returns a nested token object like { token: {...} } instead of the flat shape.

Related errors


AI-assisted analysis of mongodb/node-mongodb-native@3366c21a63 (2026-08-04). Data as JSON: /data/errors/c0bfef8a63962e41.json. Report an issue: GitHub.