Skip to content

[WIP] Allow accepting JWT tokens from other CARDs instances - #2388

Closed
OrdiNeu wants to merge 12 commits into
devfrom
ia45/foreign-jwt-auth
Closed

[WIP] Allow accepting JWT tokens from other CARDs instances#2388
OrdiNeu wants to merge 12 commits into
devfrom
ia45/foreign-jwt-auth

Conversation

@OrdiNeu

@OrdiNeu OrdiNeu commented Jul 7, 2026

Copy link
Copy Markdown
Member

Description

For the hub-and-spoke principle that we're hoping to use, it'll be convenient for us to pass JWT tokens between CARDS instances (for example, to pass updates on a form from one instance to another). This PR introduces a few things that allow this:

  1. Switching from symmetric to asymmetric encryption, so that we can pass the ability for CARDS instances to verify one another without needing them to be able to create new tokens for each other. The current CARDS implementation uses symmetric encryption, where the same key is used for encryption & decryption, which opens up a vulnerability where if you can decode it, you could also fake requests coming from another CARDS instance.
  2. Allowing you to store peer tokens, trusting or distrusting their JWTs as needed. This allows each site to selectively choose which peers they trust, which is a key part of federation (although slightly annoying in practice because we've had issues in CanDIG where people retained out of date keys).

To Test

  • Start up two cards instances:
    1. On one, add: audBuilder.add("localhost8081"); to CardsJwtTokenManagerImpl:152 and start via ./start_cards.sh --dev --test
    2. On the other, export CARDS_HOST_AND_PORT=localhost:8081 and then run ./start_cards.sh --dev --test -p 8081
  • Create a new patient/visit for each

You'll notice, under /bin/browser.html, that the JWTSigningKey has been moved to a node named JWTRSA256Key replaced with an asymmetric key:
image

You'll also notice, after creating a Survey for the new patient and logging in as that patient, that the structure of the JWT in the cards_auth_token has changed
image

You can then create a new Node /jcr:system/cards:jwt/localhost8080 (EDIT: you now need to use the hex representation of the hash of the public key as the node name) to the second instance, with property "verify" equal to the "verify" token from the first instance. If you login to the second instance as a Visit subject, and then replace the cards_auth_token cookie with its value from the first instance, it will not crash when you refresh the page.

This code is technically backwards compatible with running instances of Cards, retaining the ability to decode tokens under the previous encryption scheme. However, it will no longer mint new Tokens using the old symmetric key.

Future work

  • Automatically providing/downloading peer tokens given just their URL is a feature that is enabled in CanDIG via the OIDC protocol, but I haven't implemented it here. Normally this involves Keycloak providing an OIDC endpoint for us to read all the public key, etc for.
  • Dev-only endpoint for minting tokens? I should probably have a dev endpoint just to mint/test the JWTs rather than co-opting the Survey link.

@OrdiNeu
OrdiNeu force-pushed the ia45/foreign-jwt-auth branch from 4b9f4ea to 6728389 Compare July 13, 2026 16:38
@OrdiNeu
OrdiNeu force-pushed the ia45/foreign-jwt-auth branch from 6728389 to 62b1160 Compare July 13, 2026 16:42
Apply code review changes by Claude
@OrdiNeu
OrdiNeu marked this pull request as ready for review July 13, 2026 17:55
@OrdiNeu

OrdiNeu commented Aug 13, 2026

Copy link
Copy Markdown
Member Author

Closed as it's been moved to IAP (see data-team-uhn/iap#40 )

@OrdiNeu OrdiNeu closed this Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant