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 identifierFUSIONAUTH_CLIENT_SECRET— OAuth application secretFUSIONAUTH_API_KEY_SECRET_KEY— API key for administrative operationsFUSIONAUTH_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:
- Perimeter authentication — OAuth 2.0 flow yielding short-lived authorization codes
- Token validation — RS256 JWT verification with JWKS key rotation support
- 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.rsusing RS256 with JWKS - Environment configuration is managed through
macro_env_var::FusionAuthEnvfor consistent client setup - Role claims from FusionAuth populate Macro's internal
UserContextfor downstream authorization - Permission enforcement uses the
macro_permissioncrate 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →