🔐 Authentication in ASP.NET Core — From Zero

Note: all original wording is preserved exactly as written. The original ASCII-art diagrams have been recreated below as proper Mermaid diagrams.

Imagine we have:

Architecture:

1. Start with the real problem

[Diagram]

API needs to know who is calling it. That is authentication.

2. Authentication vs Authorization

Authentication → Who are you? Authorization → What can you do?

Authentication is identity; authorization is permission.

3. Why not send password every time

Do not send username/password on every API request. User proves identity during login, then gets a token.

Analogy:

4. Token

A token is proof that the user/application has been authenticated and/or has certain permissions.

5. JWT

JWT = JSON Web Token. It is a token format.

Example:

eyJhbGciOiJIUzI1NiIs...
eyJzdWIiOiIxMjM0NTYi...
SflKxwRJSMeKKF2QT4fwp...

Conceptually a JWT may contain:

{
  "userId": "123",
  "name": "John",
  "role": "User",
  "exp": 1791195300
}

JWT is signed, allowing the API to verify it was issued by a trusted signer and not modified.

Important: JWT is not the same thing as OAuth.

6. Angular → ASP.NET Core basic flow

[Diagram]
[Diagram]

7. Login example

Conceptual login:

POST /login
Content-Type: application/json
{
  "email": "john@gmail.com",
  "password": "password123"
}

After authentication, client can receive:

{
  "accessToken": "eyJhbGciOi...",
  "refreshToken": "abc123..."
}

In real OAuth/OIDC SPA architecture, login is typically done through the Identity Provider rather than Angular directly handling the user password.

8. Calling API

GET /api/orders
Authorization: Bearer eyJhbGciOi...

"Bearer" basically means "I am presenting this token as my credential."

9. ASP.NET Core pipeline

[Diagram]

ASP.NET Core:

app.UseAuthentication();
app.UseAuthorization();

10. 401 vs 403

Memory: 401 = Who are you? I don't know you. 403 = I know you, but you can't do this.

11. Access token vs refresh token

Access token:

Refresh token:

Memory:

[Diagram]

12. Why access token is short-lived

If access token lasts 30 days and is stolen, attacker may use it for a long time. Short-lived token (e.g. 15 minutes) reduces exposure. But user should not have to log in every 15 minutes. Refresh token solves this.

13. Who creates refresh token

Usually authorization server / Identity Provider creates and issues it as part of the appropriate OAuth/OIDC flow.

Examples:

14. Who uses refresh token

Very important:

Correct:

[Diagram]

The client/application (Angular or a BFF/server depending on architecture) requests refresh; the authorization server actually validates the refresh credential and issues the new access token.

15. When refresh happens

Example:

10:00 AM User logs in Access Token expires 10:15 Refresh Token has longer lifetime

[Diagram]

10:15 Access Token expires Now client needs new access token.

16. How Angular knows access token expired

Two common patterns:

Approach A: Angular checks exp

JWT contains:

{
  "sub": "123",
  "name": "John",
  "role": "User",
  "exp": 1791195300
}

Angular can decode JWT payload and inspect exp.

Concept:

[Diagram]

Angular can refresh before making the API call or shortly before expiration.

Approach B: Let API return 401

Angular sends token:

[Diagram]

Angular HTTP interceptor sees 401 and triggers refresh.

Important nuance:

17. Actual refresh flow

[Diagram]

User does not need to type password again.

18. "Who refreshes the token?"

Wording is confusing:

Mental model:

[Diagram]

19. What authorization server checks

May check:

If invalid, refresh fails and user may need login again.

20. What if refresh token expires

[Diagram]

21. Refresh token rotation

Some providers use rotation:

[Diagram]

Helps detect suspicious reuse and limits useful lifetime of stolen refresh credential.

22. Refresh token storage / browser security

Do not memorize "refresh token always goes in localStorage."

Common designs:

HttpOnly means JavaScript cannot directly read cookie via document.cookie.

