# SHCLinks: Redirect Design Sketch ## Background and Design goals See https://hackmd.io/kvyVFD5cQK2Bg1_vnXSh_Q ## Design Sketch #2: Redirect Method ## Redirect Method: Protocol & Workflow * **Upload Shared File(s)**. Data Sharer chooses or creates files to share; encrypts them (see details under "Decryption" below); uploads them to the resource server. If there is more than one file to share, the resource server creates a Sharing Manifest JSON file with an array of high-entropy shared file URLs: ```json { "type": "shclink-read", "locations": [ "http://server.example.org/file/33EA8A8ABC2F72F6A08319072083B6E2555C34F0487519558CA6E8DF8798ABD7", "http://server.example.org/file/55DADF33D4BB85C5E3B90011469B913DDD07A216D0A338309B6FAF467E58CDDF", ], "datatypes": [ "application/smart-health-card", "application/fhir+json" ] } ``` * **Generate a QR Link**. Data Sharer asks resource server to generate a QR Link for a Sharing Manifest or individual file. This is encoded as a `shclink:/...` URI. The QR can be configured as limited-use (e.g., only redeemable once), and *optionally* bound to a PIN that the Data Receiver must present to the Resource Server in order to follow the QR Link. ##### JSON QR Payload * `url`: URL for the authorization server (`https://` endpoint). * `exp`: Optional. Expiration time in Epoch seconds. Hint to help the Data Recipient determine if this QR is stale. * `flags`: Optional. String created by concatenating single-character flags in alphabetical order * `L` for long-term use * `O` for one-time-use * `P` if a receiver-supplied PIN is required for redemption * `decrypt`: Conditional. Omitted if the target resource is not encrypted. Included otherwise. This key is used to encrypt/decrypt the target file. (Format: 43 character string consisting of 32 random bytes, base64urlencoded. This field is necessary if we want to support encrypting files so that the resource server and authorization sever can't read them.) ##### Construct QR from JSON QR Payload 1. Create a JSON QR Payload ```json { "url": "https://ehr.example.org/qr/Y9xwkUdtmN9wwoJoN3ffJIhX2UGvCL1JnlPVNL3kDWM/claim", "flags": "LP", "decrypt": "rxTgYlOaKJPFtcEd0qcceN8wEU4p94SqAwIWQe6uX7Q" } ``` 2. Minify and base64urlencode ```text eyJ1cmwiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAvcXIvWTl4d2tVZHRtTjl3d29Kb04zZmZKSWhYMlVHdkNMMUpubFBWTkwza0RXTS9jbGFpbSIsImZsYWdzIjoiTFAiLCJkZWNyeXB0IjoicnhUZ1lsT2FLSlBGdGNFZDBxY2NlTjh3RVU0cDk0U3FBd0lXUWU2dVg3USJ9 ``` 3. Prepend `shclink:/` ```text shclink:/eyJ1cmwiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAvcXIvWTl4d2tVZHRtTjl3d29Kb04zZmZKSWhYMlVHdkNMMUpubFBWTkwza0RXTS9jbGFpbSIsImZsYWdzIjoiTFAiLCJkZWNyeXB0IjoicnhUZ1lsT2FLSlBGdGNFZDBxY2NlTjh3RVU0cDk0U3FBd0lXUWU2dVg3USJ9 ``` 4. Optionally prepend an https URL with a suffix of `#` if the resource server wishes to provide a landing page and/or a viewer for this content ```url https://ehr.example.org/qr-viewer#shclink:/eyJ1cmwiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAvcXIvWTl4d2tVZHRtTjl3d29Kb04zZmZKSWhYMlVHdkNMMUpubFBWTkwza0RXTS9jbGFpbSIsImZsYWdzIjoiTFAiLCJkZWNyeXB0IjoicnhUZ1lsT2FLSlBGdGNFZDBxY2NlTjh3RVU0cDk0U3FBd0lXUWU2dVg3USJ9 ``` 4. Encode QR ![qr](https://hackmd.io/_uploads/ryBjeDMEK.png =300x300) * **Share the QR Link**. Data Sharer allows a Data Recipient to scan the QR code. * **Follow the QR Link to redeem it**. Data Recipient "redeems" a link by submitting a `POST` to the the `.url` property from the `shclink:/` JSON payload, appending the PIN to this URL if the QR's `.flags` field indicates that a PIN is required. If the request is valid, the Resource Server returns a `301 Moved Permanently` status and a `Location:` header redirecting the client to a high-entropy URL where the Sharing Manifest is exposed (or in the case of a single file: a direct link to that file). Data Recipient SHALL follow up to three redirects, dereferencing any redirect Locations via `GET` to arrive at a Sharing Manifest with a MIME type of `application/smart-health-links-manifest+json` or an individual data file with a MIME type of `application/smart-health-links+jose`. * *PIN protection*. If a QR Link is bound to a PIN, the Resource Server SHALL require a correct `?PIN={bound PIN}` parameter on the initial `POST` before responding with a redirect header. If an incorrect PIN is supplied, this increments the server's cumulative count of failed redemption attempts. When this count exceeds a server-defined threshold (say, ~5), the Resource Server SHALL inactive the QR Link and respond with a `410 Gone` status. (Note that a request with a *missing* or *empty* PIN does not contribute to the failed redeption count.) * **Decrypt Received Files.** To decrypt files, the Data Recipient: * Derives a symmetric decryption key by base64urldecoding the `.decrypt` value (yielding a 32-byte random sequence) * Processes each file as a compact-serialization JWE encrypted with `"alg": "dir", "enc": "A256GCM"`, where the header includes only the `alg` and `dir` claims and the payload is the full shared file. * **Optional: Update Shared Files**. For some sharing scenarios, the Data Sharer MAY update the shared files from time to time (e.g., when new lab results arrive or new immunizations are performed). Updated verions SHALL be encrypted using the same key (if any) as the initial version. * **Optional: Periodically Re-fetch Updated Files**. When the original QR includes the `L` flag for long-term use, the Data Recipient MAY re-fetch contents at any time. When re-fetching data, the Data Recipient SHALL begin from the final redirect URL it discovered when first following the QR Link, because the first-stage redirection may no longer be in place.