Authentication and Authorization in Micro Frontends
Learn how to design authentication and authorization in micro frontend architecture, including shell-owned auth bootstrap, token handling, session refresh, remote identity context, permission checks, logout, security risks, and interview tradeoffs.
Authentication and authorization become more complex when a frontend is split into multiple independently owned micro apps.
In a monolithic frontend, auth is usually simple:
One app
One router
One session provider
One auth guard
One token handling flowIn a micro frontend system, you may have:
Shell App
Catalog Remote
Cart Remote
Checkout Remote
Profile Remote
Orders Remote
Admin RemoteNow the questions become:
Who checks whether the user is logged in?
Who refreshes the token?
How do remotes know the current user?
Can remotes access tokens?
Who handles logout?
Where should permission checks happen?
What happens when the session expires?This article explains how to design authentication and authorization in micro frontends in a clean, secure, and interview-ready way.
1. Authentication vs Authorization
Before designing the system, separate these two concepts.
Authentication
Authentication answers:
Who is the user?Examples:
- Login
- Logout
- Session validation
- Token refresh
- Identity bootstrap
Authorization
Authorization answers:
What is the user allowed to do?Examples:
- Can the user view orders?
- Can the user edit profile?
- Can the user access admin tools?
- Can the user place an order?
- Can the user use a payment method?
Simple rule:
Authentication = identity Authorization = permission
In micro frontends, the shell often handles authentication bootstrap, while remotes handle feature-level authorization.
2. Core Auth Principle
The recommended principle is:
The shell should own authentication bootstrap, but remotes and backend APIs must still enforce authorization.
The shell can answer:
- Is the user logged in?
- What is the session status?
- Should this protected route load?
- Should we redirect to login?
The remote can answer:
- Can this user use this feature?
- Should this button be visible?
- Can this user edit this resource?
The backend must answer:
- Is this request actually allowed?
Frontend checks improve UX.
Backend checks protect the system.
3. High-Level Auth Architecture
A common architecture:
┌──────────────────────┐
│ Browser │
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ Shell App │
│ Auth Bootstrap │
│ Session Provider │
│ Route Guard │
└──────────┬───────────┘
│
┌────────────────────┼────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Profile Remote │ │ Orders Remote │ │ Checkout Remote │
│ Feature AuthZ │ │ Feature AuthZ │ │ Feature AuthZ │
└────────┬────────┘ └────────┬────────┘ └────────┬────────┘
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Profile API │ │ Orders API │ │ Checkout API │
│ Backend AuthZ │ │ Backend AuthZ │ │ Backend AuthZ │
└─────────────────┘ └─────────────────┘ └─────────────────┘The shell gives a consistent authentication experience.
The remotes apply domain-specific permission logic.
The backend enforces real security.
4. Shell Responsibilities
The shell usually owns platform-level authentication concerns.
Shell responsibilities:
Login detection
Session bootstrap
Token refresh orchestration
Logout handling
Global route protection
Identity context provider
Auth loading state
Redirect to login
Redirect after login
Session expiry handlingExample shell flow:
User opens /orders
│
▼
Shell checks session
│
├── Not logged in → redirect to /login?redirect=/orders
│
└── Logged in → load Orders RemoteThis keeps the global authentication experience consistent.
5. Remote Responsibilities
Remotes should not usually own the global login flow.
They should own domain-specific authorization and UX behavior.
Remote responsibilities:
Feature-level permission checks
Role-based UI visibility
Domain route restrictions
Calling domain APIs
Handling 401/403 responses gracefully
Displaying permission-specific empty statesExample: Orders Remote
- Orders Remote checks if user can view order history
- Calls Orders API
- Handles 403 forbidden response
- Shows “You do not have access to this order” if needed
Example: Checkout Remote
- Checkout Remote checks if user can place order
- Checks delivery/payment eligibility
- Calls Checkout API
- Handles payment/session authorization errors
The remote owns the domain experience.
6. Backend Responsibilities
Backend APIs must enforce real authorization.
Never rely only on frontend checks.
Backend responsibilities:
- Validate access token/session
- Validate user permissions
- Validate resource ownership
- Reject unauthorized requests
- Reject forbidden actions
- Apply business rules
- Audit sensitive actions
Example:
User manually calls:
GET /orders/order_123Even if the frontend hides the order page, the backend must still verify:
- Does this user own order_123?
- Is the user allowed to view it?
Strong interview phrase:
Frontend authorization improves user experience, but backend authorization protects the system.
7. Identity Context
The shell can provide a safe identity context to remotes.
Example identity context:
{
"isAuthenticated": true,
"userId": "user_123",
"displayName": "Avick",
"roles": ["customer"],
"locale": "en-IN",
"currency": "INR"
}This is useful for rendering UI.
But be careful.
Do not expose sensitive data unnecessarily.
Avoid passing:
- Raw access tokens through props
- Refresh tokens
- Secrets
- Payment data
- Sensitive profile data
- Full permission graph if not needed
Give remotes only what they need.
8. Token Handling
Token handling must be designed carefully.
Common options:
- HTTP-only secure cookies
- In-memory token storage
- Auth SDK managed session
- Backend session
- Token passed through API layer
Avoid storing sensitive tokens in:
- localStorage
- sessionStorage
- Custom browser events
- Global window variables
- URL query params
Bad:
/cart?token=eyJhbGciOi...
Bad:
window.__ACCESS_TOKEN__ = token
Better:
- Use HTTP-only secure cookies where possible.
- Let API calls include credentials safely.
- Keep token access centralized.
Exact implementation depends on your auth provider and backend architecture, but the principle is stable:
Do not spread token handling across every remote.
9. Should Remotes Access Tokens?
Ideally, remotes should not directly manage tokens.
Better options:
- Shell/auth provider initializes session.
- API client attaches credentials.
- Backend validates session/token.
- Remotes call domain APIs through approved clients.
If remotes directly handle tokens, you risk:
- Inconsistent refresh logic
- Security leaks
- Different token storage strategies
- Hard logout coordination
- Duplicate auth code
- Inconsistent error handling
A platform-owned auth layer keeps behavior consistent.
10. Session Bootstrap Flow
When the app starts, the shell can bootstrap session state.
Browser loads Shell
│
▼
Shell initializes auth provider
│
▼
Shell checks existing session
│
├── Loading → show app skeleton
├── Unauthenticated → public routes only
└── Authenticated → identity context readyThen routes can load remotes.
Example:
Authenticated user opens /profile
│
▼
Shell confirms session
│
▼
Shell loads Profile Remote
│
▼
Profile Remote fetches profile dataDo not load protected remotes before the auth state is known unless the route supports it safely.
11. Token Refresh Flow
Token/session refresh should be centralized.
Bad approach:
- Catalog Remote refreshes token.
- Cart Remote refreshes token.
- Checkout Remote refreshes token.
- Profile Remote refreshes token.
This can cause race conditions and inconsistent behavior.
Better:
- Shell/auth provider handles refresh.
- Remotes use API layer.
- 401 handling is standardized.
Flow:
API request receives 401
│
▼
Auth layer attempts refresh
│
├── Refresh succeeds → retry request
└── Refresh fails → logout or redirect to loginThis keeps auth behavior consistent.
12. Logout Flow
Logout must clear the full application session.
A good logout flow:
User clicks logout
│
▼
Shell calls auth logout
│
▼
Session/cookies cleared
│
▼
In-memory identity context cleared
│
▼
Remotes are notified through safe event/context update
│
▼
User redirected to login or public homeRemotes should respond to logout by clearing sensitive local UI state.
Example:
- Cart Remote clears in-memory cart summary.
- Profile Remote clears profile cache.
- Orders Remote clears order list cache.
Do not rely on remotes to perform the primary logout.
The shell/auth layer should own it.
13. Protected Routes
Some routes require authentication.
Examples:
- /profile
- /orders
- /checkout
Shell-level protected route flow:
User opens /orders
│
▼
Shell checks auth state
│
├── unauthenticated → /login?redirect=/orders
└── authenticated → load Orders RemoteRemote-level feature guard:
Orders Remote loads
│
▼
Checks permission/resource access
│
├── allowed → render orders
└── forbidden → show no-access stateBoth levels are useful.
14. Public Routes
Not all routes need authentication.
Examples:
- /
- /categories/:slug
- /search
- /product/:id
- /campaign/:slug
Public remotes should still be careful.
They may have mixed behavior:
- Anonymous user can view product.
- Logged-in user can see personalized price or wishlist.
The shell can provide optional identity context.
Remote should handle both states.
Example:
- Product Remote ├── Anonymous: show product └── Logged in: show wishlist and personalized offers
15. Authorization Models
Common frontend authorization models:
- Role-based access control
- Permission-based access control
- Feature-flag-based access
- Resource ownership checks
- Plan/subscription-based access
Examples:
- Admin can access admin remote.
- Customer can view own orders.
- Premium user can access premium feature.
- Store manager can edit catalog.
Frontend can hide or show UI based on these rules, but backend must enforce them.
16. Role-Based UI
Role-based UI can live inside remotes.
Example:
- Customer sees profile details
- Support agent sees customer assistance panel
- Admin sees account control tools
The shell should not know every domain-specific permission.
Bad:
Shell decides whether profile edit button appears.
Good:
Profile Remote decides profile feature visibility using identity/permissions.
The shell may provide the identity summary, but the remote owns the domain UI.
17. Permission Context
Instead of passing raw roles everywhere, some systems expose a permission context.
Example:
{
"permissions": [
"orders:view",
"profile:edit",
"checkout:place_order"
]
}A remote can check:
- Can user perform profile:edit?
- Can user perform orders:view?
- Can user perform checkout:place_order?
Benefits:
- More precise than roles
- Easier feature checks
- Clearer domain permissions
Risk:
- Too much permission logic duplicated in frontend
- Large permission object exposed unnecessarily
Keep it minimal and safe.
18. Handling 401 and 403
Remotes must handle API auth failures gracefully.
401 Unauthorized
Means:
User is not authenticated or session expired.
Possible behavior:
- Trigger refresh
- Redirect to login
- Show session expired message
403 Forbidden
Means:
User is authenticated but not allowed.
Possible behavior:
- Show no-access page
- Hide restricted action
- Show permission error
Do not treat 401 and 403 the same.
Example:
- 401 → login required
- 403 → access denied
19. Auth and Routing
Auth is closely tied to routing.
Example protected flow:
User opens /checkout
│
▼
Shell checks auth
│
├── not logged in → /login?redirect=/checkout
└── logged in → load Checkout RemoteAfter login:
Login success
│
▼
Redirect back to /checkoutThis preserves user intent.
Bad UX:
User tries checkout. Login succeeds. User lands on homepage. Cart journey is lost.
Good UX:
Return user to original route after successful login.
Redirect logic should be consistent across remotes.
The shell is usually the right place for global redirect rules.
20. Auth and Deep Linking
Deep links must work with auth.
Example:
/orders/order_123Flow:
User opens deep link
│
▼
Shell checks auth
│
├── not logged in → login with redirect
└── logged in → load Orders Remote
│
▼
Orders Remote checks order accessIf user does not own the order:
Show 403/no access
If order does not exist:
Show 404/not found
Auth, routing, and domain validation must work together.
21. Cross-App Auth Events
Some global auth events are useful.
Examples:
- auth:logged-in
- auth:logged-out
- auth:session-expired
- auth:token-refreshed
Use carefully.
Good event:
auth:logged-out Payload: { reason: "user_action" }
Bad event:
auth:token-refreshed Payload: { accessToken: "..." }
Never pass raw tokens through browser events.
22. Auth State and Browser Storage
Be careful with browser storage.
Avoid:
- localStorage for access tokens
- sessionStorage for refresh tokens
- localStorage as cross-remote auth API
Safer options often include:
- HTTP-only secure cookies
- Backend-managed session
- Auth SDK-managed secure flow
- In-memory short-lived token access
The exact choice depends on architecture, but never spread storage decisions across remotes.
23. Security Risks
Common security risks in micro frontend auth:
| Risk | Why It Is Dangerous |
|---|---|
| Tokens in localStorage | XSS exposure |
| Tokens in URL | Leaks through logs/history |
| Tokens in browser events | Any listener may read them |
| Remote owns refresh logic | Inconsistent and risky |
| Shell trusts frontend-only permissions | Backend bypass possible |
| Sensitive identity passed to all remotes | Data exposure |
| Untrusted remote loaded | Executable JS risk |
| Logout does not clear remote cache | Sensitive data may remain |
| Different auth handling per remote | Inconsistent security |
Security must be centralized where possible and enforced at the backend.
24. Auth in E-commerce Example
Route access:
| Route | Auth Required? | Owner |
|---|---|---|
| / | No | Home Remote |
| /categories/:slug | No | Catalog Remote |
| /product/:id | No | Product Remote |
| /cart | Optional/depends | Cart Remote |
| /checkout | Usually yes | Checkout Remote |
| /profile | Yes | Profile Remote |
| /orders | Yes | Orders Remote |
| /admin | Yes + role | Admin Remote |
Example checkout flow:
User opens /checkout
│
▼
Shell checks login
│
├── anonymous → /login?redirect=/checkout
└── authenticated → load Checkout RemoteCheckout Remote then checks:
- Can user place order?
- Is cart valid?
- Is delivery address allowed?
- Is payment method valid?
Backend finally enforces all rules.
25. Multi-Tenant / Role-Based Systems
In enterprise apps, auth may include tenant or organization context.
Example:
{
"userId": "user_123",
"tenantId": "tenant_456",
"roles": ["admin"],
"permissions": ["users:view", "billing:edit"]
}Micro frontend implications:
- Shell bootstraps tenant context.
- Remote checks domain permissions.
- APIs validate tenant access.
- Route changes preserve tenant scope.
Example routes:
- /org/acme/users
- /org/acme/billing
- /org/acme/audit-logs
Tenant context must be consistent across remotes.
26. Testing Auth in Micro Frontends
Test auth at multiple levels.
Test cases:
- Unauthenticated user opens protected route.
- User logs in and returns to original route.
- Session expires while remote is open.
- Remote receives 403 from API.
- Logout clears shell and remote state.
- Deep link to protected nested route works.
- Role-based UI appears correctly.
- Unauthorized user cannot access admin remote.
Important E2E journeys:
- Login → profile
- Login → checkout
- Session expiry → redirect
- Logout → protected route blocked
- Admin user → admin page allowed
- Normal user → admin page denied
Auth bugs can create both security and UX problems.
27. Observability for Auth
Track auth-related events:
- Login success/failure
- Logout
- Session refresh success/failure
- Protected route redirects
- 401 responses
- 403 responses
- Session expiry
- Auth provider errors
- Remote permission failures
Useful fields:
route
remoteName
shellVersion
remoteVersion
authState
errorType
permission
userRoleGroupDo not log sensitive tokens or private user data.
28. Common Anti-Patterns
| Anti-Pattern | Why It Is Bad |
|---|---|
| Each remote implements its own login | Inconsistent UX/security |
| Tokens passed through props/events | Security risk |
| Tokens stored in localStorage | XSS exposure |
| Shell owns all permission logic | Shell becomes domain-aware |
| Remotes trust frontend-only permissions | Backend bypass risk |
| No session refresh strategy | Random auth failures |
| No logout coordination | Sensitive stale data |
| Same handling for 401 and 403 | Wrong UX |
| No redirect preservation | Broken user journeys |
| Auth logic duplicated everywhere | Maintenance and security risk |
29. Interview Questions
Q1. Where should authentication live in micro frontends?
Authentication bootstrap should usually live in the shell or platform layer. The shell can initialize the session, handle login/logout, refresh tokens, and protect top-level routes. Remotes consume safe identity context and handle domain-specific authorization.
Q2. Where should authorization live?
Authorization should exist at multiple levels. The shell can handle broad route protection, remotes can handle feature-level permissions, and backend APIs must enforce real authorization. Frontend checks are not enough for security.
Q3. Should remotes access tokens directly?
Ideally no. Token handling should be centralized through the shell/auth provider or approved API layer. Passing tokens to every remote increases security risk and creates inconsistent refresh/logout behavior.
Q4. How do you handle session expiry?
The shared auth layer should detect session expiry or refresh failure, clear identity context, notify the app safely, and redirect the user to login while preserving the original route where appropriate.
Q5. How do you handle logout across remotes?
The shell/auth layer should own logout. After logout, it clears the session and identity context, notifies remotes safely, and redirects the user. Remotes should clear sensitive in-memory data when auth state changes.
Q6. What is the biggest security mistake in micro frontend auth?
One major mistake is spreading token handling across remotes or exposing tokens through localStorage, browser events, URL params, or global variables. Another is relying only on frontend permission checks without backend enforcement.
30. Strong Senior Answer
If an interviewer asks:
“How would you design authentication and authorization in micro frontends?”
A strong answer:
I would keep authentication bootstrap in the shell or platform layer. The shell would initialize the auth provider, check the session, handle token refresh, protect top-level routes, manage logout, and preserve redirect URLs after login. Remotes would not implement their own login flows. They would consume a safe identity context from the shell, such as user ID, logged-in status, locale, and minimal role or permission information. Each remote would handle feature-level authorization inside its domain. For example, Orders Remote decides whether the user can view order history, and Checkout Remote decides whether the user can access specific checkout actions. Backend APIs must still enforce authorization because frontend checks are only for user experience, not real security. I would avoid passing raw tokens through props, browser events, localStorage, or URLs. Token/session handling should be centralized through the platform auth layer or secure API client. The key principle is: shell owns authentication bootstrap, remotes own domain authorization UX, and backend APIs enforce security.
31. Final Auth Checklist
- Does the shell own authentication bootstrap?
- Is login/logout centralized?
- Is token/session refresh centralized?
- Are protected routes guarded?
- Is redirect-after-login preserved?
- Do remotes avoid implementing separate login flows?
- Is identity context minimal and safe?
- Are raw tokens kept out of browser events and URLs?
- Are tokens avoided in localStorage where possible?
- Do remotes handle feature-level authorization?
- Do backend APIs enforce real authorization?
- Are 401 and 403 handled differently?
- Does logout clear sensitive remote state?
- Are auth failures observable?
- Are deep links to protected routes supported?
32. Summary
Authentication and authorization in micro frontends require clear ownership.
Recommended model:
Shell owns authentication bootstrap.
Shell owns top-level route protection.
Remotes own feature-level authorization UX.
Backend APIs enforce real authorization.
Token handling is centralized.
Identity context is minimal and safe.
Logout is coordinated globally.Avoid:
Each remote having its own login flow.
Passing tokens through events or URLs.
Storing sensitive tokens casually in browser storage.
Putting all permission logic in the shell.
Trusting frontend-only authorization.The strongest takeaway:
In micro frontends, authentication should be centralized for consistency, authorization should be domain-aware, and real security must be enforced by the backend.
References
- Micro Frontends — Martin Fowler (https://martinfowler.com/articles/micro-frontends.html)
- Micro Frontends (https://micro-frontends.org)
- webpack Module Federation Documentation (https://webpack.js.org/concepts/module-federation/)
- AWS Prescriptive Guidance: Micro-frontends (https://docs.aws.amazon.com/prescriptive-guidance/latest/micro-frontends-aws/introduction.html)
- Module Federation Official Site (https://module-federation.io)