Versions Compared
Key
- This line was added.
- This line was removed.
- Formatting was changed.
Overview
The Ed-Fi API needs to be secured with the OAuth 2.0 Client Credentials flow. In many cases a third-party authentication provider will be most appropriate for managing authentication. However, some organizations may wish to continue using a built-in authentication provider, as with the ODS/API Suite 3. In addition to managing the authentication process itself, the built-in provider should handle provisioning of keys and secrets. In this way, we will be able to have a micro data store that is accessed by only a single application.
Requirements
Authentication / Token Generation
Support Client Credentials flow
- Example route signature:
POST /oauth/token
- with support for the following message body formats:
grant_type
,client_id
, andclient_secret
in a JSON payloadgrant_type
,client_id
, andclient_secret
in a form-urlencoded payloadgrant_type
in a json payload, withclient_id
, andclient_secret
encoded into a basic authentication headergrant_type
in a form-urlencoded payload, withclient_id
, andclient_secret
encoded into a basic authentication header.
- with responses:
200 when the request is valid, with a signed JSON Web Token (JWT) as an access code response (more detail on JWT below). Example:
Code Block { "access_token": "eyJ0eXAiOiJKV1QiLCJibGciOiJIUzI1NiJ9.eyJpc3MiOiJlZC1maS1tZWfkb3dsYXJrIiwiYXVkIjoibWVhZG93bGFyayIsInJvbGVzIjpbInZlbmRvciJdLCJzdWIiOiJzdXBlci1ncmVhdC1TSVMiLCJqdGkiOiIyODQxNTY3Yi0wNzRiLTRiMDktYmQwMS1jZGYyODVlY2NjMDEiLCJpYXQiOjE2NTkzNzA2MjgsImV4cCI6MTY1OTM3NDIyOH0.GKwl3Uactabl6emQy9Ta2R5emGL6IF_v8w85LoR2wAs", "token_type": "bearer", "expires_in": 1659374228, "refresh_token": "not available" }
400 when the payload structure is invalid or the
grant_type
is invalid. Example:Code Block { "message": "The request is invalid.", "modelState": { "grant_type": [ "The grant_type '???' is not supported." ] } }
Note This is an "ideal" example that provides some consistency with existing messaging. The actual solution can be different based on the package components used in the solution.
401 with no message body when the
client_id
orclient_secret
is invalid. Deliberately not revealing why the authentication attempt failed.
JSON Web Token Response
The access token provided by the /oauth/token endpoint should be in the format of a signed JSON Web Token (JWT). The expected format of the JWT is described in some detail in Meadowlark - Data Authorization. In summary, the token's payload is expected to match this structure:
Code Block |
---|
{ "iss": "ed-fi-meadowlark", "aud": "ed-fi-meadowlark", "sub": "client name", "jti": "3d59b75f-a762-4baa-9116-19c82fdf8de3", "iat": 1636562060, "exp": 3845548881, "client_id": "fbf739c4-fb86-4f03-a477-91af51cc46f2", "roles": [ "vendor" ] } |
Token Introspection
An endpoint for verifying a token and accessing information about the token.
Warning |
---|
Can regular vendor/host tokens verify tokens? Or should we have a special client credential with a different role? For example, a role of "application" (Meadowlark itself) is allowed to verify tokens that are received by the application. Must decide on this when implementing. |
Example route signature: POST /oauth/verify with the token to verify in a form-urlencoded body, as well as a valid token authorizing the request itself. Example:
Code Block POST /oauth/verify Authorization: bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI.... token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI....
- The specification notes an optional
token_type
hint. Meadowlark will only support bearer tokens, so this parameter is not necessary. However, the service should not reject a payload that includes this parameter. It can simply ignore the parameter, always validating as a bearer token.
- The specification notes an optional
- responses:
200 if the token is still valid with a message body containing the token information in in a JSON payload.
Active token example:
Code Block language js title Active Token { "active": true, "client_id": "fbf739c4-fb86-4f03-a477-91af51cc46f2", "sub": "client name", "aud": "ed-fi-meadowlark", "iss": "ed-fi-meadowlark", "exp": 1659374285, "iat": 1659374285, "roles": [ "vendor" ] }
Inactive token example:
Code Block language js title Inactive Token { "active": false }
active
will mean that the token is valid:- issued by this application
- not revoked
- not expired
- 401 if the Authorization header is missing, invalid, or expired.
- Authorization
- A token with the "vendor" or "host" role can only verify their own token, no others. A token with the "admin" role can verify any token.
- A token with "admin.
Tip |
---|
One implication of this design is that the meadowlark API application needs to have client credentials with the "admin" role in order to verify incoming tokens. |
Client Credential Management
At this time there is no concept of vendors and applications - just keys and secrets. Therefore most of the Admin API Design is not relevant to this project. We simply need to have a route that supports creating keys and secrets.
- Support standard HTTP verbs and status codes
- Requires a token with role claim of "admin", any other valid token gets a 403 "forbidden" response, and invalid or no token gets a 401 response.
- URL endpoint: "oauth/client" to start with, adjust as needed.
- GET
- GET by id
- GET all
POST
body
Code Block { "clientName": "Hometown SIS", "roles": [ "vendor" ] }
- 400 response if clientName is missing and/or there is not at least one role in the request.
Three roles and one variant will be available.
- vendor
- READ access on all descriptors
- Full CRUD access on those resources created by this client credential
- OAuth Token introspection for own token
- host
- Full CRUD access on all Ed-Fi API resources
- OAuth Token introspection for own token
- admin
- Full CRUD on OAuth Client endpoint
- OAuth Token introspection for any token
- assessment
- Disables the reference checks on POST statements
- Generally speaking, one client would have either vendor or host role, not both. However, it is probably not worthwhile to force them to be mutually exclusive through validation.
- vendor
response
Code Block location: /oauth/client/a-uuid-v4-value { "client_id": "a-uuid-v4-value", "client_secret": "a really good random secret", "clientName": "Hometown SIS", "roles": [ "vendor" ] }
- PUT
body
Code Block { "client_id": "a-uuid-v4-value", "clientName": "Hometown SIS", "roles": [ "vendor" ] }
- does not update client_id or client_secret
Generate a new secret for an existing client id:
Request: POST /oauth/client/a-uuid-v4-value/reset
Response
Code Block { "client_id": "a-uuid-v4-value", "client_secret": "a new really good random secret" }
- DELETE should be a soft delete / deactivation
- When deactivated, token introspection endpoint should return "active": false for any token created for that client_id, and that client_id should now get a 401 response when used in a POST to oauth/token
Implementation Notes
Treat as a microserviceSeparate API application,Microservice
Application should be separate from the Meadowlark Ed-Fi API, and can be written in either TypeScript or Python
As a microservice, it will have its own datastore.
- Should support both PostgreSQL and MongoDB
- By default, should use the same database as the Meadowlark API code, but with complete independence from the tables / collections used by the API code.
Can utilize open source* third-party identity provide packages (so as not GPL, LGPL, Affero GPL, or other restrictive / "viral" license)
Bootstrapping Initial Admin Credentials
Ideas:
- Manually run a local script that invokes the client creation process, bypassing the API and therefore not requiring credentials
- When first startup, cache existing admin accounts. If there are no admin accounts, relax security to allow new "admin" type client creation without a token. As soon as the first one is created, fully enforce the token authentication.
- What if the service is load-balanced? Implications for cache.
The first option sounds more secure than the second one; however, it might not be practical when running on a cloud service.
Table of Contents
Table of Contents |
---|