{"record":{"id":"1ceabf2464b04ec4","repo":"mastra-ai/mastra","slug":"google-workspace-directory-authentication-is-not-c","errorCode":null,"errorMessage":"Google Workspace Directory authentication is not configured.","messagePattern":"Google Workspace Directory authentication is not configured\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"auth/google/src/rbac-provider.ts","lineNumber":196,"sourceCode":"\n    if (this.accessToken && Date.now() < this.tokenExpiresAt - 60_000) {\n      return this.accessToken;\n    }\n\n    if (this.options.serviceAccount) {\n      if (!this.tokenRefreshPromise) {\n        this.tokenRefreshPromise = this.getServiceAccountToken().finally(() => {\n          this.tokenRefreshPromise = undefined;\n        });\n      }\n      return this.tokenRefreshPromise;\n    }\n\n    if (this.accessToken) {\n      return this.accessToken;\n    }\n\n    throw new Error('Google Workspace Directory authentication is not configured.');\n  }\n\n  private async getServiceAccountToken(): Promise<string> {\n    const account = this.options.serviceAccount!;\n    const now = Math.floor(Date.now() / 1000);\n    const header = { alg: 'RS256', typ: 'JWT', ...(account.privateKeyId ? { kid: account.privateKeyId } : {}) };\n    const claim = {\n      iss: account.clientEmail,\n      scope: (account.scopes ?? DEFAULT_DIRECTORY_SCOPES).join(' '),\n      aud: OAUTH_TOKEN_URL,\n      exp: now + 3600,\n      iat: now,\n      ...(account.subject ? { sub: account.subject } : {}),\n    };\n    const unsigned = `${this.base64Url(JSON.stringify(header))}.${this.base64Url(JSON.stringify(claim))}`;\n    const privateKey = this.normalizePrivateKey(account.privateKey);\n\n    let signature: string;","sourceCodeStart":178,"sourceCodeEnd":214,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/auth/google/src/rbac-provider.ts#L178-L214","documentation":"Thrown by MastraRBACGoogle.getToken when no authentication source is available: no getAccessToken callback, no serviceAccount, and no (remaining) accessToken. The provider needs a bearer token for the Google Workspace Directory API to fetch the user's groups, and none is configured.","triggerScenarios":"getRoles/getPermissions called on a MastraRBACGoogle instance constructed without any of: options.getAccessToken, options.serviceAccount, options.accessToken — or with an accessToken that was consumed/expired and no refresh path (tokenExpiresAt passed, accessToken stale).","commonSituations":"Instantiating the RBAC provider with only roleMapping and forgetting credentials; assuming the SSO provider's tokens are shared with the RBAC provider (they are not); passing an expired accessToken with no serviceAccount fallback; env vars for the service account not loaded in the deployment.","solutions":["Configure authentication: pass a serviceAccount ({ clientEmail, privateKey, subject }) for server-side deployments — the recommended long-lived option.","Alternatively supply a getAccessToken callback that returns a valid Directory-API bearer token.","Or pass a static accessToken, understanding it will only work until expiry (and 401s surface as error 63 after this).","Verify env vars (service account key, client email) are actually loaded where the provider is constructed.","Validate options at startup so missing credentials fail fast rather than on first getRoles call."],"exampleFix":"// before\nconst rbac = new MastraRBACGoogle({ roleMapping: mapping });\n// after\nconst rbac = new MastraRBACGoogle({\n  serviceAccount: {\n    clientEmail: process.env.GOOGLE_SA_CLIENT_EMAIL!,\n    privateKey: process.env.GOOGLE_SA_PRIVATE_KEY!.replace(/\\\\n/g, '\\n'),\n    subject: 'admin@mycompany.com',\n  },\n  roleMapping: mapping,\n});","handlingStrategy":"validation","validationCode":"function assertRbacAuthConfigured(opts: {\n  getAccessToken?: () => Promise<string>;\n  serviceAccount?: unknown;\n  accessToken?: string;\n}): void {\n  if (!opts.getAccessToken && !opts.serviceAccount && !opts.accessToken) {\n    throw new Error('MastraRBACGoogle needs one of: getAccessToken, serviceAccount, or accessToken');\n  }\n}\n// call before constructing the provider","typeGuard":"interface RbacAuthOptions {\n  getAccessToken?: () => Promise<string>;\n  serviceAccount?: { clientEmail: string; privateKey: string; subject?: string };\n  accessToken?: string;\n}\nfunction hasDirectoryAuth(o: RbacAuthOptions): boolean {\n  return Boolean(o.getAccessToken || o.serviceAccount || o.accessToken);\n}","tryCatchPattern":"try {\n  const roles = await rbac.getRoles(user);\n} catch (err) {\n  if (err instanceof Error && err.message === 'Google Workspace Directory authentication is not configured.') {\n    // config bug, not transient: log loudly and fall back to default permissions\n    logger.error('RBAC provider missing Directory credentials');\n    return roleMapping['_default'] ?? [];\n  }\n  throw err;\n}","preventionTips":["Prefer serviceAccount credentials — they self-refresh and outlive static access tokens","If using a static accessToken, remember it expires; pair it with a getAccessToken callback for production","Verify service-account env vars are loaded in the deployment before startup","Construct the provider eagerly at boot so missing credentials fail fast","Do not assume SSO provider tokens are shared with the RBAC provider — configure auth separately"],"tags":["configuration","authentication","rbac","google","missing-credentials"],"backgroundTag":"missing-credentials","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}