# How Macro Implements Authentication and Authorization with FusionAuth

> Discover how Macro implements authentication and authorization with FusionAuth using OAuth 2.0 JWT validation and role claims for robust security.

- Repository: [Macro/macro](https://github.com/macro-inc/macro)
- Tags: how-to-guide
- Published: 2026-08-16

---

**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`](https://github.com/macro-inc/macro/blob/main/tooling/seed_cli/src/main.rs) demonstrates the core token exchange logic used throughout Macro's authentication services:

```rust
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`](https://github.com/macro-inc/macro/blob/main/tooling/xtask/crates/xtask_local/src/local/fusionauth.rs) manages local development configuration:

```rust
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`](https://github.com/macro-inc/macro/blob/main/services/mcp_auth_proxy/src/outbound/fusionauth.rs) performs cryptographic verification using FusionAuth's public keys:

```rust
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`](https://github.com/macro-inc/macro/blob/main/crates/macro_permission/src/lib.rs):

```rust
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`](https://github.com/macro-inc/macro/blob/main/services/authentication_service/src/api/email/verify_fusionauth_user_email.rs), Macro implements email verification by invoking FusionAuth's verification endpoints:

```rust
// 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`](https://github.com/macro-inc/macro/blob/main/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`](https://github.com/macro-inc/macro/blob/main/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`](https://github.com/macro-inc/macro/blob/main/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`](https://github.com/macro-inc/macro/blob/main/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`](https://github.com/macro-inc/macro/blob/main/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`](https://github.com/macro-inc/macro/blob/main/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.