mastra-ai/mastra · error

Google Workspace Directory authentication is not configured.

Error message

Google Workspace Directory authentication is not configured.

What it means

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.

Source

Thrown at auth/google/src/rbac-provider.ts:196

    if (this.accessToken && Date.now() < this.tokenExpiresAt - 60_000) {
      return this.accessToken;
    }

    if (this.options.serviceAccount) {
      if (!this.tokenRefreshPromise) {
        this.tokenRefreshPromise = this.getServiceAccountToken().finally(() => {
          this.tokenRefreshPromise = undefined;
        });
      }
      return this.tokenRefreshPromise;
    }

    if (this.accessToken) {
      return this.accessToken;
    }

    throw new Error('Google Workspace Directory authentication is not configured.');
  }

  private async getServiceAccountToken(): Promise<string> {
    const account = this.options.serviceAccount!;
    const now = Math.floor(Date.now() / 1000);
    const header = { alg: 'RS256', typ: 'JWT', ...(account.privateKeyId ? { kid: account.privateKeyId } : {}) };
    const claim = {
      iss: account.clientEmail,
      scope: (account.scopes ?? DEFAULT_DIRECTORY_SCOPES).join(' '),
      aud: OAUTH_TOKEN_URL,
      exp: now + 3600,
      iat: now,
      ...(account.subject ? { sub: account.subject } : {}),
    };
    const unsigned = `${this.base64Url(JSON.stringify(header))}.${this.base64Url(JSON.stringify(claim))}`;
    const privateKey = this.normalizePrivateKey(account.privateKey);

    let signature: string;

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Configure authentication: pass a serviceAccount ({ clientEmail, privateKey, subject }) for server-side deployments — the recommended long-lived option.
  2. Alternatively supply a getAccessToken callback that returns a valid Directory-API bearer token.
  3. Or pass a static accessToken, understanding it will only work until expiry (and 401s surface as error 63 after this).
  4. Verify env vars (service account key, client email) are actually loaded where the provider is constructed.
  5. Validate options at startup so missing credentials fail fast rather than on first getRoles call.

Example fix

// before
const rbac = new MastraRBACGoogle({ roleMapping: mapping });
// after
const rbac = new MastraRBACGoogle({
  serviceAccount: {
    clientEmail: process.env.GOOGLE_SA_CLIENT_EMAIL!,
    privateKey: process.env.GOOGLE_SA_PRIVATE_KEY!.replace(/\\n/g, '\n'),
    subject: 'admin@mycompany.com',
  },
  roleMapping: mapping,
});
Defensive patterns

Strategy: validation

Validate before calling

function assertRbacAuthConfigured(opts: {
  getAccessToken?: () => Promise<string>;
  serviceAccount?: unknown;
  accessToken?: string;
}): void {
  if (!opts.getAccessToken && !opts.serviceAccount && !opts.accessToken) {
    throw new Error('MastraRBACGoogle needs one of: getAccessToken, serviceAccount, or accessToken');
  }
}
// call before constructing the provider

Type guard

interface RbacAuthOptions {
  getAccessToken?: () => Promise<string>;
  serviceAccount?: { clientEmail: string; privateKey: string; subject?: string };
  accessToken?: string;
}
function hasDirectoryAuth(o: RbacAuthOptions): boolean {
  return Boolean(o.getAccessToken || o.serviceAccount || o.accessToken);
}

Try / catch

try {
  const roles = await rbac.getRoles(user);
} catch (err) {
  if (err instanceof Error && err.message === 'Google Workspace Directory authentication is not configured.') {
    // config bug, not transient: log loudly and fall back to default permissions
    logger.error('RBAC provider missing Directory credentials');
    return roleMapping['_default'] ?? [];
  }
  throw err;
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Understand the failure class

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/1ceabf2464b04ec4. Report an issue: GitHub.