Role-Based Access Control (RBAC) across microservices isn’t just about defining roles; it’s about managing decentralized trust and ensuring consistent policy enforcement without a single point of failure.

Imagine a user trying to access a resource in your product-catalog service. This request might originate from your frontend application, which then calls the product-catalog service. The product-catalog service, in turn, might need to consult the user-profile service to verify the user’s identity and then check with an authorization-service to see if the identified user has the "viewer" role for product information.

Here’s a look at the components and interactions in a typical RBAC setup for microservices:

  • Identity Provider (IdP): This is where users authenticate. Think Okta, Auth0, or even a custom JWT issuer. It issues a token (usually JWT) containing user identity and potentially some basic claims.
  • API Gateway / Edge Service: This is often the first point of contact for incoming requests. It can perform initial authentication by validating the JWT from the IdP. It might also enforce coarse-grained authorization policies.
  • Microservices: Each service is responsible for its own fine-grained authorization. It receives the authenticated user’s token and decides, based on the token’s claims and its own internal policies, whether to permit or deny the request.
  • Authorization Service (Optional but Recommended): A dedicated service to manage authorization policies and roles centrally. Microservices query this service to make authorization decisions. This helps avoid policy duplication and inconsistency.

Let’s trace a request:

  1. User Login: A user logs in via the frontend application, which interacts with the IdP.

  2. Token Issuance: The IdP authenticates the user and issues a JWT. This JWT might look something like this:

    {
      "sub": "user123",
      "name": "Alice Smith",
      "roles": ["viewer", "editor"],
      "iss": "https://my-idp.com",
      "aud": "my-api-gateway",
      "exp": 1678886400
    }
    
  3. Request to API Gateway: The frontend includes this JWT in the Authorization: Bearer <token> header of its request to the product-catalog service, routed through the API Gateway.

  4. Gateway Validation: The API Gateway validates the JWT’s signature and expiration. It might forward the token or just relevant claims (like sub and roles) to the product-catalog service.

  5. Service Authorization: The product-catalog service receives the request. It checks its internal logic: "Does the user have the viewer role to read product details?"

    • Scenario A: Roles in Token: If the roles claim is present and trusted, the service directly checks if "viewer" is in ["viewer", "editor"]. Yes, it is. Access granted.
    • Scenario B: Centralized Authorization: If the service relies on an authorization-service, it might call authorization-service with user_id="user123" and action="read_product". The authorization-service looks up its policies and returns true or false.

The beauty of RBAC here is that the product-catalog service doesn’t need to know how Alice got the "viewer" role, only that she has it according to the validated token or the authorization service. This decouples identity management from authorization enforcement.

Consider a slightly more complex scenario: the order-management service needs to check if a user can cancel an order. This might involve not just a role ("customer-service-rep") but also a condition: "can only cancel orders placed in the last 24 hours." This is where attribute-based access control (ABAC) often starts to blend in, but the core RBAC principle of assigning permissions based on roles remains. The order-management service might query the authorization-service: can_cancel_order(user_id="user123", order_id="ORD987", order_creation_time="2023-10-26T10:00:00Z"). The authorization service then checks if "user123" has the "order-admin" role and if the order is within the 24-hour window.

The critical part is how services trust each other’s authorization decisions or how they delegate to a central authority. JWTs, signed by a trusted IdP, are the common mechanism for passing authenticated identity and roles. Services verify the signature, ensuring the token hasn’t been tampered with and originates from a known source.

When you’re implementing RBAC across services, you’re essentially building a distributed system of trust. The IdP is the root of trust for identity. The API Gateway is a first line of defense for authentication and broad authorization. Individual services are responsible for granular authorization, often by consulting a central policy store or by trusting claims within a securely signed JWT.

One aspect that trips many people up is the difference between authentication and authorization. Authentication is about verifying who you are (e.g., "Is this really Alice?"). Authorization is about verifying what you are allowed to do (e.g., "Can Alice view this product?"). In a microservices world, the IdP handles authentication, issuing a token that asserts Alice’s identity. The API Gateway and individual microservices then use this token for authorization. A common mistake is to conflate them, thinking that if a service trusts the JWT, it automatically trusts the user’s actions. You still need explicit authorization checks based on the claims within that token.

The next logical step after mastering RBAC is exploring how to handle dynamic authorization based on context and attributes, moving towards Attribute-Based Access Control (ABAC).

Want structured learning?

Take the full Microservices course →