Phạm vi
Những gì một khóa được phép làm.
Bộ từ vựng
Một tập đóng, dạng resource:action. Đủ nhỏ để hiển thị cho con người trong một danh sách ô đánh dấu, và đủ ổn định để một quyền cấp đã lưu vẫn mang cùng ý nghĩa một năm sau. Cùng bộ từ vựng này là thứ dùng để viết VAI TRÒ của không gian làm việc và kiểm soát các công cụ MCP, nên một client chỉ đọc thậm chí không thể nhìn thấy công cụ gửi thư. Một bảng chữ cái, ba bề mặt.
| Phạm vi | Cấp quyền |
|---|---|
| emails:send | Gửi email |
| emails:read | Đọc thư đã gửi và trạng thái chuyển phát của chúng |
| drafts:read | Đọc bản nháp |
| drafts:write | Tạo và chỉnh sửa bản nháp |
| threads:read | Đọc luồng thư và thư |
| threads:write | Gắn nhãn, đánh dấu đã đọc và lưu trữ luồng thư |
| labels:read | Đọc nhãn |
| labels:write | Tạo và chỉnh sửa nhãn |
| contacts:read | Đọc liên hệ |
| contacts:write | Thêm, chỉnh sửa và xóa liên hệ |
| audiences:read | Đọc nhóm đối tượng và những ai thuộc về chúng |
| audiences:write | Tạo và chỉnh sửa nhóm đối tượng, và thay đổi những ai thuộc về chúng |
| calendar:read | Đọc sự kiện lịch và lời mời |
| calendar:write | Tạo, thay đổi và phản hồi sự kiện lịch |
| templates:read | Đọc mẫu email và xem trước chúng |
| templates:write | Tạo, chỉnh sửa và gửi bằng mẫu email |
| domains:read | Đọc tên miền và trạng thái DNS của chúng |
| domains:write | Xác minh và cấu hình tên miền |
| webhooks:read | Đọc endpoint webhook và các lần chuyển phát |
| webhooks:write | Tạo, chỉnh sửa và kiểm thử webhook |
| rules:read | Đọc quy tắc thư và kiểm thử chúng |
| rules:write | Tạo, chỉnh sửa và sắp xếp lại quy tắc thư |
| connections:read | Đọc những hộp thư nào đã được kết nối |
| members:read | Xem ai ở trong không gian làm việc và họ có những quyền gì |
| members:write | Thêm và xóa người, và thay đổi những gì họ có thể truy cập |
| roles:read | Đọc các vai trò mà không gian làm việc này định nghĩa |
| roles:write | Tạo, chỉnh sửa và xóa vai trò |
| settings:read | Đọc cài đặt hộp thư, bao gồm chữ ký |
| settings:write | Thay đổi cài đặt hộp thư và chữ ký |
| keys:write | Thay thế secret của chính nó mà không cần ai mở console |
Khóa được tạo mà không có danh sách phạm vi được cân nhắc sẽ nhận emails:send và không gì khác. Mặc định an toàn cho một thông tin xác thực là thứ hẹp nhất vẫn khiến nó hữu dụng.
Một khóa bị giới hạn bởi vai trò đứng sau nó
Một khóa có thể được cấp theo một VAI TRÒ, và vai trò là mức trần chứ không phải quyền cấp thứ hai. Những gì khóa thực sự được làm là các phạm vi của chính nó GIAO với các quyền của vai trò đó (key.scopes ∩ role.permissions), được tính một lần tại ranh giới, trên mọi yêu cầu, trước khi đến bất kỳ endpoint nào. Không có gì ở phía sau biết đến sự tồn tại của vai trò: một phạm vi mà vai trò không có đơn giản là không nằm trong danh sách mà các bước kiểm tra phạm vi đọc.
Vì vậy, hai danh sách được đọc cùng nhau và không bên nào tự thắng. Một khóa có emails:send dưới một vai trò không có quyền đó thì không được gửi; một vai trò có emails:send không cho gì một khóa chưa từng yêu cầu nó. Đánh dấu một phạm vi là yêu cầu thẩm quyền, và vai trò quyết định bạn nhận được bao nhiêu trong số những gì đã yêu cầu.
Một khóa KHÔNG có vai trò thì không có mức trần, và do đó rộng bằng không gian làm việc mà nó được cấp cho. Đó là thứ mà mọi khóa được tạo trước khi có vai trò mang theo và là thứ mà chủ sở hữu vẫn nhận được khi để trống trường này, nên vai trò null là trạng thái RỘNG NHẤT mà một khóa có thể có, không phải hẹp nhất. Đó cũng là lý do việc xóa một vai trò buộc bạn phải cho biết các khóa của nó sẽ đi đâu: bỏ mồ côi chúng sẽ lặng lẽ nâng quyền từng khóa một.
Phần giao được phân giải cho từng yêu cầu thay vì được đóng dấu lên khóa lúc cấp. Điều đó khiến việc thu hẹp một vai trò là thu hồi trực tiếp, có hiệu lực từ lệnh gọi tiếp theo của bên gọi mà không cần xoay vòng khóa, và việc mở rộng một vai trò cũng có hiệu lực ngay theo đúng cách đó, và đó là nửa đáng ghi nhớ.
GET /ping và GET /keys/self báo cáo scopes cùng với grantedScopes và roleId cho một tình huống lỗi cụ thể. scopes là danh sách hiệu lực và là danh sách duy nhất cấp quyền cho bất cứ điều gì; grantedScopes là những gì khóa được cấp. Bất cứ thứ gì có trong danh sách thứ hai mà thiếu ở danh sách thứ nhất đã bị vai trò lấy đi, và sự khác biệt đó là toàn bộ câu trả lời cho “khóa của tôi có emails:send mà tôi vẫn nhận insufficient_scope”. Cách khắc phục là thay đổi vai trò chứ không phải tạo khóa khác.
curl "$OE/ping" -H "$AUTH" { "ok": true, "keyId": "4c1b257a66287fd113bd89d0", "mode": "live", "scopes": ["emails:read", "threads:read"], "roleId": "role_c40a95f21cc65d31c2a89e07", "grantedScopes": ["emails:send", "emails:read", "threads:read"], "workspaceId": "10417196-e324-4283-af98-66ec62167c47"}Năm quyền không bao giờ có thể đến được khóa: api-keys:read, api-keys:write, billing:read, billing:write và workspace:manage. Chúng là quyền nhưng không phải phạm vi, nên không vai trò nào dù hào phóng đến đâu có thể đặt chúng lên token: tạo khóa khác, thay đổi những gì khóa khác được làm, hoặc chuyển gói là việc chỉ một người đã đăng nhập mới làm được. Điều duy nhất một khóa có thể làm với chính nó là thay thế secret của mình, dưới phạm vi keys:write. GET /roles/permissions đánh dấu năm quyền này là scope: false, nhờ đó một component có thể hiển thị cả ma trận vai trò lẫn danh sách ô đánh dấu khi tạo khóa.
roles:write thực chất là toàn bộ bộ từ vựng, và giả vờ khác đi mới là tài liệu nguy hiểm hơn. Một khóa có quyền này có thể PATCH chính vai trò đang giới hạn nó và tự trao cho mình mọi thứ khác, và vì mức trần được phân giải cho từng yêu cầu nên mức rộng hơn áp dụng ngay ở lệnh gọi tiếp theo. Đó không phải lỗ hổng cần vá, vì một trình chỉnh sửa vai trò không thể chỉnh sửa vai trò thì không phải là trình chỉnh sửa vai trò. Đó là lý do không nên đặt roles:write lên một khóa chỉ cần đọc danh sách thành viên.
Phạm vi gửi
Tách biệt với phạm vi, một khóa có thể bị thu hẹp về những gì nó được gửi với tư cách. Nó mang hai danh sách. domainAllowlist chứa toàn bộ tên miền, và khóa có một tên miền có thể gửi với tư cách bất kỳ địa chỉ nào trên đó, kể cả các địa chỉ được tạo sau khóa. addressAllowlist chứa từng địa chỉ riêng lẻ. Để trống cả hai thì khóa rộng bằng không gian làm việc, không bao giờ rộng hơn. GET /keys/self hiển thị cả hai danh sách và GET /addresses báo cáo những gì một khóa cụ thể thực sự có thể dùng, đó là câu trả lời cho một lỗi from_address_forbidden không rõ nguyên nhân.
Cùng tập hợp đó thu hẹp những gì khóa đọc được. Thư đã gửi, theo dõi và lịch chỉ trả lời cho các địa chỉ mà khóa được gửi với tư cách, nên một khóa giới hạn trong một tên miền không gửi cũng không đọc thay mặt tên miền khác. Một tên miền trọn vẹn cũng cho phép khóa đặt tracking host của tên miền đó, điều mà khóa chỉ giới hạn ở từng địa chỉ không làm được.
Vậy là có ba lớp thu hẹp, và chúng kết hợp với nhau chứ không ghi đè nhau: các phạm vi trên khóa, các quyền của vai trò bên trên nó, và các tên miền cùng địa chỉ mà nó có thể đặt vào header From. Một lần gửi cần cả ba, và lời từ chối chỉ nêu tên lớp đầu tiên mà nó gặp.