# ASP.NET Core Security Interview Questions for Senior .NET Developers (2026)

ASP.NET Core security is one of the most consistently tested areas in senior .NET developer interviews. Whether you are applying for a tech lead role, a principal engineer position, or a senior backend role at a security-conscious company, interviewers expect you to go beyond "use HTTPS" and demonstrate a production-level understanding of authentication, authorization, threat modeling, and the security primitives built into the framework itself.

This guide covers 25+ ASP.NET Core security interview questions for senior .NET developers in 2026, organized from foundational concepts through advanced scenarios. Each question includes the answer examiners are looking for - not just the textbook definition, but the context and trade-offs that distinguish senior answers from mid-level ones.

Security questions probe whether you have shipped it, not just read about it. The full secure-API setup - auth, JWT with refresh, and resource authorization - is on [Patreon](https://www.patreon.com/CodingDroplets). [Chapter 7 of the ASP.NET Core Web API: Zero to Production course](https://aspnetcoreapi.codingdroplets.com/) builds JWT auth and refresh tokens inside a real API.

[![ASP.NET Core Web API: Zero to Production](https://newsletter.codingdroplets.com/images/aspnet-core-api-course-banner-1.jpg)](https://aspnetcoreapi.codingdroplets.com/)

---

## Basic: Authentication and Authorization Fundamentals

### What is the difference between authentication and authorization in ASP.NET Core?

Authentication establishes *who* the caller is - it validates identity through credentials, tokens, or certificates. Authorization determines *what* an authenticated caller is permitted to do. In ASP.NET Core, these are distinct middleware layers: `UseAuthentication()` must be registered before `UseAuthorization()` in the pipeline.

A senior answer adds: failing to call them in the correct order is a common misconfiguration that silently allows unauthenticated requests through to authorization handlers. The pipeline is sequential - if authentication hasn't run, the `HttpContext.User` identity is unauthenticated, and policy-based authorization will fail or behave unexpectedly depending on how handlers are written.

### How does cookie-based authentication differ from JWT bearer authentication in ASP.NET Core?

Cookie authentication stores session state server-side (or encrypts it into a cookie with Data Protection) and is best suited for browser-driven web applications where CSRF protection is a concern. JWT bearer authentication is stateless - the token carries all claims and is validated on each request without server-side session lookup, making it the standard choice for APIs consumed by mobile apps, SPAs, and microservices.

The distinction interviewers probe here: cookie authentication requires CSRF mitigation (ASP.NET Core's antiforgery system), while JWT is vulnerable to token theft if stored in `localStorage`. Senior developers know that `HttpOnly` cookie storage for JWTs can combine the stateless nature of JWTs with the XSS-resistance of cookies.

### What is the purpose of `AddAuthentication()` versus `AddAuthorization()` in the DI container?

`AddAuthentication()` registers authentication services and specifies the default authentication scheme. It does not add any scheme-specific handler itself - you chain scheme registrations onto it (e.g., `.AddJwtBearer()`, `.AddCookie()`). `AddAuthorization()` registers the authorization services and optionally configures a fallback policy, default policy, and named policies.

A common interview trap: adding a scheme handler (e.g., `AddJwtBearer()`) without calling `AddAuthentication()` first causes a `InvalidOperationException` at runtime. The default scheme matters because middleware calls `AuthenticateAsync` against it when no explicit scheme is specified on an endpoint.

### What is a claims principal in ASP.NET Core and how is it populated?

A `ClaimsPrincipal` is the authenticated identity representation attached to `HttpContext.User`. It contains one or more `ClaimsIdentity` objects, each carrying a set of `Claim` key-value pairs (e.g., `sub`, `email`, `role`).

In JWT bearer authentication, the principal is populated by the `JwtBearerHandler` during the `AuthenticateAsync` step - it parses and validates the token, maps standard JWT claims to `ClaimTypes` equivalents, and builds the principal. Senior developers note that claim type mapping is configurable and often needs to be disabled (`MapInboundClaims = false`) to preserve original JWT claim names like `sub` and `roles` instead of having them remapped to long Microsoft URI strings.

---

## Intermediate: JWT, OWASP, and Data Protection

### How do you implement JWT refresh token rotation in ASP.NET Core?

Refresh token rotation means issuing a new refresh token every time a refresh token is redeemed, and immediately invalidating the old one. The implementation involves persisting refresh tokens server-side (database or distributed cache) with expiry and a one-time-use flag.

The rotation logic: on `/token/refresh`, validate the incoming refresh token against the store, issue a new access token and a new refresh token, invalidate the old refresh token in the store, and return both. Concurrency handling matters - use optimistic locking or a transactional update to prevent a replayed refresh token from succeeding in a race condition.

This topic also links to [JWT Authentication vs Reference Tokens in ASP.NET Core APIs](https://codingdroplets.com/jwt-authentication-vs-reference-tokens-aspnet-core-apis-enterprise-decision-guide), where the trade-offs between self-contained JWTs and opaque reference tokens are explored in depth for enterprise scenarios.

### What OWASP Top 10 risks are most relevant to ASP.NET Core API development?

Senior developers are expected to map OWASP risks to concrete framework mitigations:

- **A01 Broken Access Control** - mitigated through policy-based authorization, resource-based authorization handlers, and avoiding reliance solely on client-supplied data for access decisions.
- **A02 Cryptographic Failures** - mitigated through ASP.NET Core Data Protection for at-rest encryption, enforcing HTTPS with HSTS, and using `PasswordHasher<T>` or BCrypt rather than MD5/SHA-1 for passwords.
- **A03 Injection** - in .NET APIs, SQL injection is mitigated through EF Core parameterized queries; command injection through avoiding `Process.Start` with user input; LDAP injection through proper escaping.
- **A07 Identification and Authentication Failures** - covered by ASP.NET Core Identity's account lockout, two-factor authentication, and secure token generation.
- **A09 Security Logging and Monitoring Failures** - mitigated by structured logging with correlation IDs, logging authentication failures at appropriate levels, and not logging sensitive claim data.

The key insight interviewers look for: OWASP risks are addressed at the framework level *and* the application code level - using the right ASP.NET Core primitives is necessary but not sufficient.

### How does ASP.NET Core Data Protection work and when should you use it?

The Data Protection API provides cryptographic primitives for protecting and unprotecting data (primarily for anti-forgery tokens, authentication cookies, and short-lived payloads). It uses key rings - collections of keys with a primary active key and archived keys for decryption of older payloads.

By default, keys are stored in-memory, which breaks in multi-instance deployments (load-balanced environments will be unable to unprotect data generated by other instances). In production, key ring storage must be externalized: `PersistKeysToAzureBlobStorage`, `PersistKeysToDbContext` (EF Core), or file system with DPAPI/Azure Key Vault encryption.

Senior developers are expected to know: Data Protection is not just for cookies. It's appropriate for any short-lived sensitive payload - password reset tokens, email confirmation tokens, CSRF tokens. Microsoft Docs coverage: [ASP.NET Core Data Protection Overview](https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/introduction).

### How do you prevent Cross-Site Request Forgery (CSRF) in an ASP.NET Core application?

CSRF attacks trick an authenticated browser into making unintended requests on behalf of the user. ASP.NET Core's antiforgery system generates and validates request tokens using the Data Protection API.

For Razor Pages and MVC forms, `@Html.AntiForgeryToken()` and `[ValidateAntiForgeryToken]` handle this automatically. For AJAX/SPA clients, the double-submit cookie pattern is used - the token is sent in a request header (e.g., `X-CSRF-TOKEN`) alongside the cookie, and the middleware validates both match.

Critical nuance: APIs that use JWT bearer authentication and require `Authorization: Bearer` headers are *not* vulnerable to CSRF because cross-origin requests cannot include custom headers without CORS preflight. Antiforgery is only relevant for cookie-authenticated endpoints.

### What is Cross-Origin Resource Sharing (CORS) and how do you configure it securely in ASP.NET Core?

CORS is a browser mechanism that restricts which origins can make cross-origin requests to an API. ASP.NET Core's CORS middleware (`UseCors()`) intercepts preflight OPTIONS requests and adds `Access-Control-Allow-*` headers.

Secure configuration means: specifying explicit allowed origins (never `AllowAnyOrigin()` with `AllowCredentials()` - this is a misconfiguration that throws at startup in ASP.NET Core 2.2+), restricting allowed methods and headers, and setting appropriate `MaxAge` for preflight caching.

Named policies allow different CORS rules for different endpoint groups - useful when you have a public API and an admin API on the same host. A frequently missed point: CORS is a browser enforcement mechanism. It does not protect against non-browser clients (curl, Postman, server-to-server calls) - those bypass CORS entirely.

---

## Advanced: Policy-Based Authorization, Secrets, and Production Security

### How does resource-based authorization differ from role-based authorization in ASP.NET Core?

Role-based authorization makes access decisions based on the caller's role claims alone (e.g., `[Authorize(Roles = "Admin")]`). It cannot account for *which* resource is being accessed.

Resource-based authorization passes the specific resource instance into the authorization handler, allowing fine-grained decisions. For example, "can this user edit *this* document" depends on the document's owner field. The implementation uses `IAuthorizationService.AuthorizeAsync(user, document, requirement)` with a custom `AuthorizationHandler<TRequirement, TResource>`.

The pattern matters for any multi-tenant application where data scoping must be enforced at the authorization layer rather than relying solely on filtering in the data access layer.

### What is a policy-based authorization requirement in ASP.NET Core?

An `IAuthorizationRequirement` is a marker interface representing what needs to be satisfied for access to be granted. It carries no logic itself - logic lives in `AuthorizationHandler<TRequirement>`.

A requirement can be satisfied by multiple handlers (OR semantics per handler), and multiple requirements in a policy must all pass (AND semantics per requirement). This allows composable, testable authorization rules.

Example: a `MinimumAgeRequirement` carries an integer. The handler checks the user's `DateOfBirth` claim, computes age, and calls `context.Succeed(requirement)` or `context.Fail()`. Senior answers include: handlers can be registered as services with full DI support, allowing them to query databases or call external services.

### How do you manage application secrets securely across development, staging, and production in ASP.NET Core?

Development: .NET User Secrets (`dotnet user-secrets`) store configuration outside the project directory, never checked into source control. Loaded automatically in the Development environment.

Production: Environment variables are the minimum acceptable approach. Preferred: Azure Key Vault, AWS Secrets Manager, or HashiCorp Vault integrated via the configuration system. ASP.NET Core's configuration providers are composable - vault-sourced values override `appsettings.json` values without code changes.

Anti-pattern: storing production secrets in `appsettings.Production.json` committed to the repository. Another anti-pattern: loading secrets from environment variables and logging the entire configuration object on startup (a surprisingly common logging mistake that exfiltrates secrets to log aggregators).

This connects to the detailed coverage in [.NET Secrets Management: Azure Key Vault vs User Secrets vs Environment Variables](https://codingdroplets.com/dotnet-secrets-management-enterprise-decision-guide).

### How does ASP.NET Core handle Content Security Policy (CSP) and security headers?

ASP.NET Core does not include built-in CSP or security header middleware - these must be added manually or via a library like `NWebsec` or `Helmet`-equivalent packages.

The standard approach: middleware that adds `Content-Security-Policy`, `X-Frame-Options`, `X-Content-Type-Options`, `Referrer-Policy`, and `Permissions-Policy` headers to every response. These headers instruct browsers to restrict resource loading, prevent clickjacking, and disable MIME-type sniffing.

Senior developers are expected to know: CSP is complex to configure without breaking legitimate functionality. A `report-only` mode (`Content-Security-Policy-Report-Only`) allows you to deploy and observe violations before enforcing. CSP directives like `script-src 'nonce-{random}'` prevent inline script injection without blocking all scripts.

### What is the difference between `[Authorize]` with a fallback policy versus `RequireAuthorization()` on endpoint groups?

A fallback policy (configured via `options.FallbackPolicy`) applies to all endpoints that have no explicit authorization attribute. It is the "default secure" approach for applications where most endpoints require authentication - you configure the fallback once and explicitly opt out with `[AllowAnonymous]` where needed.

`RequireAuthorization()` is the Minimal API / endpoint routing equivalent - it applies authorization to a specific endpoint or group. The two approaches compose: a fallback policy covers any endpoint not explicitly configured, while `RequireAuthorization()` provides per-endpoint overrides.

The senior insight: fallback policies do not apply to endpoints that have any `[Authorize]` attribute - if an endpoint explicitly uses `[Authorize]`, only its specified policies apply, not the fallback.

### How do you audit and log security events in an ASP.NET Core application?

Security event logging should capture: failed authentication attempts, authorization failures, privilege escalation events, and changes to sensitive resources. These differ from request logging - they are business-security events, not infrastructure traces.

Implementation pattern: use `IAuthorizationService` result inspection in middleware or resource handlers to log `AuthorizationFailure`. For authentication events, `JwtBearerOptions.Events` (e.g., `OnAuthenticationFailed`, `OnTokenValidated`) allow structured logging at the scheme level.

Critical: do *not* log claim values like `sub`, `email`, or role names to general-purpose application logs - log aggregators (Datadog, Splunk) are often accessible to a broader team than your security team. Log event types and outcome codes, not raw claim data. Microsoft's guidance: [Security logging and monitoring (OWASP A09)](https://owasp.org/Top10/A09_2021-Security_Logging_and_Monitoring_Failures/).

---

## Expert: Multi-Tenancy, Zero Trust, and .NET 10 Security Changes

### How do you enforce per-tenant data isolation at the authorization layer in a multi-tenant ASP.NET Core API?

Per-tenant isolation should be enforced at the authorization layer (not just the data access layer) to prevent application bugs from accidentally cross-contaminating tenant data. The pattern: extract the tenant ID from the authenticated user's claims, inject it into a scoped `ITenantContext`, and use a custom `IAuthorizationHandler` that validates the requested resource belongs to that tenant.

EF Core Global Query Filters complement this at the persistence layer - but they are a defence-in-depth measure, not the primary authorization control. Relying solely on query filters means a missing `AsNoTracking()` or a manual query bypasses the filter. See [Multi-Tenant Data Isolation in ASP.NET Core: Row-Level vs Schema vs Database-per-Tenant](https://codingdroplets.com/multi-tenant-data-isolation-aspnet-core-row-level-vs-schema-vs-database-per-tenant) for the broader architecture decision.

### What are the security implications of using `IOptionsSnapshot` vs `IOptionsMonitor` for sensitive configuration?

Both support hot-reload of configuration, which is problematic for security-sensitive values like API keys, connection strings, and signing keys. A hot-reloaded signing key can cause in-flight JWT validations to fail if the key changes between token issuance and validation in the same request window.

For security-sensitive configuration, `IOptions<T>` (snapshot at startup, no hot-reload) is safer. If hot-reload is genuinely needed (e.g., rotating a key without restarting), you must handle the transition window explicitly - maintain both old and new keys in the validator's `ValidIssuingKeys` list during rotation.

### How does ASP.NET Core 10 change the handling of security headers and HTTPS enforcement compared to earlier versions?

.NET 10 and ASP.NET Core 10 continue to refine the `UseHsts()` and `UseHttpsRedirection()` defaults. In development, HTTPS redirection is disabled by default to simplify local development. HSTS is configured with `IncludeSubDomains` and a `MaxAge` of 30 days by default - senior developers should increase this to 1 year for production and consider `Preload` submission for high-value domains.

New in the .NET 10 cycle: improved OpenAPI security scheme documentation via the built-in OpenAPI support (`Microsoft.AspNetCore.OpenApi`), allowing security requirements to be declared on endpoint groups - eliminating the boilerplate of per-endpoint security declarations that was required in Swashbuckle-based setups.

### What is the zero-trust model and how does it apply to ASP.NET Core service-to-service communication?

Zero trust means "never trust, always verify" - no network location is inherently trusted. For service-to-service communication in a microservices architecture, this means every inter-service call must carry a verifiable identity (service account token, mTLS certificate) rather than relying on network-level trust (same VPC, same subnet).

In ASP.NET Core, this is implemented through: mutual TLS (mTLS) using Kestrel's client certificate authentication, or bearer tokens issued by an internal identity provider (e.g., Duende IdentityServer, Azure AD Managed Identities). The calling service acquires a token (typically via client credentials flow), and the receiving service validates it through the normal JWT bearer middleware.

The practical implication: even services behind a private load balancer should require and validate caller identity. Network-level firewalls are a perimeter control, not a zero-trust control.

---

---

## How to Answer Security Questions in a Senior .NET Interview

Beyond knowing the answers, senior candidates distinguish themselves with how they frame responses:

- **Lead with the risk, then the mitigation.** Interviewers want to know you understand *why* a control exists, not just *how* to configure it.
- **Mention trade-offs.** Every security control has a usability or performance cost. Acknowledging these shows architectural maturity.
- **Reference production experience.** Concrete examples ("in a multi-tenant SaaS we secured, we used...") carry more weight than abstract recitations.
- **Connect the dots.** Security is cross-cutting - link authentication to logging, link authorization to multi-tenancy, link secrets management to configuration. Senior engineers think in systems.

---

## Frequently Asked Questions

**What ASP.NET Core security topics are most commonly asked in senior .NET interviews?**
JWT authentication and refresh token rotation, OWASP Top 10 mitigations in .NET, policy-based and resource-based authorization, ASP.NET Core Data Protection, CORS misconfiguration, and secrets management strategies are the most consistently tested areas for senior roles. Most interviews include at least one scenario-based question where you are asked to design the authorization model for a specific feature.

**What is the difference between `[Authorize]` and `[AllowAnonymous]` in ASP.NET Core?**
`[Authorize]` applies the default authorization policy (or a named policy when specified) to an endpoint, requiring the caller to be authenticated and meet any defined requirements. `[AllowAnonymous]` explicitly bypasses all authorization checks, including any fallback policy. It takes precedence over `[Authorize]` - if both are present on the same endpoint, `[AllowAnonymous]` wins.

**How do you protect ASP.NET Core APIs from SQL injection in 2026?**
EF Core uses parameterized queries by default for all LINQ-based queries, making traditional SQL injection impossible through the ORM layer. Raw SQL via `FromSqlRaw` is vulnerable if user input is string-interpolated - always use `FromSqlInterpolated` (which uses `FormattableString` and parameterizes automatically) or `DbParameter` objects. Dapper requires explicit parameterization - pass anonymous objects as parameters, never string-concatenate user input into query strings.

**What is the recommended way to store passwords in an ASP.NET Core application?**
ASP.NET Core Identity's `PasswordHasher<TUser>` uses PBKDF2 with HMAC-SHA512, 600,000 iterations, and a random salt by default in .NET 8+. Do not use MD5, SHA-1, or SHA-256 without key stretching - they are too fast for password hashing. If you are not using Identity, use a library like `BCrypt.Net-Next` or `Argon2` via `Isopoh.Cryptography.Argon2`. Never store plaintext passwords or reversibly encrypted passwords.

**What is the significance of `ValidateIssuerSigningKey`, `ValidateIssuer`, and `ValidateAudience` in JWT validation?**
These are JWT validation parameters in `TokenValidationParameters`. `ValidateIssuerSigningKey` verifies the token's signature against the trusted signing key - disabling this effectively accepts any token without integrity verification. `ValidateIssuer` ensures the token was issued by a trusted authority (the `iss` claim). `ValidateAudience` ensures the token was intended for your API (the `aud` claim). All three should be `true` in production. A common misconfiguration: disabling audience validation in a microservices setup, which allows a token issued for Service A to be replayed against Service B.

**How should HTTPS be enforced in an ASP.NET Core production deployment?**
Use `UseHttpsRedirection()` to redirect HTTP requests to HTTPS, and `UseHsts()` to set the `Strict-Transport-Security` header, instructing browsers to only connect over HTTPS for the duration of the `max-age` period. For production, set `max-age` to at least one year and consider adding `includeSubDomains` and `preload`. TLS termination at the load balancer (with only internal traffic being plain HTTP) is acceptable - in this case, HTTPS redirection can be disabled internally, but HSTS should still be set on responses leaving the load balancer.

**What is an authorization policy in ASP.NET Core and how do you register a custom one?**
An authorization policy is a named set of requirements that an authenticated caller must satisfy. Policies are registered in `AddAuthorization(options => options.AddPolicy("PolicyName", policy => ...))`. Common policy builders: `RequireAuthenticatedUser()`, `RequireClaim(claimType, value)`, `RequireRole(role)`, and custom `Requirements` added via `policy.AddRequirements(new MyRequirement())`. Custom requirements need a corresponding `AuthorizationHandler<MyRequirement>` registered in DI. Named policies are then applied via `[Authorize(Policy = "PolicyName")]` or `RequireAuthorization("PolicyName")` on Minimal API endpoints.

* * *

## About the Author

**Celin Daniel** is Co-founder of Coding Droplets with 13+ years of hands-on experience building, shipping, and operating .NET and ASP.NET Core systems in production. The guidance here comes from real projects and production incidents, not theory.

- Website: [codingdroplets.com](https://codingdroplets.com/)
- GitHub: [github.com/codingdroplets](http://github.com/codingdroplets/)
- YouTube: [youtube.com/@CodingDroplets](https://www.youtube.com/@CodingDroplets)
