# API Authn/Authz * Authn: Prove who you say you are (e.g. passport) * Authz: Prove that you're allowed to do what you're trying to do. (e.g. plane ticket) ## Example * [Auth0][5] * provides [OpenID Connect][4]. * returns an access token. * UI (:3000) * initiates a login/logout with Auth0. * retrieves data from the api using the access token. * API (:4000) * authorizes requests using the access token from the request. * returns data via a REST API. ``` ||========================|| ---------- --------- || --------------- ------ || | UI | | Auth0 | || | API ||| PDP | | DB | || ---------- --------- || --------------- ------ || | | || | | | || | GET /login | || | | | || |----------->| || | | | || |<-----------| || | | | || | "x.y.z" | || | | | || | | || | | | || | GET /atlas/{id} || | | | || | Authorization: "x.y.z" | | | || |----------------------->| | | || | | || |------>| | || | | || | allow | | || | | || |<------| | || | | || | | | || | | || |-------------->| || | | || | | | || | | || |<--------------| || |<-----------------------| | | || | | || | | | || | DELETE /atlas/{id}| | | | || | Authorization: "x.y.z" | | | || |----------------------->| | | || | | || |------>| | || | | || | deny | | || | | || |<------| | || |<-----------------------| | | || | | ||========================|| ``` ## Access Token ```json { "iss": "https://cmd0-dev.us.auth0.com/", "sub": "auth0|627b10e1019dd10068e03db4", "aud": [ "https://api.cmdzero.io", "https://cmd0-dev.us.auth0.com/userinfo" ], "iat": 1652843177, "exp": 1652929577, "azp": "zap85dH6ugiMvGCaXeHRjvD4AC1AOiU9", "scope": "openid profile email offline_access", "permissions": [ "read:incidents" ] } ``` ## Policy The [PDP][1] enforces policy by checking: * casbin policies to match the subject, request path, and request method. * subject is defined in the access token. * permissions are defined in the access token. ## Example Rule ```conf [request_definition] r = subject, resource, action [policy_definition] p = subject, resource, action [policy_effect] e = some(where (p.eft == allow)) [matchers] m = (p.subject == "*" || r.subject == p.subject) && r.resource == p.resource && r.action == p.action ``` | policy | subject | resource | method | | ------ | ------------------------ | ------------------------------- | ------ | | p | * | /api/atlas | GET | | p | * | /api/notifications/global | GET | | p | * | /api/public | GET | | p | 627b10e1019dd10068e03db4 | /api/notifications/QwfsJDutXwPD | GET | Example 1: ```http GET /api/public 200 OK ``` Example 2: ```http GET /api/public Authorization: Bearer access_token("627b10e1019dd10068e03db4") 200 OK ``` Example 3: ```http GET /api/notifications/QwfsJDutXwPD Authorization: Bearer access_token("627b10e1019dd10068e03db4") 200 OK ``` Example 4: ```http GET /api/notifications/QwfsJDutXwPD Authorization: Bearer access_token("f00d1e") 401 Unauthorized ``` [ABAC][2] ## Roles What about Roles? Rule ``` [request_definition] r = subject, resource, action [role_definition] g = subject, role, domain [policy_definition] p = role, domain, resource, action [policy_effect] e = some(where (p.eft == allow)) [matchers] m = g(r.subject, p.role, r.domain) && r.resource == p.resource && r.action == p.action ``` Policies | policy | role | domain | resource | action | | ------ | ----- | ------- | -------- | ------ | | p | admin | domain1 | data1 | read | | p | admin | domain1 | data1 | write | | p | admin | domain2 | data2 | read | | p | admin | domain2 | data2 | write | Groups | group | subject | role | domain | | ----- | ------- | ---- | ------ | | g | alice | admin | * | | g | bob | admin | domain2 | [RBAC][3] [1]: https://csrc.nist.gov/glossary/term/policy_decision_point [2]: https://casbin.org/docs/en/abac [3]: https://casbin.org/docs/en/rbac [4]: https://openid.net/specs/openid-connect-core-1_0.html#TokenResponse [5]: https://auth0.com/docs/secure/tokens/access-tokens/get-access-tokens#control-access-token-audience