OAuth 2.0 và OpenID Connect

Tìm hiểu về OAuth 2.0 và OpenID Connect là gì?

I. OAuth 2.0 là gì?

OAuth 2.0 là một giao thức tiêu chuẩn để ủy quyền, được sử dụng rộng rãi để cho phép các ứng dụng truy cập vào tài nguyên của người dùng trên một dịch vụ khác mà không cần chia sẻ thông tin đăng nhập (username/password). OAuth 2.0 là phiên bản cải tiến của OAuth 1.0, cung cấp một phương thức linh hoạt, an toàn và dễ triển khai hơn.
Ví dụ cho ứng dụng sử dụng OAuth 2.0  là draw.io, đây là một ứng dụng vẽ đồ thị thông dụng.
Draw.io sử dụng OAuth 2.0 để xin quyền truy cập vào các bộ lưu trữ như Google Drive, One Drive,… của người dùng.
OAuth 2.0 hoạt động xoay quanh access token, là một chuỗi kí tự bất kì, đại diện cho các quyền mà Resource owner cấp cho Client app. Access token luôn là kết quả của một OAuth 2.0 flow, là giá trị mà Client app nhận được. Client app có được access token, cũng đồng nghĩa với việc sở hữu giấy chứng nhận quyền được phép làm những gì với những tài nguyên nào.

II. Các thành phần trong OAuth 2.0

  • Resource owner: là chủ sở hữu các tài nguyên, là người dùng đứng ra cấp quyền cho các ứng dụng bên thứ 3.
  • Client: là ứng dụng bên thứ 3 đang xin quyền truy cập vào tài nguyên của Resource owner. Khi Resource owner cấp quyền, client nhận được access token, client app sử dụng access token để truy cập tài nguyên được cấp quyền.
  • Authorization server: đóng vai trò là trung gian giữa Resource owner, Client, và Resource server. Authorization server là bên đứng ra cấp access token cho client sau khi client được Resource owner cấp quyền.
  • Resource server: Nơi nắm giữ tài nguyên của người dùng. Những tài nguyên này được bảo vệ, và chỉ cho phép các ứng dụng khác (Client app) truy cập khi các ứng dụng này cung cấp được access token với những quyền tương ứng.

III. Một số OAuth 2.0 flow tiêu biểu

OAuth 2.0 cung cấp một số flow phù hợp với tính chất của các ứng dụng phía client.  Client trong OAuth 2.0 có thể là các ứng dụng web như các website, web application, SAP. Các web client có thể chỉ là ứng dụng client only hoặc bao gồm cả backend. Ngoài ra có các flow áp dụng cả cho cả các thiết bị mobile, wearable hoặc tv…

1. Authorization code flow

OAuth 2.0-va-OpenID-Connect-3
Mô tả:
Authorization code flow cho phép các ứng dụng client truy cập các resource được bảo vệ như API, user data,… mà không cần tới các thông tin xác thực người dùng như username và password. Flow này liên quan tới việc Client app đổi authorization code lấy access token. Client app sau đó sử dụng access token để truy cập tài nguyên được cấp quyền.
Cách hoạt động:

Bước 1: User (resource owner) ấn nút login

Bước 2: Client chuyển hướng (redirect) user tới trang của Authorization Server để ủy quyền.

Các parameter được đưa vào redirect URL để khởi động Authorization Flow. Ví dụ, một Client app có thể xin quyền truy cập vào email của người dùng với request như sau:

https://example-authorization-server.com/authorize-endpoint
?response_type=code
&client_id=example-client-id
&redirect_uri=https://example-client.com/callback
&scope=email
&state=random-text
  • response_type: giá trị “code” có nghĩa là Client app expect nhận được authorization code nếu thành công.
  • client_id: id public của Client app, được Authorization server cấp khi lập trình viên đăng kí Client app.
  • redirect_uri (optional): Sau khi user đồng ý cấp quyền cho Client app, Authorization server redirect trình duyệt người dùng về đường dẫn này. URL này cũng được đăng kí từ trước, khi lập trình viên đăng kí Client app.
  • scope (optional): giá trị chỉ định những quyền mà Client app đang xin được cấp (có thể xin cấp 1 hoặc nhiều quyền cùng lúc). Tùy Authorization Server sẽ có những scope khác nhau, chi tiết các bạn có thể tìm trong spec của Authorization Server đang request.
  • state (recommend): Giá trị được client app tạo ra và đính kèm vào request, được sử dụng để chống CSRF. Authorization server khi trả về authorization code cho client app (bước 5), sẽ trả về cả giá trị state này. Client app sau đó có nên thực hiện validate giá trị state nhận được với giá trị state đang nắm giữ.
