How Macro Implements Authentication and Authorization with FusionAuth

Macro integrates FusionAuth as its central identity provider using OAuth 2.0 Authorization Code flow with JWT validation, achieving authentication through signed tokens and authorization through role claims mapped to Macro's permission system.

The macro-inc/macro repository implements a complete authentication and authorization architecture built around FusionAuth. This guide examines how the platform handles user login, token verification, and permission enforcement across its service mesh, with specific implementation details drawn from the production source code.

OAuth 2.0 Login Flow with Authorization Code Exchange

Macro's authentication flow follows the standard OAuth 2.0 Authorization Code pattern with FusionAuth as the identity provider. The process begins with frontend credentials and completes with a validated JWT.

Token Exchange Implementation

The Seed CLI in tooling/seed_cli/src/main.rs demonstrates the core token exchange logic used throughout Macro's authentication services:

use fusionauth::FusionAuthClient;

let client = FusionAuthClient::new(
    env_vars.fusionauth_api_key_secret_key.to_string(),
    env_vars.fusionauth_client_id.to_string(),
    env_vars.fusionauth_client_secret_key.to_string(),
    transform_docker_url(&env_vars.fusionauth_base_url),
);
let token_response = client
    .exchange_code_for_token(auth_code, redirect_uri)
    .await?;

This client configuration relies on environment variables loaded through the macro_env_var crate. The FusionAuthEnv struct in tooling/xtask/crates/xtask_local/src/local/fusionauth.rs manages local development configuration:

use macro_env_var::FusionAuthEnv;

/// Reads FusionAuth variables from the environment.
let fusionauth = FusionAuthEnv::for_instance(&instance);
fusionauth.write(&mut env);

Required environment variables include:

  • FUSIONAUTH_CLIENT_ID — OAuth application identifier
  • FUSIONAUTH_CLIENT_SECRET — OAuth application secret
  • FUSIONAUTH_API_KEY_SECRET_KEY — API key for administrative operations
  • FUSIONAUTH_BASE_URL — FusionAuth instance endpoint

JWT Verification in the MCP Auth Proxy

All authenticated requests pass through Macro's MCP Auth Proxy, which validates FusionAuth-issued JWTs before forwarding requests to downstream services.

Signature Validation with JWKS

The proxy implementation in services/mcp_auth_proxy/src/outbound/fusionauth.rs performs cryptographic verification using FusionAuth's public keys:

use jsonwebtoken::{decode, decode_header, Validation, Algorithm};

let header = decode_header(&jwt)?;
let jwk = fusionauth_client.get_jwk(&header.kid).await?;
let mut validation = Validation::new(Algorithm::RS256);
validation.set_audience(&[env.fusionauth_audience()]);
validation.set_issuer(&[env.fusionauth_issuer()]);
let token_data = decode::<Claims>(&jwt, &jwk.public_key, &validation)?;

The validation enforces four security properties:

  • Signature integrity — RS256 verification against JWKS-retrieved public key
  • Audience restriction — matches configured FusionAuth application
  • Issuer verification — confirms token origin from trusted FusionAuth instance
  • Temporal validity — expiration and not-before claims

User Context Propagation

After successful validation, the proxy extracts identity claims and injects them into request headers for downstream consumption:

Claim Header Purpose
sub (subject) User ID for resource ownership checks
roles RBAC membership for authorization decisions
groups Organizational membership for multi-tenant isolation

Role-Based Authorization with macro_permission

Macro implements authorization through the macro_permission crate, which maps FusionAuth role claims to internal permission sets.

Permission Enforcement Pattern

Individual services enforce access control using the role claims forwarded by the auth proxy. A typical admin-only check follows this pattern from crates/macro_permission/src/lib.rs:

fn check_admin(user: &UserContext) -> Result<(), Error> {
    if user.roles.contains(&"admin".to_string()) {
        Ok(())
    } else {
        Err(Error::Unauthorized)
    }
}

The permission system supports Macro-specific access models including:

  • Owner-only — resource creator has exclusive access
  • Admin-only — restricted to system administrators
  • Role-based — mapped from FusionAuth role assignments
  • Group-scoped — organizational boundaries from FusionAuth groups

FusionAuth Service Integration Points

Email Verification Workflows

The authentication service calls FusionAuth APIs directly for user lifecycle operations. In services/authentication_service/src/api/email/verify_fusionauth_user_email.rs, Macro implements email verification by invoking FusionAuth's verification endpoints:

// FusionAuth user email verification API call
// Source: services/authentication_service/src/api/email/verify_fusionauth_user_email.rs

Infrastructure Deployment

FusionAuth runs as a containerized service defined in infra/stacks/fusion-auth/fusionauth-service.ts. The local development stack exposes:

  • Port 9011 — FusionAuth administrative UI and API
  • Port 9000 — Internal service communication

Security Architecture Summary

Macro's FusionAuth integration operates across three defense layers:

  1. Perimeter authentication — OAuth 2.0 flow yielding short-lived authorization codes
  2. Token validation — RS256 JWT verification with JWKS key rotation support
  3. Service authorization — role claim interpretation through centralized permission crate

Each layer is implemented in distinct components that can be independently tested and rotated, reducing the blast radius of potential security issues.

Summary

  • FusionAuth serves as Macro's sole identity provider via OAuth 2.0 Authorization Code flow
  • JWT validation occurs in services/mcp_auth_proxy/src/outbound/fusionauth.rs using RS256 with JWKS
  • Environment configuration is managed through macro_env_var::FusionAuthEnv for consistent client setup
  • Role claims from FusionAuth populate Macro's internal UserContext for downstream authorization
  • Permission enforcement uses the macro_permission crate to translate roles into service-specific access decisions

Frequently Asked Questions

How does Macro store FusionAuth configuration secrets?

Macro loads credentials through the macro_env_var crate, specifically FusionAuthEnv::for_instance() in tooling/xtask/crates/xtask_local/src/local/fusionauth.rs. In production, these values are injected via environment variables rather than committed to version control. The Seed CLI and auth proxy read FUSIONAUTH_CLIENT_ID, FUSIONAUTH_CLIENT_SECRET, and FUSIONAUTH_API_KEY_SECRET_KEY at runtime.

What JWT validation algorithm does Macro use with FusionAuth?

Macro validates tokens using RS256 (RSA with SHA-256) as implemented in services/mcp_auth_proxy/src/outbound/fusionauth.rs. The proxy fetches the appropriate public key from FusionAuth's JWKS endpoint using the kid (key ID) from the JWT header, enabling seamless key rotation without service reconfiguration.

Can Macro work with multiple FusionAuth tenants?

The codebase shows organizational scoping through the groups claim in JWT validation, but the current implementation in services/mcp_auth_proxy/src/outbound/fusionauth.rs uses a single configured fusionauth_issuer() and fusionauth_audience(). Multi-tenant support would require extending the proxy to validate against multiple issuer-audience pairs or using FusionAuth's tenant-scoped JWTs with dynamic configuration.

Where does Macro handle FusionAuth user provisioning?

User creation and initial setup occur in tooling/seed_cli/src/main.rs, which provides a CLI for creating test users before running integration tests. Production user provisioning typically happens through FusionAuth's self-registration flows or administrative APIs, with Macro services consuming the resulting user identities through validated JWTs rather than directly managing user records.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →