Auth / Identity — Mental Model

Auth / Identity — Mental Model

1. OAuth 2.0

OAuth chỉ là một standard/protocol, không phải technology hay framework.

Bản chất implementation vẫn là:

  • database
  • random token
  • conditions
  • API endpoints
  • expiry / permission checks

Server-to-server

1
2
3
4
client_id + client_secret
→ Authorization Server
→ access_token
→ Resource Server

client_id chỉ cần unique.
client_secret là random secret đủ mạnh.

Access token:

  • có thể là JWT
  • có thể chỉ là random opaque string
  • format không phải điểm quan trọng

Điểm quan trọng là:

1
2
3
Authorization Server phát token
→ Resource Server có cách verify token
→ biết token đại diện cho client/user nào và có quyền gì

User-delegated flow

Core vẫn giống server-to-server, chỉ thêm bước:

1
user consent

Flow:

1
2
3
4
5
6
7
8
Client
→ redirect Authorization Server
→ user login + consent
→ Authorization Server tạo authorization_code
→ redirect về Client
→ Client gửi code + client credentials/PKCE
→ Authorization Server trả access_token
→ Client dùng access_token gọi Resource Server

authorization_code có thể đơn giản là random string.

Backend Authorization Server lưu:

1
2
3
4
5
6
code
→ user_id
→ client_id
→ scope
→ expires_at
→ used_at

Code tồn tại chủ yếu để access token không phải đi qua browser redirect.


2. OpenID Connect

OIDC là standard xây trực tiếp trên OAuth 2.0, reuse lại flow và concepts của OAuth.

OAuth chủ yếu nói về:

1
client được phép làm gì

OIDC thêm:

1
user này là ai

Nó thêm một ID Token, thường là JWT.

Ví dụ:

1
2
3
4
5
6
7
{
"iss": "https://accounts.google.com",
"sub": "user_123",
"aud": "google-drive-client",
"exp": 123456,
"iat": 123000
}

Client verify:

  • signature
  • issuer
  • audience
  • expiration

Sau khi verify được ID Token, application có thể tạo local session riêng.

Mental model:

1
2
3
4
5
Identity Provider xác thực user
→ phát ID Token
→ App verify
→ biết user là ai
→ tạo session riêng cho app

OIDC không bắt buộc app phải dùng JWT cho local session; random session ID + database cũng được.


3. Identity database

OIDC dẫn đến bài toán:

1
2
Identity lưu tập trung
Application data lưu phân tán

Ví dụ:

1
2
3
4
5
6
7
8
9
10
11
12
Google Accounts:
user identity / password / MFA / sub

Google Drive:
oidc_sub
files
preferences

Gmail:
oidc_sub
mailbox
settings

App có thể tạo local user ngay lần login đầu:

1
2
3
4
5
verify ID Token
→ lấy iss + sub
→ không có local user
→ create local user
→ create session

Đây là JIT provisioning.


4. SCIM

OIDC không xử lý việc:

1
2
user bị create/update/disable/delete
→ sync sang các application khác

Standard cho việc này là SCIM 2.0.

Bản chất vẫn chỉ là standardized API:

1
2
3
4
POST /Users
PATCH /Users/:id
DELETE /Users/:id
/Groups

Không có technology đặc biệt; giá trị nằm ở việc mọi Identity Provider và SaaS cùng hiểu một contract.


5. AWS Cognito User Pool

Cognito User Pool về bản chất là:

1
2
3
4
User database
+ Authentication Server
+ OAuth Authorization Server
+ OpenID Provider

User login:

1
2
3
email/password
→ Cognito
→ ID Token + Access Token + Refresh Token

Backend app không cần call Cognito mỗi request.

Thay vào đó:

1
2
3
4
5
6
request có JWT
→ lấy kid
→ lấy public key từ JWKS
→ verify signature
→ check exp / iss / client_id / token_use
→ allow / reject

JWKS chỉ là public endpoint chứa public keys để verify JWT signatures.

Trade-off:

1
2
3
4
local JWT verification
= fast + cheap
but
revocation/disable có thể không realtime

6. Passkeys / WebAuthn

Passkey cuối cùng vẫn chỉ dựa trên asymmetric cryptography.

Register Passkey

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Facebook backend tạo random challenge
→ frontend gọi WebAuthn API
→ browser nói chuyện với macOS authenticator
→ macOS tạo:

private key
public key

→ private key giữ trong passkey store / iCloud Keychain
→ public key trả qua WebAuthn
→ frontend gửi public key về Facebook backend
→ Facebook lưu:

user_id
credential_id
public_key

Login

1
2
3
4
5
6
7
8
9
Facebook tạo challenge mới
→ browser/WebAuthn
→ macOS tìm private key
→ Touch ID cho phép sử dụng private key
→ private key ký challenge
→ signature gửi về Facebook
→ Facebook lấy public key đã lưu
→ verify
→ tạo Facebook session

challenge chỉ là random bytes để mỗi request authentication khác nhau và chống replay.

Touch ID không được gửi cho Facebook.

Nó chỉ làm:

1
2
user consent locally
→ macOS cho phép dùng private key

Standards

Umbrella:

1
2
3
FIDO2
├── WebAuthn
└── CTAP

WebAuthn chuẩn hóa website/browser flow.

CTAP chuẩn hóa browser/OS ↔ authenticator.

Backend vẫn tự do chọn Rails/Go/Postgres/Redis…, nhưng phải follow WebAuthn verification rules.


Core conclusion

Hầu hết những thứ nghe rất phức tạp trong auth thực ra vẫn là:

1
2
3
4
5
6
normal programming
+ database
+ cryptography
+ API
+ conditions
+ standardized contracts

OAuth, OIDC, SCIM, WebAuthn không phải magic hoặc technology mới.

Giá trị lớn nhất của chúng là:

1
2
3
4
nhiều hệ thống khác nhau
→ cùng nói một ngôn ngữ
→ interoperable
→ không phải tự invent auth protocol