Bước 3: Authorization server hiển thị màn hình cho phép user đăng nhập và phân quyền cho client app.
Ví dụ với Client app là draw.io, xin cấp quyền truy cập vào drive của người dùng (google đóng vai trò là Authorization server, google drive là Resource server):
Bước 4: User ấn xác nhận đồng ý cấp quyền cho client app

Bước 5: Authorization Server generate authorization_code, redirect trình duyệt người dùng về địa chỉ redirect_uri, đồng thời đính kèm authorization_code

HTTP/1.1 302 Found
Location: https://example-client.com/callback?code=example-authorization-code&state=random-text
  • code: Giá trị authorization code
  • state: Nếu ở bước 2, Client app có đính kèm state, thì response cũng sẽ có tham số này với cùng chính xác giá trị.

Bước 6: Client app gửi authorization code, client_id, cùng với thông tin xác thực của Client app (như client_secret hay private key) tới Authorization Server (token endpoint).

POST /token-endpoint HTTP/1.1
Host: example-authorization-server.com
grant_type=authorization_code
&code=example-authorization-code
&redirect_uri=https://example-client.com/callback
&client_id=example-client-id
&client_secret=example-client-secret
  • grant_type (required): phải dược set với giá trị “authorization_code”
  • code (required): giá trị authorization code
  • redirect_uri (có thể required): nếu ở bước 2 có bao gồm giá trị redirect_uri, thì bước này cũng cần truyền theo, và giá trị redirect_uri ở bước 2 và bước này phải bằng nhau
  • client_id (có thể required nếu như không sử dụng phương thức xác thực client khác): ở bước 6 này, Client app cần xác thực với Authorization server. Một cách thường hay sử dụng là truyền trực tiếp giá trị client_id và client_secret vào parameter. Một phương thức xác thực khác cũng thường được sử dụng là HTTP Basic Authentication. Ngoài ra theo spec, public/private key pair cũng có thể được dùng thay cho các phương thức trên, tuy nhiên cách này không được phổ biến bằng.
  • client_secret (sử dụng tùy lúc theo như mô tả ở trên): là giá trị bí mật mà Client app được cấp khi lập trình viên đăng kí Client app. Client app cần lưu giữ giá trị này một cách bảo mật, tránh để lộ, có thể hình dung client_secret như mật khẩu riêng của Client app.
Bước 7: Authorization server verify các giá trị authorization code, các thông tin xác thực của Client app. Nếu hợp lệ, Authorization server generate access token và trả về cho Client app.
HTTP/1.1 200 OK
Content-Type: application/json
 
{
    "access_token": "example-access-token",
    "scope": "email",
    "token_type": "Bearer",
    "expires_in": 299
}
  • access_token: giá trị access token
  • scope: phạm vi quyền được cấp
  • token_type: mô tả cách sử dụng access token, thường có giá trị “Bearer” (dùng trong header Authorization: Bearer <access_token>)
  • expire_in: thời gian sống của token (giây)
Bước 8: Client sử dụng access token, request tài nguyên từ Resource Server.
Bước 9: Resource server kiểm tra access token hợp lệ, trả về tài nguyên cho client.
Loại app có thể sử dụng:
Flow này được thiết kế tối ưu dành cho các ứng dụng có khả năng lưu trữ giá trị client_secret một cách bảo mật. Ví dụ như các server-side web app, như Java, .Net, Python, …
2. Authorization code flow with PKCE
Mô tả:
Proof Key for Code Exchange (viết tắt PKCE) là một extension cho Authorization code flow, giúp tăng cường bảo mật, chống lại các cuộc tấn công CSRF.
Cách hoạt động:
  • Trước mỗi authorization code flow, Client app thực hiện generate 1 cặp giá trị code_challenge và code_verifier.
  • code_verifier: một chuỗi từ 43 – 128 kí tự, bao gồm các kí tự A-Z, a-z, 0-9, -._~
  • code_challenge: nếu thiết bị có thể thực hiện sha256, thì caode_challenge được tính như sau: base64url(sha256(code_verifier)). Ngược lại, code_challenge có giá trị bằng code_verifier.
  • code_challenge được đính kèm tại bước 2 (code_challenge_method chỉ định phương thức tạo code_challenge, có thể là sha256 hoặc plain):
    https://example-authorization-server.com/authorize-endpoint
    ?response_type=code
    &client_id=example-client-id
    &redirect_uri=https://example-client.com/callback
    &scope=email
    &state=random-text
    &code_challenge=example-code-challenge
    &code_challenge_method=S256
    
      Phía authorization server sẽ chủ động detect code_challenge và code_challenge_method trong request, và liên kết giá trị code_challenge với giá trị authorization_code tạo ra.

Tại bước 6, client đính kèm code_verifier trong request lấy access token:

https://example-authorization-code.com/token-endpoint
?grant_type=authorization_code
&client-id=example-client-id
&client-secret=example-client-secret
&redirect_uri=https://example-client.com/callback
&code=example-authorization-code
&code_verifier=example-code-verifier

Authorization server nhận code_verifier, kiểm tra với giá trị code_challenge đã nhận trước đó. Nếu cặp giá trị hợp lệ thì request lấy access token mới được chấp nhận.

Loại app có thể sử dụng:

  • Là phần mở rộng, PKCE cũng có thể được sử dụng trên các loại Server-base web app tương tự Authorization Code Flow. Ngoài ra, PKCE flow cũng thường được sử dụng cho các app dạng public (không thể lưu giữ client_secret một cách bảo mật) như:
  • Single page app (SPA)
  • Desktop app
  • Mobile app

PKCE flow được khuyên dùng thay cho Authorization code flow nếu có thể.

3. Implicit flow

Mô tả:

Implicit flow thường được sử dụng cho các ứng dụng SPA trước đây khi browser còn nhiều hạn chế. Một trong những nguyên nhân chính Implicit flow ra đời là do thời điểm về trước, javascript chỉ có thể gửi request tới cùng domain mà trang web được load. Tuy nhiên, tại bước 6 của Authorization code flow cần client app gửi POST request tới Authorization Server, chính vì vậy, không thể sử dụng Authorization code flow.

Cách hoạt động:

  • Implicit flow loại bỏ việc client app gọi API đổi authorization code lấy access token, thay vào đó, access token được trả thẳng về cho Client app ngay sau khi user đồng ý cấp quyền.

Loại app có thể sử dụng:

  • Ngày nay, flow này được khuyên thay bằng Authorization code flow with PKCE do các vấn đề bảo mật, nhiều nhà cung cấp dịch vụ Authorization Server cũng không còn hỗ trợ loại flow này nữa.

4. Device flow

Mô tả:

Là loại flow được thiết kế cho 1 số loại thiết bị có sự hạn chế về đầu vào. Thay vì trực tiếp xác thực ủy quyền, các thiết bị sẽ nhờ người dùng truy cập đường dẫn trên máy tính hoặc điện thoại của họ để thực hiện điều này. Ví dụ, một số loại internet TV có khả năng truy cập internet, tuy nhiên việc yêu cầu người dùng đăng nhập và ủy quyền trực tiếp rất khó khăn do người dùng phải dò tìm lần lượt từng kí tự trên điều khiển TV, gây khó khăn và tạo trải nghiệm không tốt cho người dùng. Thay vào đó, TV hiển thị mã QR trên màn hình, người dùng có thể quét mã này bằng điện thoại, truy cập đường dẫn, và cấp quyền cho thiết bị.

Cách hoạt động:

Bước 1: User ấn khởi động thiết bị và sử dụng ứng dụng

Bước 2: Client (device app) request tới “device authorization endpoint” để lấy device code, user code, verification URL.

POST /device-authorization-endpoint HTTP/1.1
Host: https://example-authorization-server.com
Content-type: application/x-www-form-urlencoded
 
client_id=example-client-id
scope=example-scope

Một lưu ý nhỏ tại bước này, một số Authorization server yêu cầu device app gửi kèm theo cả client_secret, hoặc gửi client_id và client_secret theo dạng basic authentication. Cụ thể các bạn nên xem document của nhà cung cấp dịch vụ Authorization server.

Bước 3: Authorization server trả dữ liệu về cho device app, ví dụ như sau:

HTTP/1.1 200 OK
Content-Type: application/json
 
