usebruno/bruno · error · Error

Client ID is required for OAuth2 password credentials flow

Error message

Client ID is required for OAuth2 password credentials flow

What it means

Thrown by fetchTokenPassword when oauth2Config.clientId is falsy. Even the password grant requires a client_id so the authorization server can identify the requesting application; the helper validates it after username/password checks.

Source

Thrown at packages/bruno-requests/src/auth/oauth2-helper.ts:227

    scope,
    credentialsPlacement = 'basic_auth_header',
    additionalParameters
  } = oauth2Config;

  if (!accessTokenUrl) {
    throw new Error('Access Token URL is required for OAuth2 password credentials flow');
  }

  if (!username) {
    throw new Error('Username is required for OAuth2 password credentials flow');
  }

  if (!password) {
    throw new Error('Password is required for OAuth2 password credentials flow');
  }

  if (!clientId) {
    throw new Error('Client ID is required for OAuth2 password credentials flow');
  }

  const requestConfig: RequestConfig = {
    method: 'POST',
    url: accessTokenUrl,
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      'Accept': 'application/json'
    },
    data: '',
    responseType: 'arraybuffer'
  };

  const data: PasswordGrantData = {
    grant_type: 'password',
    username,
    password
  };

View on GitHub (pinned to 9bdd81c7bd)

Solutions

  1. Provide a non-empty clientId for the application registered with the authorization server.
  2. Verify the client registration includes the password grant as an allowed flow.
  3. Load clientId from a single source of truth and assert it is set at startup.

Example fix

// before
const config = { grantType: 'password', accessTokenUrl: url, username: user, password: pass };

// after
const config = {
  grantType: 'password',
  accessTokenUrl: url,
  username: user,
  password: pass,
  clientId: process.env.OAUTH_CLIENT_ID
};
Defensive patterns

Strategy: validation

Validate before calling

if (!config.clientId) throw new Error('clientId required even for password grant');

Type guard

function hasClientIdForPassword(c) { return typeof c.clientId === 'string' && c.clientId.length > 0; }

Try / catch

try { await getOAuth2AccessToken(config, tokenStore); }
catch (e) { if (e.message.includes('Client ID is required for OAuth2 password')) { /* set clientId */ } else throw e; }

Prevention

When it happens

Trigger: getOAuth2AccessToken with grantType='password', valid accessTokenUrl/username/password, but clientId empty/undefined.

Common situations: Public-client setup where the developer assumed client_id is optional; the clientId env var missing in production; config assembled from multiple sources and the clientId branch was skipped.

Related errors


AI-assisted analysis of usebruno/bruno@9bdd81c7bd (2026-08-13). Data as JSON: /api/errors/147ce35b734a647c. Report an issue: GitHub.