Skip to content

DT-2991: GA4GH Passport User Info API#2237

Merged
rushtong merged 46 commits intodevelopfrom
gr-passports
Mar 4, 2026
Merged

DT-2991: GA4GH Passport User Info API#2237
rushtong merged 46 commits intodevelopfrom
gr-passports

Conversation

@rushtong
Copy link
Copy Markdown
Contributor

@rushtong rushtong commented Jan 26, 2024

Addresses

https://broadworkbench.atlassian.net/browse/DT-2991

Summary

This PR represents our first effort to generate a compliant GA4GH passport implementation. This PR implements the following features:

  • Authenticated userinfo endpoint that provides a JSON Passport. This follows the implementation requirements specified in the AAI OpenID spec
  • Passport consisting a list of visas:
    • ControlledAccessGrants Visa per dataset the user has current access to.
    • AffiliationAndRole Visa describing the user's affiliation
    • ResearcherStatus Visa describing the user's status

What this PR does NOT cover

This work should be slated for future implementation efforts.

  • Provide a passport scoped access token
    • Requires an additional scope that we do not currently support: ga4gh_passport_v1
  • Provide a signed JWT
    • Requires public and private keys
  • Complete the currently unimplemented claim types:
    • AcceptedTermsAndPolicies
    • LinkedIdentities
  • ResearcherStatus: We need to provide a URL Claim to describe a researcher

Have you read CONTRIBUTING.md lately? If not, do that first.

  • Label PR with a Jira ticket number and include a link to the ticket
  • Label PR with a security risk modifier [no, low, medium, high]
  • PR describes scope of changes
  • Get a minimum of one thumbs worth of review, preferably two if enough team members are available
  • Get PO sign-off for all non-trivial UI or workflow changes
  • Verify all tests go green
  • Test this change deployed correctly and works on dev environment after deployment

@rushtong rushtong changed the title Gr passports WIP: Passports Jan 26, 2024
@rushtong
Copy link
Copy Markdown
Contributor Author

@dependabot show ignore conditions

@sonarqubecloud

This comment was marked as outdated.

@sonarqubecloud

This comment was marked as outdated.

# Conflicts:
#	src/main/java/org/broadinstitute/consent/http/ConsentApplication.java
@sonarqubecloud

This comment was marked as outdated.

# Conflicts:
#	src/main/java/org/broadinstitute/consent/http/ConsentApplication.java
# Conflicts:
#	src/main/resources/assets/api-docs.yaml
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/main/resources/assets/schemas/VisaClaim.yaml
Comment thread src/main/resources/assets/schemas/VisaClaim.yaml
.map(LibraryCard::getCreateDate)
.orElse(user.getCreateDate());
// GA4GH requires Unix timestamps in seconds; Date#getTime() returns milliseconds.
return assertedDate.getTime() / 1000L;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the tolerance for being off by a second? Technically speaking we could be rounding up. If it's inconsequential, I'm not concerned. If it is, we might want to convert these Date objects to something like Instant and use the built in functions to convert to epoch seconds.

Copy link
Copy Markdown
Contributor Author

@rushtong rushtong Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have a hard requirement for that level of precision. I would be amenable to a more centralized function to ensure we're always following the same pattern.

}

@Override
public Long asserted() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this date represent? How will a consumer use it?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This represents the seconds since the visa assertion is made: https://ga4gh.github.io/data-security/ga4gh-passport#visa-object-claims