Correct storage depends on architecture/threat model.

23. Angular HTTP interceptor

Instead of adding token manually to every API request, interceptor can attach it:

[Diagram]

Conceptual code:

intercept(req, next) {
    const token = this.authService.getAccessToken();
    const request = req.clone({
        setHeaders: {
            Authorization: `Bearer ${token}`
        }
    });
    return next.handle(request);
}

Interceptor can also handle 401, trigger refresh, retry original request.

Production implementation should coordinate concurrent 401s so 10 requests do not all trigger refresh separately.

24. Who creates JWT?

Two patterns:

Option A: ASP.NET Core creates JWT:

[Diagram]

Possible for learning/simple architectures; production requires careful password handling, signing key management, validation, refresh handling, account lifecycle/security.

Option B: Dedicated Identity Provider:

[Diagram]

25. OAuth 2.0

OAuth 2.0 is an authorization framework, not "JWT." It defines ways for client applications to obtain access tokens to access protected resources. Access token may be JWT but OAuth does not require JWT.

OAuth vocabulary:

26. OAuth Authorization Code + PKCE

For modern browser applications such as Angular:

[Diagram]

The browser does not simply send password to Angular code and let Angular decide identity. Identity Provider handles authentication and issues credentials.

27. PKCE

Pronounced "pixy."

Simplified:

Before login:

[Diagram]

After login:

[Diagram]

Analogy:

28. OAuth scopes

Scopes describe access:

scope = orders.read
scope = orders.read orders.write

Think of scopes as permissions printed on pass:

[Diagram]

29. OpenID Connect (OIDC)

OIDC = identity layer built on OAuth 2.0.

OAuth:

"What can this application access?"

OIDC:

"Who is the user who authenticated?"

OIDC standardizes identity info and adds ID token.

30. ID Token vs Access Token

ID Token:

Access Token:

Mental model:

[Diagram]

Do not use ID token as API access token just because both may look like JWT.

31. OIDC login flow

  1. Angular starts login
  2. Browser goes to Identity Provider
  3. User authenticates
  4. IdP redirects with authorization code
  5. Code redeemed using PKCE
  6. Angular receives ID token + access token
  7. Angular sends access token to ASP.NET Core API

ID token helps client understand authenticated identity; access token is used to call protected API.

32. JWT vs OAuth vs OIDC

[Diagram]

Analogy:

33. ASP.NET Core JWT validation

API validates:

Security guard analogy:

Conceptual config:

builder.Services
    .AddAuthentication("Bearer")
    .AddJwtBearer("Bearer", options =>
    {
        options.Authority = "https://your-identity-provider";
        options.Audience = "orders-api";
    });

app.UseAuthentication();
app.UseAuthorization();

Exact config depends on IdP.

34. JWT signature / tamper protection

JWT has:

[Diagram]

If someone changes:

{"role":"User"}

to:

{"role":"Admin"}

the signature no longer matches and token is invalid.

The API must validate signature properly.

35. Why API can check expiration without DB

JWT contains exp; API can compare current time:

Current: 10:16
exp: 10:15
10:16 > 10:15 → expired

No DB query is needed just to determine whether exp has passed. This is one reason JWTs can be useful in distributed APIs.

36. Complete production architecture

[Diagram]

When access token expires:

[Diagram]

37. Complete end-to-end story

  1. User opens Angular.
  2. User clicks Login.
  3. Angular starts OAuth/OIDC Authorization Code + PKCE.
  4. Browser goes to Identity Provider.
  5. User authenticates.
  6. IdP redirects with authorization code.
  7. Code redeemed using PKCE.
  8. Client receives tokens.
  9. Angular calls ASP.NET Core API with access token.
  10. API validates token.
  11. API checks authorization.
  12. Controller executes.
  13. Access token expires.
  14. Client refreshes through the refresh mechanism.
  15. New access token is obtained.
  16. Angular continues API calls.
  17. When refresh/session credential can no longer be used, user may need to authenticate again.
[Diagram]