{
    "user_code": "WSNQ-GDNJ",
    "device_code": "YoZL2MpW4wbTul1SsmQRaE7GYhkPIV7kjXB0jldResRk80nGoii1BOQWPBALMHl7W1eVK5DSR2DgssJ7cxFXRzeSQE6ru3IWTHyaxe-qB6v_WPbtT4ANwmrn04tCDEKt",
    "verification_uri": "http://example-authorization-server.com/device-verification-endpoint",
    "verification_uri_complete": "http://example-authorization-server.com/device-verification-endpoint?user_code=WSNQ-GDNJ",
    "expire_in": 300
}
    • user_code: mã code mà người dùng cần nhập khi truy cập verification_uri để cấp quyền cho client (device app)
    • device_code: mã unique code cho client
    • verification_uri: chứa URL người dùng truy cập để cấp quyền
    • verification_uri_complete: chứa URL hoàn chỉnh người dùng truy cập để cấp quyền cho client
    • expire_in: thời gian sống của device_code, user_code (giây)
    • Bước 4: Người dùng nhận user_code và verification_uri
    • Thường client sẽ hiển thị mã user_code trực tiếp lên màn hình thiết bị cho người dùng, còn verification_uri sẽ được hiển thị qua QR code. Người dùng có thể sử dụng thiết bị khác quét mã QR này, để truy cập verification_uri cấp quyền cho Client.

Bước 5: Client sử dụng kĩ thuật polling, định kì gửi request tới “token endpoint” để lấy access token. Ví dụ như sau:

POST /token-endpoint HTTP/1.1
Host: https://example-authorization-server.com
Content-type: application/x-www-form-urlencoded
 
grant_type=urn:ietf:params:oauth:grant-type:device_code
client_id=example-client-id
device_code=YoZL2MpW4wbTul1SsmQRaE7GYhkPIV7kjXB0jldResRk80nGoii1BOQWPBALMHl7W1eVK5DSR2DgssJ7cxFXRzeSQE6ru3IWTHyaxe-qB6v_WPbtT4ANwmrn04tCDEKt

Tương tự như ở bước 2, client_secret có thể cần được gửi kèm, tuỳ thuộc vào nhà cung cấp Authorization server.

  • Bước a, b, c: Các bước này sẽ diễn ra trên trình duyệt của một thiết bị khác của người dùng:
  • Bước a: Người dùng truy cập đường dẫn verification_url, nhập user_code
  • Bước b: Authorization server yêu cầu người dùng xác nhận cấp quyền cho client
  • Bước c: Người dùng đồng ý cấp quyền

Bước 6: Sau khi người dùng đồng ý cấp quyền, request token tại bước 5 sẽ thành công, trả về access token cho client:

HTTP/1.1 200 OK
Content-Type: application/json
 
{
    "access_token": "example-access-token",
    "scope": "example-scope",
    "token_type": "Bearer",
    "expires_in": 299
}

Bước 7: Client gửi request lấy tài nguyên tới resource server, đính kèm access token

Bước 8: Resource server kiểm tra access_token hợp lệ, trả về tài nguyên cho client, kết thúc flow

IV. Ứng dụng của OAuth 2.0

  • Các ứng dụng bên thứ 3 muốn truy cập các tài nguyên của người dùng.
  • Sử dụng trong hệ thống microservice: các service trong hệ thống microservice có thể request access token từ 1 Authorization Server và sử dụng token này để xác thực với các service khác.
  • Single sign on (SSO): Oauth 2.0 có thể được sử dụng để triển khai SSO. Tuy nhiên cần tự triển khai thêm cơ chế để nhận dạng người dùng. Ví dụ client app sau khi nhận access token có thể gọi API /userinfo để lấy thông tin định danh người dùng.
  • Tích hợp các thiết bị thông minh: Các thiết bị như TV thông minh, tủ lạnh thông minh,… có thể sử dụng device flow để xin người dùng cấp quyền và tương tác tới các ứng dụng bên thứ 3 khác sử dụng access token được cấp.

Tìm hiểu về OpenID Connect

I. OpenID Connect là gì?

OpenID Connect là phần mở rộng được xây dựng dựa trên OAuth 2.0. Nó cho phép Client xác minh danh tính của người dùng, đồng thời cũng cho phép lấy các thông tin cơ bản về người dùng.

II. Các hoạt động của OpenID Connect

  • OpenID Connect hoạt động dựa trên khái niệm “ID Token”. Các OpenID Connect flow ngoài trả về access token, còn trả về thêm ID Token cho client app.
  • ID Token có dạng JWT (JSON Web Token). Khác với access token, ID Token có thể được client app decode và lấy các giá trị cần thiết chứa bên trong, có thể kể đến như sub (subject) là giá trị ID duy nhất của user, iss (viết tắt của issuer) là giá trị ID duy nhất của server sinh ra token, aud (viết tắt của audience) là giá trị ID của client app đang request token này.
  • Một OpenID Connect flow dựa trên Auth 2.0 Authorization Code flow như sau:

