All Blogs Tutorials 4 min read

JWT Authentication and Refresh Tokens in ASP.NET Core

Sandeep Pal
June 3, 2026
JWT Authentication and Refresh Tokens in ASP.NET Core

Why JWTs dominate modern .NET APIs

Cookie authentication still fits same-site web apps, but SPAs, mobile clients, and microservices frontends usually need bearer tokens. JSON Web Tokens let resource servers validate identity without server-side session storage on every node—though refresh tokens and revocation still require thoughtful storage. At Toolliyo we teach JWT flows because security questions appear in almost every ASP.NET Core interview, and production bugs here become headline breaches.

This guide explains access vs refresh tokens, ASP.NET Core configuration, and patterns that survive security review—not just a demo that works until you deploy.

Access token vs refresh token responsibilities

Access tokens are short-lived (often 5–15 minutes). They authorize API calls. Keep claims minimal: sub, name, roles, maybe tenant id. Refresh tokens are long-lived secrets used only against a token endpoint to obtain new access tokens. They should be rotatable, revocable, and stored more securely than access tokens. Never put sensitive PII in JWT payloads—they are signed, not encrypted, unless you use JWE (rare in typical LOB apps).

Register JWT bearer authentication in ASP.NET Core

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:Key"]!))
    };
  });

Use asymmetric keys (RSA) when multiple services validate tokens without sharing a symmetric secret. Store private keys in HSM or Key Vault; distribute public keys via JWKS endpoint.

Issuing tokens at login

Validate credentials against Identity, ASP.NET Identity, or your user store. On success, create access token with JwtSecurityTokenHandler and return refresh token to client. Example claims:

var claims = new[] {
  new Claim(JwtRegisteredClaimNames.Sub, user.Id),
  new Claim(ClaimTypes.Name, user.UserName),
  new Claim(ClaimTypes.Role, "Admin")
};

Set expires explicitly. Clock skew is handled in validation parameters—keep servers on NTP.

Refresh token rotation pattern

Store refresh tokens hashed in the database with user id, device id, expiry, and revoked flag. On refresh:

  1. Validate presented refresh token against hash.
  2. Revoke the old refresh token (detect reuse—possible theft).
  3. Issue new access and refresh pair.

Reuse detection: if a revoked refresh token appears again, revoke all sessions for that user family. This is OAuth best practice and stops replay chains.

Where clients should store tokens

Browser SPAs: memory for access token minimizes XSS exfiltration from localStorage; pair with refresh in HttpOnly Secure SameSite cookie if you control the API domain—or accept SPA trade-offs and harden CSP. Mobile: secure enclave / Keychain. Never log tokens. Avoid query string tokens—they leak via referrer and logs.

Authorization after authentication

Authentication proves who; authorization decides what. Use policies and requirements:

builder.Services.AddAuthorization(options => {
  options.AddPolicy("CanManageOrders", policy =>
    policy.RequireRole("Admin", "Ops"));
});

Attribute controllers with [Authorize(Policy = "CanManageOrders")]. For fine-grained rules, implement IAuthorizationHandler with resource-based checks.

Integrating with ASP.NET Core Identity

Identity issues cookies by default; you can add JWT for API endpoints while keeping cookies for MVC admin pages. Many teams use Identity for user management and a custom token endpoint for mobile. Understand lockout, two-factor, and password reset flows—they still matter with JWTs.

Logout and revocation reality

Stateless JWT access tokens cannot be revoked instantly without a blocklist or short lifetimes. That is why short access tokens plus refresh rotation win. Maintain a revocation table for refresh tokens and critical events (password change, admin suspend). For immediate access revocation, add a version claim (security_stamp) validated on each request or use reference tokens for highest sensitivity APIs.

CORS, CSRF, and cookies if you mix patterns

If refresh is cookie-based, configure CORS allowlist strictly, SameSite=Lax or Strict where possible, and anti-forgery for cookie-changing endpoints. Do not use wildcard origins with credentials.

Testing and observability

Integration tests should obtain a token from a test auth handler or dedicated test issuer. Log authentication failures without printing tokens. Correlate 401 spikes with clock skew, expired signing keys after rotation, or wrong audience strings between environments.

Common mistakes checklist

  • Symmetric signing key in git—rotate and use vault.
  • alg=none acceptance—validation parameters prevent this when configured correctly.
  • Long-lived access tokens with roles that change rarely but must revoke instantly.
  • Refresh tokens in localStorage beside XSS-vulnerable dependencies.
  • Missing HTTPS everywhere tokens travel.

Interview talking points

Explain difference between OAuth2 authorization server and your API resource server. Describe refresh rotation and theft detection. Compare JWT vs opaque server-side sessions for your last project with honest trade-offs.

JWT auth in ASP.NET Core is straightforward to prototype and subtle to harden. Short access lifetimes, rotated refresh tokens, secure client storage, and clear authorization policies give you production-grade security you can explain in an interview and defend in a review.

1 views 0 likes 0 comments
Comments (0)
Sign in to leave a comment
Toolliyo Assistant
Ask about tutorials, ebooks, training, pricing, mentor services, and support. I use public site content only—not admin or internal tools.

care@toolliyo.com

Need callback? Share your details