OSIRAA - Open Source Implementer's Reference Authorized Agent
DRP Cert Test Suite
Version 0.9.3 - Updated November 2024
See also https://github.com/consumer-reports-innovation-lab/data-rights-protocol/blob/main/data-rights-protocol.md
2. POST /v1/data-rights-request (“Data Rights Exercise” endpoint)
- A Data Rights Exercise request SHALL contain a JSON-encoded message body
- The message body SHALL have a libsodium/NaCl/ED25119 binary signature immediately prepended to it
- The message body MUST containing the following fields:
- “agent-id” - a string identifying the Authorized Agent which is submitting the data rights request
- “business-id” - a string identifying the Covered Business which the request is being sent to
- “issued-at” - an ISO 8601-encoded timestamp expressing when the request was created.
- “expires-at” - an ISO 8601-encoded timestamp expressing when the request should no longer be considered viable
- “drp.version” - a string referencing the current protocol version "0.9.3"
- “exercise” - string specifying the Rights Action: [ access | deletion | sale:opt_out | sale:opt_in | access:categories | access:specific ]
- “regime” (optional) - a string specifying the legal regime under which the Data Request is being taken: [ ccpa | voluntary ]
- “relationships” (optional) - a list of string 'hints' for the Covered Business
- “status_callback” (optional) - a URL that the Status Callback can be sent to
- “name” (str) - if known, claim SHALL contain the user's full name most likely known by the Covered Business
- “email” (str) - if known, claim SHALL contain the user's email address
- “email_verified” (bool) - TRUE if the user's email address has been affirmatively verified according to the System Rules
- “phone_number” (str) - if known, claim SHALL contain the user's phone number in E.164 encoding
- “phone_number_verified” (bool) - TRUE if the user's phone number has been affirmatively verified according to the System Rules
- “address” (str) - if known, claim SHALL contain the user's preferred address, asspecified in OpenID Connect Core 1.0 section 5.1.1
- “address_verified” (bool) - TRUE if the user's address has been affirmatively verified according to the System Rules
- “power_of_attorney” (str) - MAY contain a reference to a User-signed document delegating power of attorney to the submitting AA
- The Privacy Infrastructure Provider SHALL validate the message is signed according to the guidance in section 3.07
- All calls MUST return a Data Rights Status object for all actions listed in the Service Directory for the Covered Business
- Values of fields may vary, see below. Test all supported permutations:
- POST /v1/data-rights-request { action: “access”, regime: “ccpa” }
- POST /v1/data-rights-request { action: “access”, regime: “voluntary” }
- POST /v1/data-rights-request { action: “deletion”, regime: “ccpa” }
- POST /v1/data-rights-request { action: “deletion”, regime: “voluntary” }
- POST /v1/data-rights-request { action: “sale:opt_out”, regime: “ccpa” }
- POST /v1/data-rights-request { action: “sale:opt_out”, regime: “voluntary” }
- POST /v1/data-rights-request { action: “sale:opt_in”, regime: “ccpa” }
- POST /v1/data-rights-request { action: “sale:opt_in”, regime: “voluntary” }
- Returns a Data Rights Status object
- MUST contain field “request_id”
- “request_id” is globally unique
- MUST contain field “status”
- “status” allowable values: [ "in_progress" | "open" | "fulfilled" | "revoked" | "denied" | "expired" ]
- allowable status values vary with action; see below
- MAY contain field “reason”
- “reason” allowable values: "need_verification" | "suspected_fraud" | “insuf_verification” | "no_match" | "claim_not_covered" | "too_many_requests" | "outside_jurisdiction" | "other" | “none”
- allowable reason values vary with status; see below
- MUST contain field “received_at”
- “received_at” is an ISO 8601 string (ISO time format)
- SHOULD contain field “expected_by”
- “expected_by” is an ISO 8601 string (ISO time format)
- MAY contain a field "processing_details", a text string - @RR is there a max character length?
- MAY contain a field "user_verification_url"
- "user_verification_url" must be a well formatted URI
- "user_verification_url" must a valid endmpoint which correctly returns data about the request
- MAY contain a field "expires_at"
- "expires_at" should be an [ISO 8601]-encoded time
- Additional optional/unknown fields - throw a warning
2.1. POST /v1/data-rights-request { action: “access”, regime: “ccpa” }
- Status: “open” | “in_progress”
- If status == “open”, reason SHOULD be “none”
- If status == “in_progress”, reason SHOULD be “need_verification” | “none”
- If status == “in_progress”, response MUST contain "expires-at"
2.2. POST /v1/data-rights-request { action: “access”, regime: “voluntary” }
- Status: “open” | “in_progress” | “denied”
- If status == “open”, reason SHOULD be “none”
- If status == “in_progress”, reason SHOULD be “need_verification” | “none”
- If status == “in_progress”, response MUST contain "expires-at"
- If status == “denied”, reason SHOULD be “outside_jurisdiction”
2.3. POST /v1/data-rights-request { action: “deletion”, regime: “ccpa” }
- Status: “open” | “in_progress”
- If status == “open”, reason SHOULD be “none”
- If status == “in_progress”, reason SHOULD be “need_verification” | “none”
- If status == “in_progress”, response MUST contain "expires-at"
2.4. POST /v1/data-rights-request { action: “deletion”, regime: “voluntary” }
- Status: “open” | “in_progress” | “denied”
- If status == “open”, reason SHOULD be “none”
- If status == “in_progress”, reason SHOULD be “need_verification” | “none”
- If status == “in_progress”, response MUST contain "expires-at"
- If status == “denied”, reason SHOULD be “outside_jurisdiction”
2.5. POST /v1/data-rights-request { action: “sale:opt_out”, regime: “ccpa” }
- Status: “open” | “in_progress”
- If status == “open”, reason SHOULD be “none”
- If status == “in_progress”, reason SHOULD be “need_verification” | “none”
- If status == “in_progress”, response MUST contain "expires-at"
2.6. POST /v1/data-rights-request { action: “sale:opt_out”, regime: “voluntary” }
- Status: “open” | “in_progress” | “denied”
- If status == “open”, reason SHOULD be “none”
- If status == “in_progress”, reason SHOULD be “need_verification” | “none”
- If status == “in_progress”, response MUST contain "expires-at"
- If status == “denied”, reason SHOULD be “outside_jurisdiction”
2.7. POST /v1/data-rights-request { action: “sale:opt_in”, regime: “ccpa” }
- Status: “open” | “in_progress”
- If status == “open”, reason SHOULD be “none”
- If status == “in_progress”, reason SHOULD be “need_verification” | “none”
- If status == “in_progress”, response MUST contain "expires-at"
2.8. POST /v1/data-rights-request { action: “sale:opt_in”, regime: “voluntary” }
- Status: “open” | “in_progress” | “denied”
- If status == “open”, reason SHOULD be “none”
- If status == “in_progress”, reason SHOULD be “need_verification” | “none”
- If status == “in_progress”, response MUST contain "expires-at"
- If status == “denied”, reason SHOULD be “outside_jurisdiction”
3. GET /v1/data-rights-request/{request_id} (“Data Rights Status” endpoint)
- Returns a Data Rights Status object
- Data Rights Status object MUST contain field “request_id”
- “request_id” value should match the value passed in
- Data Rights Status object SHOULD contain field “received_at”
- “received_at” is an ISO 8601 string (ISO time format)
- Data Rights Status object SHOULD contain field “expected_by”
- “expected_by” is an ISO 8601 string (ISO time format)
- Data Rights Status object MUST contain field “status”
- “status” allowable values: [ "in_progress" | "open" | "fulfilled" | "revoked" | "denied" | "expired" ]
- allowable status values vary with action; see below
- Data Rights Status object MAY contain “reason” field
- “reason” allowable values: “need_verification” | "suspected_fraud" | “insuf_verification” | "no_match" | "claim_not_covered" | "too_many_requests" | "outside_jurisdiction" | "other" | “none”
- allowable reason values vary with status; see below
- Data Rights Status object MAY contain field “processing_details”
- unconstrained text - @RR is the there a max character limit?
- Data Rights Status object MAY contain field “user_verification_url”
- “user_verification_url” is a well-formatted url
- “user_verification_url” is a an returns the correct data when called
- Data Rights Status object MAY contain field “expires_at”
- “expires_at” is an ISO 8601 string (ISO time format)
- Additional optional/unknown fields - throw a warning
3.1 GET /status fulfilled
- Additional fields: “results_url”, “expires_at”
- Final
3.2 GET /status denied
- “reason” allowable values: "suspected_fraud" | “insuf_verification” | "no_match" | "claim_not_covered" | "too_many_requests" | "outside_jurisdiction" | "other" | “none”
- Additional fields: “processing_details”
- Final for all reasons except "too_many_requests"
3.3 GET /status expired
- The time is currently after “expires_at” in the request
- Final
3.4 GET /status revoked
3.5 POST $status_callback (“Data Rights Status Callback” endpoint)
- SHOULD be implemented by Authorized Agents which will be exercising data rights for multiple Users
- The request body MUST adhere to the Exercise Status Schema
- THe PIP SHOULD make a best effort to ensure that a 200 response is issued for the most recent status update
- The body of the callback's response SHOULD be discarded and not be considered for parsing
4 DELETE /v1/data-rights-request/{request_id} (“Data Rights Revoke” endpoint)
- Returns a Data Rights Status object
- Data Rights Status object MUST contain field “request_id”
- “request_id” value should match the value passed in
- Data Rights Status object MUST contain field “received_at”
- “received_at” is an ISO 8601 string (ISO time format)
- Data Rights Status object MUST contain “status” field
- “status” allowable values: [ "in_progress" | "open" | "revoked" | "denied" | "expired" ]
- allowable status values vary with action; see below
- Responses MUST contain the new revoked state - @RR this is underspecified, in what field is "revoked" contained?
- Data Rights Status object MAY contain “reason” field
- “reason” allowable values: “need_verification” | "suspected_fraud" | “insuf_verification” | "no_match" | "claim_not_covered" | "too_many_requests" | "outside_jurisdiction" | "other" | “none”
- allowable reason values vary with status; see below
- Additional optional fields
- TBD - enumerated in DRP spec, some have enumerated values for their fields
- Additional optional/unknown fields - throw a warning
5 POST /v1/agent/{agent-id} (“Pair-wise Key Setup” endpoint)
- returns a JSON response
- response has a field “agent-id”
- “agent-id” key SHALL match the agent-id presented in the signed request
- response has a field "token"
- PIPs SHOULD generate this token using a cryptographically secure source such as libsodium's CSPRNG
- if validation fails, the PIP SHALL return an HTTP 403 Forbidden response with no response body
5.1 GET /v1/agent/{agent-id} (“Agent Information” endpoint)
- does not need to return anything more than an empty JSON document and HTTP 200 response code
- if the agent-id presented does not match the presented Bearer Token, the PIP MUST return a 403 Forbidden response