protected List<Visa> buildControlledAccessGrants(
String userSubjectId, List<ApprovedDataset> approvedDatasets) {
return approvedDatasets.stream()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to be more selective about the filter here? Don't we want the ApprovedDataset with the longest runway?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. I should sort them by the expiration and then filter out duplicates so we get the ones that extend the furthest into the future.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After digging into this some more, it doesn't matter which of the ApprovedDataset entities we return, only that we return one of them. IOW, if the user has access to two ApprovedDataset objects, one that expires tomorrow, one that expires next year, they have the same underlying dataset identifier.

Copy link
Copy Markdown
Contributor

@otchet-broad otchet-broad Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's true that they'll have the same identifier, but I'm thinking about how we communicate when access to that dataset is no longer authorized. I haven't gotten through enough of the spec yet to see how that unwinds (or if it's even supported). What is clear to me is that the expiration (exp) of the Visa shouldn't be past when the we would remove access (when access is planned to expire or the user's LC is revoked). Fun stuff we'll be able to work through in future PRs. :-)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is clear to me is that the expiration (exp) of the Visa shouldn't be past when the we would remove access (when access is planned to expire or the user's LC is revoked)

Of these two conditions, we have control over the planned expiration, but not future LC revocation. I can see improvements on the expiration front at least.

description: The Issued-At timestamp
exp:
type: number
description: The Expiration timestamp
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might want to be clearer that making an access decision after the exp is reached is unsupported.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ControlledAccessGrants is just one type of visa which is what that language would be applicable to. I think it would be confusing with respect to the other visa types that exist, such as ResearcherStatus or AffiliationAndRole.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ControlledAccessGrants is just one type of visa which is what that language would be applicable to. I think it would be confusing with respect to the other visa types that exist, such as ResearcherStatus or AffiliationAndRole.

I have to correct myself. exp applies equally to all Visas, and in the case of ControlledAccessGrants it does NOT refer to the expiration of the user's access to the dataset. It applies only to the state of the Visa such that the visa will always expire 1 hour from issuance.

@otchet-broad
Copy link
Copy Markdown
Contributor

As I'm coming up to speed on the GA4GH Passport spec, I'm wondering if we should be creating durable logs for every passport we issue so that we can trace (with high fidelity) all of the clients that have requested these objects and know their expiration so that we can:

  1. Inform overseers and data custodians about potential usage in other systems.
  2. Maintain a clear audit trail for issuance.
  3. Monitor for abuse.

@rushtong
Copy link
Copy Markdown
Contributor Author

rushtong commented Mar 3, 2026

As I'm coming up to speed on the GA4GH Passport spec, I'm wondering if we should be creating durable logs for every passport we issue so that we can trace (with high fidelity) all of the clients that have requested these objects and know their expiration so that we can:

  1. Inform overseers and data custodians about potential usage in other systems.
  2. Maintain a clear audit trail for issuance.
  3. Monitor for abuse.

Absolutely, these are great features. There are a number of other things we need to do to be fully compliant as noted in the PR description so I intend that this be iterated upon over time. Currently, there are no clients that will be using this in the near (1-3 month at a minimum) future.

Copy link
Copy Markdown
Contributor

@fboulnois fboulnois left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a first approach, this looks reasonable! 👍

@rushtong rushtong requested a review from otchet-broad March 4, 2026 13:33
@otchet-broad
Copy link
Copy Markdown
Contributor

Thanks for the harmonization around dates. I think that's going to be helpful in the future.

I'm wondering if the resource should be updated so that it's not PermitAll, but rather Admin and maybe Service Account for now. I think there are Expiration and Revocation cases that are important from a compliance standpoint that are missing from this that make me concerned we'll communicate a controlled access grant without having these other mechanisms in place. https://github.com/ga4gh-duri/ga4gh-duri.github.io/blob/master/researcher_ids/ga4gh_passport_v1.md#overview

Would that be an okay next step on this?

@rushtong
Copy link
Copy Markdown
Contributor Author

rushtong commented Mar 4, 2026

Thanks for the harmonization around dates. I think that's going to be helpful in the future.

I'm wondering if the resource should be updated so that it's not PermitAll, but rather Admin and maybe Service Account for now. I think there are Expiration and Revocation cases that are important from a compliance standpoint that are missing from this that make me concerned we'll communicate a controlled access grant without having these other mechanisms in place. https://github.com/ga4gh-duri/ga4gh-duri.github.io/blob/master/researcher_ids/ga4gh_passport_v1.md#overview

Would that be an okay next step on this?

Sure thing. I'd prefer to limit it to Admin for now rather than SA since they are not an intended audience, general researchers are the current target. For comparison, this API is doing essentially the same thing that https://consent.dsde-prod.broadinstitute.org/#/User/get_api_user_me_researcher_datasets does ... retrieving the same entity for an authenticated user. That API is also @PermitAll.

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Mar 4, 2026

Copy link
Copy Markdown
Contributor

@otchet-broad otchet-broad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍
Nice work!

@rushtong rushtong merged commit e02bfa4 into develop Mar 4, 2026
14 checks passed
@rushtong rushtong deleted the gr-passports branch March 4, 2026 15:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants