-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add schema version to issued manifests
This will make it easier to detect incompatible versions in the future.
- Loading branch information
Showing
5 changed files
with
178 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
--- | ||
layout: default | ||
title: 2.0.0-rc.2 | ||
parent: Manifest Spec | ||
--- | ||
<!-- #content --> | ||
# SponsorLink Version 2.0.0 | ||
|
||
## Overview | ||
|
||
A sponsor manifest is a JWT (JSON Web Token) that encapsulates a user' sponsorship relationship | ||
with another user or organization (the "sponsorable"). This manifest is issued and signed by the | ||
sponsorable (or the sponsorship platform, if supported). There are no third-party intermediaries | ||
between the sponsorable (or sponsorship platform) and the sponsor. | ||
|
||
The sponsor manifest can be utilized to enable features exclusive to sponsors or to suppress requests | ||
for sponsorships by the author's code. | ||
|
||
During regular usage of a SponsorLink-enabled tool or library, the author might perform an offline | ||
check to verify the user's sponsorship status before enabling a feature or suppressing build warnings. | ||
|
||
This check is performed by reading the manifest from a well-known location in the user's environment | ||
and verifying its contents and signature. | ||
|
||
Users can subsequently request a manifest to the backend issuer service provided by the author so | ||
that subsequent checks can succeed, as well as renew/sync the manifest if it has expired. | ||
|
||
## Purpose | ||
|
||
Establishing a standard method to represent and verify sponsorships in a secure, offline, and | ||
privacy-conscious manner would be advantageous for both open-source software (OSS) authors and users. | ||
|
||
## Terminology | ||
|
||
The term "sponsor" refers to the user or organization that is providing financial support | ||
to another user or organization. | ||
|
||
The term "sponsorable" refers to the user or organization that is receiving financial | ||
support from another user or organization. | ||
|
||
## Sponsorable Manifest | ||
|
||
A sponsorable user or organization can make its support for SponsorLink known by providing | ||
a manifest in JWT (JSON Web Token) format containing the following claims: | ||
|
||
| Claim | Description | | ||
| ----------- | ----------- | | ||
| `iss` | [Standard claim](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.1) containing the URL of the backend that issues sponsor manifests | | ||
| `aud` | [Standard claim](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.3) containing one or more URLs of the supported sponsoring platforms | | ||
| `iat` | [Standard claim](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.6) containing the time the manifest was issued at | | ||
| `sub_jwk` | [Standard claim](https://openid.net/specs/openid-connect-core-1_0.html#SelfIssuedResponse) containing the public key (JWK) that can be used to check the signature of issued sponsor manifests | | ||
| `schema` | Optional schema version of the manifest. Defaults to 2.0.0 | | ||
|
||
This manifest can be discovered automatically by tools that provide sponsor manifest synchronization | ||
and verification. | ||
|
||
{: .note } | ||
> By convention, issuers should provide an endpoint at `[iss]/jwt` that returns the sponsorable manifest. | ||
The following is an example of a sponsorable manifest: | ||
|
||
```json | ||
{ | ||
"iss": "https://sponsorlink.devlooped.com/", | ||
"aud": "https://github.com/sponsors/devlooped", | ||
"iat": 1696118400, | ||
"sub_jwk": { | ||
"e": "AQAB", | ||
"kty": "RSA", | ||
"n": "5inhv8Q..." | ||
} | ||
} | ||
``` | ||
|
||
## Sponsor Manifest | ||
|
||
The sponsor manifest is used to verify the sponsor's sponsorship status. It's a signed JWT | ||
that the sponsorable issuer provides to the sponsor, containing the following claims: | ||
|
||
| Claim | Description | | ||
| ----------- | ----------- | | ||
| `iss` | The token [issuer](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.1), matching the sponsorable manifest issuer claim | | ||
| `aud` | The [audience](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.3) URL(s) from the sponsorable manifest | | ||
| `iat` | The [time the manifest was issued at](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.6) | | ||
| `sub` | The [subject](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.2) claim, which is the sponsor account (i.e. user GitHub login) | | ||
| `roles` | The sponsoring [roles](https://www.rfc-editor.org/rfc/rfc9068.html#section-7.2.1.1) of the authenticated user (e.g. team, org, user, contrib) | | ||
| `email` | The sponsor's email(s) [standard claim](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims) | | ||
| `exp` | The token's [expiration date](https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.4) | | ||
| `schema` | Optional schema version of the manifest. Defaults to 2.0.0 | | ||
|
||
{: .note } | ||
> Tools can fetch the sponsorable manifest from `[iss]/jwt` for verification of the sponsor manifest signature. | ||
The [roles](https://www.rfc-editor.org/rfc/rfc9068.html#section-7.2.1.1) claim can be used to distinguish | ||
between different types of sponsorships. | ||
|
||
* `user`: The sponsor is personally sponsoring. | ||
* `org`: The user belongs to at least one organization that is sponsoring. | ||
* `contrib`: The user is a contributor and is therefore considered a sponsor. | ||
* `team`: The user is a member of the sponsorable organization or is the sponsorable user. | ||
|
||
For example, given: | ||
|
||
- An organization `acme` that is sponsoring another organization `devlooped`. | ||
- A user `alice` who is a member of the organization `acme`. | ||
- `alice` requests from `devlooped` a sponsor manifest to access a feature. | ||
|
||
The issuer provided by `devlooped` would return a signed sponsor manifest token containing the following claims: | ||
|
||
```json | ||
{ | ||
"iss": "https://sponsorlink.devlooped.com", | ||
"aud": "https://github.com/sponsors/devlooped", | ||
"sub": "alice", | ||
"email": [ | ||
"[email protected]", | ||
"[email protected]" | ||
], | ||
"roles": "org", | ||
"exp": 1696118400, | ||
"schema": "2.0.0" | ||
} | ||
``` | ||
|
||
### Token Signing | ||
|
||
The issuing backend provided by the sponsorable signs the sponsor JWT using a private key. The | ||
corresponding public key (available publicly in the sponsorable manifest itself) can be used by | ||
the author's libraries and tools to verify the manifest's signature and expiration date. | ||
|
||
## Manifest Usage | ||
|
||
Various sponsorship platforms can provide reference implementations of the backend service to issue | ||
SponsorLink manifests using their platform's APIs. For example, GitHub, Open Collective, and Patreon | ||
could all provide such services. Either for self-hosting by authors or as a managed service. | ||
|
||
A client-side tool would be provided for users to synchronize their SponsorLink manifest(s) with the | ||
backend service. This tool would typically require the user to authenticate with the platform and | ||
authorize the backend service to access their sponsorship information. This step would be explicit | ||
and require the user's consent to sharing their sponsorship information. | ||
|
||
{: .important } | ||
> By convention, sponsor manifests are stored at `~/.sponsorlink/[platform]/[sponsorable].jwt`. | ||
The author's code can check for the manifest presence and verify its contents and signature, which | ||
could enable or disable features, suppress build warnings, or provide other benefits to sponsors. | ||
The author can optionally perform a local-only offline check to ensure the user's email address | ||
in the manifest matches the one in his local source repository configuration. | ||
|
||
The author may also choose to verify the token's expiration date, decide on a grace period, and | ||
issue a notification if the manifest is expired. | ||
|
||
{: .note } | ||
> See the [GitHub implementation](github.md) of SponsorLink for more information. | ||
## Privacy Considerations | ||
|
||
* The method of user identification for manifest generation is entirely determined by the issuer. | ||
* The method of user identification for manifest consumption is left to the discretion of the tool | ||
or library author. | ||
|
||
Once a manifest is generated in a user-explicit manner and with their consent, and stored in their | ||
local environment, it can be utilized by any tool or library to locally verify sponsorships without | ||
any further network access. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters