{"record":{"id":"2aa2a014b0b88df6","repo":"usebruno/bruno","slug":"grant-type-is-required-for-oauth2","errorCode":null,"errorMessage":"Grant type is required for OAuth2","messagePattern":"Grant type is required for OAuth2","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/bruno-requests/src/auth/oauth2-helper.ts","lineNumber":333,"sourceCode":"\n/**\n * Manages OAuth2 token retrieval and storage\n */\nexport const getOAuth2Token = async (oauth2Config: OAuth2Config, tokenStore: TokenStore, verbose: string, axiosInstance?: AxiosInstance): Promise<string | null> => {\n  const {\n    grantType,\n    accessTokenUrl,\n    credentialsId = 'default',\n    autoFetchToken = true,\n    tokenSource = 'access_token'\n  } = oauth2Config;\n\n  if (verbose) {\n    debug.enable('oauth2');\n  }\n\n  if (!grantType) {\n    throw new Error('Grant type is required for OAuth2');\n  }\n\n  if (!accessTokenUrl) {\n    throw new Error('Access token URL is required for OAuth2');\n  }\n\n  if (!['client_credentials', 'password'].includes(grantType)) {\n    throw new Error(`Unsupported grant type: ${grantType}. Supported types: client_credentials, password`);\n  }\n\n  // Check if we already have credentials stored\n  const existingToken = await tokenStore.getCredential({ url: accessTokenUrl, credentialsId });\n\n  if (existingToken) {\n    // Check if token is expired\n    if (!isTokenExpired(existingToken)) {\n      // Token is valid, use it\n      return tokenSource === 'id_token' ? existingToken.id_token : existingToken.access_token;","sourceCodeStart":315,"sourceCodeEnd":351,"githubUrl":"https://github.com/usebruno/bruno/blob/9bdd81c7bdc57006e5f5ebffb79321a8d979f712/packages/bruno-requests/src/auth/oauth2-helper.ts#L315-L351","documentation":"Thrown by the main getOAuth2AccessToken entry point when oauth2Config.grantType is falsy. The grant type selects which token flow to run, so the dispatcher rejects the call before consulting the token store. This is the outermost guard, hit before any flow-specific validation.","triggerScenarios":"Calling getOAuth2AccessToken with a config object whose grantType field is missing, null, undefined, or empty string.","commonSituations":"Config deserialized from JSON that omitted grantType; UI radio button for grant type never selected; programmatic caller built a partial config and forgot the grant type selector.","solutions":["Set grantType to one of the supported values ('client_credentials' or 'password') on the config.","Default the field explicitly in your config builder so an unset value is impossible.","Validate the config shape before calling the helper (see validationCode)."],"exampleFix":"// before\nconst config = { accessTokenUrl: url, clientId: id, clientSecret: secret };\nawait getOAuth2AccessToken(config, tokenStore);\n\n// after\nconst config = {\n  grantType: 'client_credentials',\n  accessTokenUrl: url,\n  clientId: id,\n  clientSecret: secret\n};\nawait getOAuth2AccessToken(config, tokenStore);","handlingStrategy":"type-guard","validationCode":"if (!config.grantType) throw new Error('grantType must be set on OAuth2Config');\nawait getOAuth2AccessToken(config, tokenStore);","typeGuard":"function hasGrantType(c) {\n  return typeof c.grantType === 'string' && c.grantType.length > 0;\n}","tryCatchPattern":"try { await getOAuth2AccessToken(config, tokenStore); }\ncatch (e) { if (e.message === 'Grant type is required for OAuth2') { /* default grant */ } else throw e; }","preventionTips":["Default grantType in your config builder so it can never be unset.","Use a discriminated union keyed on grantType to get compile-time safety.","Reject config objects with unknown grant types at the boundary."],"tags":["oauth2","validation","configuration"],"backgroundTag":null,"analyzedSha":"9bdd81c7bdc57006e5f5ebffb79321a8d979f712","analyzedAt":"2026-08-13T04:09:25.751Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}