Giới thiệu
Thật tuyệt vời khi đăng nhập vào ứng dụng web hay app mobile (ví dụ: Trello) bằng thông tin đăng nhập và thông tin của bạn đã được lữu trữ nơi khác, chẳng hạn như Google? hay Facebook?
Vâng đúng vậy OAuth2 và OpenID Connect đã mang lại cho chúng ta cảm giác thật tuyệt này.
Trước tiên chúng ta cùng xem thằng OAuth2 nó hoạt động ra sao trước rồi tới thằng OpenID Connect (vì OpenID Connect nó được phát triển từ OAuth2)
OAuth2
OAuth2.0 là gì?
OAuth2.0 là giao thức cho phép người dùng cấp quyền truy cập hạn chế tới tài nguyên của họ trên một web site này đến một web site khác mà không tiết lộ thông tin đăng nhập của họ.
#Access Token
Để có quyền truy cập vào các tài nguyên được bảo vệ, OAuth2.0 đã sử dụng access token, nó là một chuỗi đại diện cho các quyền truy cập. Access Token được sinh ra cho việc Authorization ở định dạng JWT.
JWTs gồm có 3 thành phần: header, playload và signature.
- Header thì chứa metadata về loại thông báo và thuật toán mã hóađẻ bảo mật nội dung của nó.
- Payload chứa một tập yêu cầu, yêu cầu về quyền nên được cho phép và các thông tin khác như đối tượng dự định và thời gian hết hạn.
- Signture được sử dụng để xác thực mã thông báo đáng tin cậy hay không bị làm giả.
#Scope
Quyền truy cập được đại diện bởi access token, trong OAuth 2.0 gọi là scope.
#Roles
OAuth roles Trong bất kỳ flow OAuth2.0 chúng ta có thể xác định các roles sau:
- Resource Owner: là thực thể có quyền truy cập vào tài nguyên thưowngf là enduser.
- Resource Server: Máy chủ lữu trữ các tài nguyên, đây chính là API mà bạn muốn truy cập.
- Client: Đây là app bên thứ 3 muốn truy cập vào tài nguyên được bảo vệ thay mặt cho Resource Owner.
- Authorization Server: Máy chủ xác thực Resource Owner và phát hành access token sau khi nhận đươc sự ủy quyền.
Protocol flow
Chi tiết về cách giao thức hoạt động. Nó hoạt động bằng cách ủy quyền xác thực người dùng cho dịch vụ lữu trữ tài khoản người dùng. Để dễ hình dùng luồng hoạt động hãy nhìn hình sau:
- Ứng dụng (Client) yêu cầu ủy quyền từ Resource Owner để truy cập tài nguyên.
- Với điều kiện Resource Owner cho phép quyền truy cập này, Ứng dụng sẽ nhận được Cấp phép.
- Ứng dụng yêu cầu Access Token (Mã truy cập) bằng cách xác thực với Authorization Server (Máy chủ ủy quyền và cấp Cấp quyền).
- Với điều kiện Ứng dụng được xác thực thành công và Cấp phép ủy quyền hợp lệ, Authorization Server sẽ phát hành Access Token (Mã truy cập) và gửi đến Ứng dụng.
- Ứng dụng yêu cầu quyền truy cập vào tài nguyên được bảo vệ bởi Resource Server (Máy chủ tài nguyên) và xác thực bằng cách hiển thị Mã truy cập Access Token.
- Với điều kiện Mã truy cập hợp lệ, Máy chủ tài nguyên sẽ phục vụ yêu cầu của Ứng dụng.
Các loại cấp phép
Ví dụ như khi bạn truy cập vào website thương mại điện tử ở form tạo account nó có button sign in with facebook
<%= link_to "Sign in with facebook", %q(https://www.facebook.com/v3.2/dialog/oauth?client_id=#{your_app_id]}&scope#{your_app_permissions}&redirect_uri=#{redirect_uri}"), class: "btn btn-primary"%>
Như các bạn thấy thì để button
hoạt động thì cần có tham số bắt buộc như:
- client_id app_id cái này khi bạn đã có account thì sẽ có cái này nhưng phải vào
facebook for developers
của bạn mới xem được. - scope cái này chỉ định quyền truy cập vào email, name, số điện thoại… mà app muốn yêu cầu từ bạn.
- redirect_uri Sau khi bạn xác nhận quyền truy cập (permissions) tức là khi bạn kết thúc quá trình ủy quyền của
facebook
và đấy chính là nó.
Tham só scope
thì không bắt buộc phải có nhưng 2 tham số client_id
và redirect_uri
thì bắt buộc.
Khi bạn vào website đăng nhập với facebook thì website này sẽ yêu cầu được trao quyền để láy các thông tin như email, username.. trên facebook của bạn. Lúc này website thưc hiện việc này băng cách chuyển tiếp người dùng về trang facebook service provider.
https://www.facebook.com/v2.8/dialog/oauth?response_type=token&display=popup&client_id=145634995501895&redirect_uri=https%3A%2F%2Fdevelopers.facebook.com%2Ftools%2Fexplorer%2Fcallback&scope=email
Như trên là một ví dụ. Trên trang của người dùng Facebook service provider đồng ý trao quyền (Màn hình request permission)
Sau khi bạn chấp nhận trao quyền thì facbook sẽ tạo cho bạn một access token cho website trên. Sau khi có được access token vừa có được thì website này sẽ gửi request cho Facebook để lấy cá thông tin của bạn mà được cho phép truy cập.
2. Open ID Connect
OnpenID Connect là một lớp nhận dạng đơn giản được phát triển dựa trên giao thức OAuth2.0, cho phép client xác minh danh tính của người dùng và cũng như lấy thông tin hồ sơ cơ bản của họ.
Một ứng dụng khi nhắc chúng ta đăng nhập với Facebook hoặc Google thì ứng dụng đó có thể OpenID Connect.
Các bước cơ bản của giao thức
- (A) Người dùng sẽ truy cập bên thứ ba và yêu cầu truy cập.
- (B) Bên thứ 3 gửi authentication request cho OpenID provider, mô tả scope sẽ được yêu cầu và response_type muốn nhận được.
- (C) OpenID provider yêu cầu user xác nhận danh tính sau đó sẽ cho phép bên thứ 3 các quyền trong scope.
- (D) OpenID provider gửi lại bên thứ 3 authentication Response chứa thông tin muốn ở bước (A) thường sẽ là ID Token và Access Token.
- (E, F) Bên thứ 3 sẽ dùng access token để trao đổi thông tin mà mình mong muốn.
OpenID Connect Authorization flow
1. Code Flow
- Người dùng yêu cầu đăng nhập vào ứng dụng bên thứ 3 (trello, lazada…)
- Bên thứ 3 sẽ redirect đến OpenID provider( lúc này người dùng cung câp các thông tin để xác thức đây là tao), kèm theo đó là thông tin như:
- client_id: mã đăng ký đinh danh với OpenID provide.
- scope: quyên mà bên thức 3 được cấp.
- response_type: code.
- redirect_uri: Nếu xác thực thành công thì bên OpenId provider sẽ redirect lại bên app thứ 3.
- OpenId provider render trang đăng nhập và yêu cầu cấp quyền. Nếu thành công sẽ quay trở lại uri ở bước 2 kem theo đó authorization code. Bên thứ 3 sẽ gửi request cùng với token. Đây là lý do mà response_type là code ở bước 2
- Lúc này người dùng đã qua lại ứng dụng bên thứ 3 đã được xác thực thành công. Sẽ lại gửi một request tới
OpenId provider
với dữ liệu gồm code, grant_type (chỉ định dang xác thực/ đăngký). Nếu thành công thìOpenId provider
trả lại ID Token có thể kèm theo access token. - Bên thứ 3 sẽ xác thực lại ID Token thành công thì có thể truy cập vào để lấy dữ liệu từ
resource server
.
2. Implicit Flow, Password Flow
- Flow này cũng giống bước 1 và 2.
- Tại bước 3 cũng tương tự nhưng response_type: id_token (và token). Ở flow này thì không yêu cầu xác thực một cách tường minh như bước 4 ở trên nên nó mới có tên Implicit flow. Điểm khác nữa của implicit flow là token trả về cho client được gắn vào phần fragment (hay hash) của callback url chứ không phải query.
3. Hybrid Flow
- Các bước của flow này hoàn toàn giống với authorization code flow.
- Ngoại trừ response_type gửi đi ở authentication request (bước 2) là code và id_token để lấy ID token và hoặc token để lấy access token hoặc cả 3.
- Sau đó
OpenId provider
trả lại authorization code và id token để gửi token request như bước 4. Bên thứ 3 nhận được authentication response sẽ có access token để sử dụng đồng thời vẫn có authorization code để trao đổi lấy refresh token để dùng dài lâu (chú ý rằng vòng đời của access token là khá ngắn, chỉ vài chục phút).
4. Example OpenID authentication
Ví dụ chuyển hướng xác thực cho OP
Bây giờ chúng ta sẽ thông qua một ví dụ xem làm thế nào nhận được ID Token từ OpenID Connect băng cách sử dụng authorization code flow khá thông dụng.
Bước 1 | Bước 2 | |
---|---|---|
Purpose | 1. Authenticate user 2. Receive user consent | 1. Authenticate client (optional) 2. Exchange code for token(s) |
Via | Front-channel request (browser redirection) | Back-channel request (app to web server) |
To | Authorisation endpoint | Token endpoint |
Result on success | Authorisation code | ID token |
Code flow: bước 1
Bên thứ 3 bắt đầu xác thực người dùng bằng cách chuyển hướng trình duyệt đến điểm cuối ủy quyền OAuth 2.0 của OpenID Provider. Yêu cầu xác thực OpenID về cơ bản là yêu cầu ủy quyền OAuth 2.0 để truy cập danh tính người dùng, được biểu thị bằng giá trị openid trong tham số scope
.
HTTP/1.1 302 Found Location: https://openid.c2id.com/login? response_type=code &scope=openid &client_id=s6BhdRkqt3 &state=af0ifjsldkj &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
Các tham số yêu cầu được mã hóa trong truy vấn URI:
- answer_type: Thiết lập code để chỉ ra luồng mã ủy quyền.
- scope Được sử dụng để chỉ định phạm vi ủy quyền được yêu cầu trong OAuth. Giá trị phạm vi
openid
báo hiệu một yêu cầu xác thực OpenID và mã thông báo ID. - client_id Mã định danh khách của bên thứ 3 tại OpenID Provider . Mã định danh này được chỉ định khi bên thứ 3 được đăng ký với OpenID Provider , thông qua API đăng ký máy khách, bảng điều khiển dành cho nhà phát triển hoặc một số phương pháp khác.
- state Giá trị mờ được đặt bởi bên thứ 3 để duy trì trạng thái giữa yêu cầu và gọi lại.
- redirect_uri URI gọi lại bên thứ 3 cho phản hồi xác thực.
Tại OpenID Provider, người dùng thường sẽ được xác thực bằng cách kiểm tra xem họ có phiên hợp lệ không (được thiết lập bởi cookie trình duyệt) và trong trường hợp không có điều đó, bằng cách nhắc người dùng đăng nhập. Sau đó, người dùng thường sẽ được hỏi liệu họ có đồng ý đăng nhập vào bên thứ 3 hay không.
OpenID Provider sau đó sẽ gọi cho máy khách redirect_uri bằng mã ủy quyền (khi thành công) hoặc mã lỗi (nếu quyền truy cập bị từ chối hoặc một số lỗi khác xảy ra, yêu cầu không đúng định dạng đó đã được phát hiện).
HTTP/1.1 302 Found Location: https://client.example.org/cb? code=SplxlOBeZQQYbYS6WxSbIA &state=af0ifjsldkj
Code flow: bước 2
OpenID Provider phải xác thực tham số state
và sử dụng code để tiến hành bước tiếp theo – trao đổi code cho ID token.
Authorisation code là một thông tin trung gian thu được từ bước 1. Do đó nó không mấy hưu ích với bên thứ 3 mà chỉ có ý nghĩa với OpenID Provider. Để lấy lại ID Token, bên thứ 3 phải gửi mã cho OpenID Provider, nhưng lần này với yêu cầu kênh ngược trực tiếp. Điều này được thực hiện vì hai lý do:
- Để xác thực khách hàng bí mật với OpenID Provider trước khi tiết lộ mã thông báo;
- Để phân phối mã thông báo trực tiếp đến bên thứ 3 , do đó, tránh để lộ chúng ra trình duyệt.
Việc trao đổi code-for-token
xảy ra tại token endpoint
của OpenID Provider:
POST /token HTTP/1.1 Host: openid.c2id.com Content-Type: application/x-www-form-urlencoded Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW grant_type=authorization_code &code=SplxlOBeZQQYbYS6WxSbIA &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
ID Khách hàng và truyền bí mất thông qua Authorization header. Ngoài xác thực cơ bản HTTP, OpenID Connect còn hỗ trợ JWT, không tiết lộ thông tin xác thực ứng dụng khách với yêu cầu token request, đã hết hạn và do đó bảo mật hơn.
Các tham số yêu token request được mã hóa theo mẫu sau:
- grant_type gán giá trị authorization code.
- code thu được từ bước 1.
- redirect_uri lặp lại uri ở bước 1
Khi thành công OpenID Provider trả về Object JSON:
HTTP/1.1 200 OK Content-Type: application/json Cache-Control: no-store Pragma: no-cache { "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ.ewogImlzc yI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5 NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZ fV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5Nz AKfQ.ggW8hZ1EuVLuxNuuIJKX_V8a_OMXzR0EHR9R6jgdqrOOF4daGU96Sr_P6q Jp6IcmD3HP99Obi1PRs-cwh3LO-p146waJ8IhehcwL7F09JdijmBqkvPeB2T9CJ NqeGpe-gccMg4vfKjkM8FcGvnzZUN4_KSP0aAp1tOJ1zZwgjxqGByKHiOtX7Tpd QyHE5lcMiKPXfEIQILVq0pc_E2DzL7emopWoaoZTF_m0_N0YzFC6g6EJbOEoRoS K5hoDalrcvRYLSrQAZZKflyuVCyixEoV9GfNQC3_osjzw2PAithfubEEBLuVVk4 XUVrWOLrLl0nx7RkKU8NXNHq-rvKMzqg" "access_token": "SlAV32hkKG", "token_type": "Bearer", "expires_in": 3600, }
Tóm lại
Tóm lại OpenID thì về xác thực (Sử dụng thông tin đăng nhập từ OpenID provider để đăng nhập ứng dụng thứ 3) còn OAuth là ủy quyền cho phép ứng dụng bên thứ 3 truy cập thông tin. Về cơ bản thì Flow của OpenId Connect giống như quy trình ủy quyển OAuth 2.0 nhưng vẫn có điểm khác như:
- Ngoài access-token thì Authorization server còn trả về Id-token.
- Có thể truyền thêm scope khi call Authorization server.
- Id-token chứa thông tin người dùng đã được xác thực.
OpenId Connect tiêu chuẩn khá nhiều thứ mà OAuth2.0 lại là sự lựa chọn như có thể định nghĩa cụ thể quyền truy cập vào username, email… đại loại rất chi tiết, đăng ký khá linh động cho client. Điều này giúp nhà phát triển để người dùng có nhiều lựa chon nhà cung cấp nhận dạng.