Set up JWT authentication for both .NET APIs and React microfrontends with proper token handling and authorization
Implements JWT authentication for .NET APIs and React frontends. Configures token validation, authorization policies, Axios interceptors, and route guards to secure microservices with role-based access and business isolation.
/plugin marketplace add usmanali4073/stylemate-plugins/plugin install stylemate-architecture@stylemate-pluginsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Use this skill to implement JWT authentication and authorization across StyleMate microservices including both .NET APIs and React frontends.
Configures:
Sets up:
Creates policies for:
Configures route metadata with:
Set up JWT authentication for the appointments service. It needs Owner, Admin, and
Staff access levels. All endpoints should require a valid business association.
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(builder.Configuration["Jwt:SecretKey"]))
};
});
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("RequireOwnerOrAdmin", policy =>
policy.RequireClaim("role", "Owner", "Admin"));
options.AddPolicy("RequireManagerOrAbove", policy =>
policy.RequireClaim("role", "Owner", "Admin", "Manager"));
options.AddPolicy("RequireBusiness", policy =>
policy.RequireClaim("business_id"));
options.AddPolicy("RequireEmailConfirmed", policy =>
policy.RequireClaim("email_confirmed", "true"));
});
[ApiController]
[Route("api/appointments/[controller]")]
[Authorize] // Requires valid JWT
public class AppointmentsController : ControllerBase
{
[HttpGet]
[Authorize(Policy = "RequireStaffAccess")]
public async Task<IActionResult> GetAll()
{
var businessId = User.FindFirst("business_id")?.Value;
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
// Query filtered by businessId
var appointments = await _service.GetByBusinessAsync(Guid.Parse(businessId));
return Ok(appointments);
}
}
import axios from 'axios';
const apiClient = axios.create({
baseURL: '/api/appointments',
withCredentials: true // For httpOnly cookies
});
// Request interceptor - Add JWT token
apiClient.interceptors.request.use(
(config) => {
const token = localStorage.getItem('accessToken');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => Promise.reject(error)
);
// Response interceptor - Handle token refresh
apiClient.interceptors.response.use(
(response) => response,
async (error) => {
const originalRequest = error.config;
if (error.response?.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
try {
const { data } = await axios.post('/api/auth/refresh');
localStorage.setItem('accessToken', data.token);
originalRequest.headers.Authorization = `Bearer ${data.token}`;
return apiClient(originalRequest);
} catch (refreshError) {
// Redirect to login
window.location.href = '/login';
return Promise.reject(refreshError);
}
}
return Promise.reject(error);
}
);
export default apiClient;
import { RouteObject } from 'react-router-dom';
interface RouteMetadata {
label: string;
allowedRoles: string[];
requireEmailConfirmed: boolean;
requireBusiness: boolean;
requireTwoFactor?: boolean;
}
export const routes: RouteObject[] = [
{
path: '/appointments',
element: <AppointmentsPage />,
handle: {
label: 'Appointments',
allowedRoles: ['Owner', 'Admin', 'Staff'],
requireEmailConfirmed: true,
requireBusiness: true
} as RouteMetadata
}
];
import { jwtDecode } from 'jwt-decode';
interface JwtPayload {
sub: string;
email: string;
role: string;
business_id: string;
email_confirmed: boolean;
}
export function useJwtClaims() {
const token = localStorage.getItem('accessToken');
if (!token) return null;
try {
return jwtDecode<JwtPayload>(token);
} catch {
return null;
}
}
Cause: Token not being sent or invalid signature Fix: Check Axios interceptor, verify JWT_SECRET matches
Cause: Missing business_id filter Fix: Always filter queries by businessId from JWT
Cause: No refresh logic Fix: Implement token refresh in interceptor
Cause: Missing credentials or wrong origin Fix: Set withCredentials: true and configure CORS properly
Master defensive Bash programming techniques for production-grade scripts. Use when writing robust shell scripts, CI/CD pipelines, or system utilities requiring fault tolerance and safety.