Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Authorization

Once a user is authenticated, Authorization determines what they are allowed to do. The gateway facilitates this by making user roles and claims available to your resolvers and downstream services.

Role-Based Access Control (RBAC)

The AuthClaims object includes a roles field (Vec<String>) which works out-of-the-box for RBAC.

Checking Roles in Logic

You can check roles programmatically within your custom resolvers or middleware:

async fn delete_user(ctx: &Context, id: String) -> Result<String> {
    let claims = ctx.get_typed::<AuthClaims>("auth.claims")
        .ok_or(Error::Unauthorized("No claims found".into()))?;
        
    if !claims.has_role("admin") {
        return Err(Error::Forbidden("Admins only".into()));
    }
    
    // Proceed with deletion...
}

Propagating Auth to Backends

The most common pattern in a gateway is to offload fine-grained authorization to the backend services. The gateway’s job is to securely propagate the identity.

Header Propagation

You can forward authentication headers directly to your gRPC services:

// Forward the 'Authorization' header automatically
let gateway = Gateway::builder()
    .with_header_propagation(HeaderPropagationConfig {
        forward_headers: vec!["authorization".to_string()],
        ..Default::default()
    })
    // ...

Metadata Propagation

Alternatively, you can extract claims and inject them as gRPC metadata (headers) for your backends. EnhancedAuthMiddleware does not do this automatically, but you can write a custom middleware to run after it:

struct AuthPropagationMiddleware;

#[async_trait]
impl Middleware for AuthPropagationMiddleware {
    async fn call(&self, ctx: &mut Context) -> Result<()> {
        if let Some(user_id) = ctx.user_id() {
            // Add to headers that will be sent to gRPC backend
            ctx.headers.insert("x-user-id", user_id.parse()?);
        }
        
        if let Some(roles) = ctx.get("auth.roles") {
             // Serialize roles to a header
             let roles_str = serde_json::to_string(roles)?;
             ctx.headers.insert("x-user-roles", roles_str.parse()?);
        }
        
        Ok(())
    }
}

Query Whitelisting

For strict control over what operations can be executed, see the Query Whitelisting feature. This acts as a coarse-grained authorization layer, preventing unauthorized query shapes entirely.

Field-Level Authorization

For advanced field-level authorization (e.g., hiding specific fields based on roles), you currently need to implement this logic in your custom resolvers or within the backend services themselves. The gateway ensures the necessary identity data is present for these decisions to be made.