usebruno/bruno · error · Error

Access Token URL is required for OAuth2 password credentials

Error message

Access Token URL is required for OAuth2 password credentials flow

What it means

Thrown by fetchTokenPassword at the start of the resource-owner password grant when accessTokenUrl is missing. The password grant still requires a token endpoint to exchange username/password for a token, so the helper aborts before constructing the POST.

Source

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

};

/**
 * Fetches an OAuth2 token using password grant
 */
const fetchTokenPassword = async (oauth2Config: OAuth2Config, axiosInstance?: AxiosInstance) => {
  const {
    accessTokenUrl,
    clientId,
    clientSecret,
    username,
    password,
    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: {

View on GitHub (pinned to 9bdd81c7bd)

Solutions

  1. Set accessTokenUrl on the config before calling the password flow.
  2. Verify the URL is a valid absolute HTTPS endpoint accepted by the authorization server.
  3. Validate the whole config shape up front (see validationCode) to catch this and the username/password/clientId checks at once.

Example fix

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

// after
const config = {
  grantType: 'password',
  accessTokenUrl: 'https://auth.example.com/oauth/token',
  username: user,
  password: pass,
  clientId: id
};
Defensive patterns

Strategy: validation

Validate before calling

function validatePasswordConfig(c) {
  if (!c.accessTokenUrl) throw new Error('accessTokenUrl missing for password flow');
  if (!c.username) throw new Error('username missing');
  if (!c.password) throw new Error('password missing');
  if (!c.clientId) throw new Error('clientId missing');
}
validatePasswordConfig(config);

Type guard

function isPasswordGrantReady(c) {
  return c.grantType === 'password'
    && typeof c.accessTokenUrl === 'string' && c.accessTokenUrl.length > 0
    && typeof c.username === 'string' && !!c.password && typeof c.clientId === 'string';
}

Try / catch

try { await getOAuth2AccessToken(config, tokenStore); }
catch (e) { if (e.message.includes('password credentials flow')) { /* surface to user */ } else throw e; }

Prevention

When it happens

Trigger: getOAuth2AccessToken invoked with grantType='password' but accessTokenUrl empty/undefined. Often happens when the same config object is reused from a client_credentials setup that never set the URL.

Common situations: Switching grant types in a shared config without re-filling the token URL; the token URL field cleared during a migration; env var missing in a staging environment.

Related errors


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