Sự khác biệt so vớ OAuth 2.0 nằm ở bước 2 và bước 7:

Bước 2: Client redirect user tới trang của Authorization Server để ủy quyền, đồng thời client cũng cho Authorization Server biết nó cần thêm ID Token, bằng cách chỉ định thêm scope openid:

https://example-authorization-server.com/authorize-endpoint
?response_type=code
&client_id=example-client-id
&redirect_uri=https://example-client.com/callback
&scope=email+openid
&state=random-text

Bước 7: Ngoài access token, refresh token (optional), Authorization Server trả về thêm id_token cho client:

HTTP/1.1 200 OK
Content-Type: application/json
 
{
    "access_token": "example-access-token",
    "scope": "email openid",
    "token_type": "Bearer",
    "expires_in": 299,
    "id_token": "example-id-token"
}

Các OpenID Connect flow khác, cũng được mở rộng dựa trên Oauth 2.0 flow theo những cách tương tự như trên.

III. Sự khác biệt so với OAuth 2.0

  • Oauth2.0 là một framework ủy quyền (authorization framework), kết quả của 1 flow Oauth 2.0, Client app nhận được access token, cho phép các ứng dụng bên thứ 3 truy cập vào các tài nguyên của người dùng mà không cần biết các thông tin định danh của người dùng (username, password). Bản thân Oauth 2.0 không định nghĩa 1 chuẩn nào để xác định thông tin của người dùng ủy quyền cho client app. Một ví dụ thực tế, khi các bạn đi thuê phòng khách sạn, bạn sẽ nhận được một thẻ phòng, các bạn có thể hình dung thẻ phòng này đóng vai trò như access token. Thẻ phòng giúp các bạn vào (truy cập) được phòng nhất định (Resource), nhưng bản thân thẻ này không chứa thông tin gì về bạn, không cho biết bạn là ai.
  • Với OpenID Connect, id_token sẽ được trả về cùng với access token. Khác với access token, Id token có dạng JWT, Client app có thể decode id_token để lấy các thông tin cơ bản về user (username, email, …).
  • Đứng ở góc độ là một người dùng, ứng dụng của OpenID Connect là về xác thực (cho phép user xác thực bản thân mình là ai với 1 ứng dụng bên thứ 3). Còn Oauth 2.0 là về ủy quyền (cho phép user ủy quyền cho một ứng dụng bên thứ 3).

IV. Ứng dụng của OpenID Connect

  • Single sign on (SSO): Với khả năng xác thực người dùng và chia sẻ danh tính người dùng một cách an toàn, OpenID Connect được ứng dụng vào các hệ thống SSO hiện đại.
  • Social login: Ngày nay rất nhiều trang web, ứng dụng sử dụng OpenID Connect cho phép người dùng đăng nhập bằng các tài khoản mạng xã hội như Google, Facebook,…

V. Kết

OAuth 2.0 và OpenID Connect là hai công nghệ quan trọng trong việc xác thực và ủy quyền, đóng vai trò then chốt trong việc bảo mật các ứng dụng hiện đại. OAuth 2.0 cung cấp cơ chế ủy quyền an toàn, cho phép người dùng chia sẻ quyền truy cập vào tài nguyên mà không cần tiết lộ thông tin nhạy cảm, như mật khẩu. Trong khi đó, OpenID Connect mở rộng OAuth 2.0 để cung cấp khả năng xác thực người dùng, giúp ứng dụng biết được danh tính của người dùng một cách an toàn và đơn giản.

Với sự phát triển không ngừng của công nghệ, việc áp dụng OAuth 2.0 và OpenID Connect trở nên phổ biến hơn bao giờ hết. Các tiêu chuẩn này không chỉ mang lại sự tiện lợi mà còn nâng cao bảo mật trong việc quản lý quyền truy cập và xác thực. Hiểu rõ và triển khai đúng các tiêu chuẩn này sẽ giúp các nhà phát triển xây dựng hệ thống đáng tin cậy, đáp ứng được các yêu cầu khắt khe về bảo mật và trải nghiệm người dùng.

Hy vọng bài viết này đã giúp bạn có cái nhìn tổng quan về OAuth 2.0 và OpenID Connect, cùng những ứng dụng thực tiễn của chúng trong thế giới số ngày nay.

Bạn cần chuyên gia tư vấn giải pháp Cloud phù hợp?

Vui lòng để lại thông tin, chúng tôi sẽ liên hệ với bạn trong thời gian sớm nhất!