Featured image of post Authentication vs. Authorization vs. OAuth: The 'ID Card' Mental Model

Authentication vs. Authorization vs. OAuth: The 'ID Card' Mental Model

Stop mixing up 401 and 403. A mastery guide to AuthN (Who you are), AuthZ (What you can do), and the OAuth Valet Key.

The two most confused words in software engineering start with “Auth”.

If you ask a junior dev, they’ll say: “It’s the login screen.” If you ask a senior dev, they’ll say: “Authentication is identity; Authorization is permission.”

But even seniors trip up when OAuth 2.0 enters the room.

This is the Mastery Guide to the Security Trinity. We’ll start with a clean mental model, then dive into JWT debugging, the crucial difference between 401 and 403, and why OAuth is like a Valet Key.


Part 1: Foundations (The Mental Model)

The Trinity

TermAbbreviationThe QuestionThe Real-World Object
AuthenticationAuthN“Who the hell are you?”ID Card (Passport)
AuthorizationAuthZ“Are you allowed to do this?”Gym Keycard
OAuthDelegation“Can he do this for you?”Valet Key

The “Luxury Condo” Analogy

Imagine you live in a high-tech luxury condo.

  • AuthN (The Doorman): You walk up to the building. The doorman looks at your face (or ID). “Ah, hello Mr. Hoang.”

    • Result: You are Authenticated. You are inside the lobby.
  • AuthZ (The Elevator): You swipe your keycard to go to the Penthouse. The elevator buzzes: beep-beep. “Access Denied.” You live on the 2nd floor, not the Penthouse.

    • Result: you are Authenticated (we know who you are), but Unauthorized (you can’t go there).
  • OAuth (The Dog Walker): You are away at work. You give your dog walker a key. But it’s a special key — it only opens the Service Entrance and the Living Room. It doesn’t open your Bedroom or Safe.

    • Result: You Delegated access to someone else, with limited scope.

Part 2: The Investigation (Debug Like a Pro)

In the API world, your “ID Card” is usually a JWT (JSON Web Token). If Auth breaks, don’t guess—inspect the token.

1. The “X-Ray Vision” (JWT.io)

A JWT is not encrypted; it’s just Base64-encoded. Anyone can read it.

Take that ey... string and paste it into jwt.io.

What to look for in the Payload:

  • sub (Subject): The User ID. (Is this the user you think it is?)
  • exp (Expiration): The Unix timestamp. (Is it expired?)
  • scope or roles: The permissions. (Does it have admin or just viewer?)

2. The Signature Check

If the token looks correct but the server rejects it, the Signature is wrong.

  • Symmetric (HS256): The API needs the same “secret key” that signed the token.
  • Asymmetric (RS256): The API needs the Public Key to verify the signature made by the Auth Server’s Private Key.

Pro Tip: If your API says “Invalid Signature”, 90% of the time you rotated the keys on the Auth Server but forgot to update the API’s Public Key.


Part 3: The Diagnosis (Error Codes Decoded)

The HTTP status code tells you exactly which part of the flow failed.

401 vs. 403 (The Most Common Debate)

CodeNameMeaningThe Doorman Says…Fix It By…
401UnauthorizedIdentity Missing/Bad.“I don’t know you. Show me your ID.”Logging in again. Sending a valid Authorization: Bearer header.
403ForbiddenPermission Denied.“I know you are Hoang, but you can’t enter the Penthouse.”Asking for more permissions (Upgrade account).

Stop saying “401 Unauthorized” means permission denied. It means Authentication failed. 403 means Authorization failed. Blame the HTTP spec for naming 401 purely.


Part 4: The Resolution (Code Patterns)

1. The OAuth “Dance” (Valet Key)

How does “Log in with Google” actually work? It is giving a Valet Key to your app.

  1. User says “I want to log in”.
  2. App sends User to Google’s “Key Counter” (Authorization Server).
  3. User tells Google: “Give this App a key that can only read my Email.” (Scope).
  4. Google hands the App a special code.
  5. App trades that code for an Access Token (The Valet Key).

2. Python Cookbook: Verifying a JWT

Don’t write your own crypto. Use PyJWT.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import jwt

token = "ey..."
public_key_pem = "-----BEGIN PUBLIC KEY..."

try:
    # 1. Decode & Verify Signature
    # 2. Check Expiration (exp) automatically
    payload = jwt.decode(token, public_key_pem, algorithms=["RS256"])
    
    print(f"Hello, User {payload['sub']}")

except jwt.ExpiredSignatureError:
    print("401: Token Expired. Please refresh.")
except jwt.InvalidTokenError:
    print("401: Fake Token. Begone, hacker!")

3. Python Cookbook: Handling 403 (Role Check)

1
2
3
4
5
6
# The token is valid (Authentication passed), now check Permissions (Authorization)
user_roles = payload.get("roles", [])

if "admin" not in user_roles:
    # We know who you are, but you can't touch this.
    raise PermissionDenied("403: You need Admin access for this.")

Final Mental Model

1
2
3
4
5
6
AuthN (401) -> "Who are you?" (ID Card)
AuthZ (403) -> "Can you do this?" (Gym Keycard)
OAuth       -> "Can this App act as you?" (Valet Key)

JWT         -> The actual plastic card. 
               (Don't accept it if the expiry date is scratched off).

If you remember “ID Card vs. Keycard”, you’ll never mix up Authentication and Authorization again.

Made with laziness love 🦥

Subscribe to My Newsletter