Papra

Privacy

Last updated August 20, 2026.

What this signing app does with your personal data. It does not cover the Papra application itself. Who publishes and who hosts the site is set out on the legal notice.

Who is responsible

Corentin Thomasset, maintainer of the Papra project, decides what is collected here and why, and is the data controller for everything described below. The postal address and registration number are on the legal notice; the quickest way to reach him is cla@papra.app.

Authentication

You sign in with GitHub, and only with GitHub. We ask for a single permission, user:email, which lets us read your account and your email addresses, nothing else. We cannot see your repositories, or any other private information, and we cannot act on your behalf.

When you come back from GitHub, we exchange the one-time code for an access token, make two calls with it (/user and /user/emails), and then throw it away. The token is never written to the database, to a cookie, or to the logs: it exists for the length of those two calls and is gone before the page you land on is rendered.

Out of your GitHub account we keep your user id, your username, and your verified primary email address. If your primary address is not verified, we stop there and cannot record a signature: an agreement signed with an address you have not proven you control would be worthless.

These three values live in a session on our server for twenty-four hours, or until you sign out. The cla_session cookie in your browser holds nothing but an opaque identifier pointing at it. It is the only cookie this app sets, it exists so that you stay signed in between the GitHub redirect and the moment you sign, and there is no analytics, no advertising, and no third-party script anywhere on the site.

What the form asks for

The agreement is a contract governed by French law, and it names you as one of its two parties. A contract that cannot identify the person bound by it is worth little, so the form asks for the details needed to identify you while avoiding information it can do without:

  • your full name - you sign in your own name, as it appears on your identity document;
  • your date and place of birth - they tell two people of the same name apart, and the date is also what shows whether you are a minor, which section 4 of the agreement makes a condition of accepting it;
  • which contributions the signature covers - picked from your own pull requests, which we list from GitHub rather than ask you to type out.

Your authenticated GitHub account and verified email provide additional identification. We do not ask for your postal address. Although having it could make a formal notification or a legal dispute easier in practice, it is not mandatory while the signer remains identifiable, and we have chosen not to collect it.

What we store

Signing produces one record, covering the contributions you selected when you signed:

  • your GitHub user id, which unlike a username cannot be renamed or re-claimed, and the username you had at the moment you signed;
  • the identity you entered: full name, date and place of birth;
  • your verified GitHub email address;
  • the version of the agreement you accepted;
  • the date and time you signed;
  • where the PDF is stored, and its SHA-256, so the file can later be shown to be unaltered.

Alongside it, one line per contribution the signature covers: the repository and its GitHub id, the pull request number and title, and when it was opened. All of that is already public on GitHub. It is copied here because Appendix 1 of the agreement has to say precisely which contributions were licensed, and a link to a pull request is not proof of what it said.

Your IP address, your user agent, and anything about how you reached the site are never recorded. The signature is already tied to an authenticated GitHub account with a verified email, which says more than an IP address would.

The signed copy

The record above is rendered onto the text of the agreement as a PDF: your identity in the parties block, your contributions in Appendix 1, the date at the end. That file is stored in Cloudflare R2, and you can download it as soon as you have signed, so that both parties hold the same document.

Agreements signed under version 1.0 asked for and include the postal address supplied at the time. Those historical PDFs remain exactly as signed. The standalone address values formerly kept in the database have been deleted.

The same PDF is then emailed to your verified GitHub address, with Papra in copy, so that neither side depends on this site to hold on to it. The message itself names only your GitHub username, the version you signed, the contributions it covers, the reference of the signature and the SHA-256 of the attached file, so that you hold the fingerprint our copy has to match; the identity you entered is in the attachment, which is the document, and nowhere in the text.

The download link only answers to the GitHub account the signature belongs to, and asking for somebody else’s gets the same “not found” as asking for one that does not exist.

The CLA check

The bot watches the repositories listed in the project’s configuration. GitHub sends it pull request events, each one signature-verified before anything reads it, and it looks at the pull request’s commits to work out which GitHub accounts contributed and whether each of them has signed for that pull request. It matches on GitHub user id, never on email, because the address configured in a git client routinely differs from the account it belongs to. The result is a pass or fail check on the pull request, and nothing from the payload is kept beyond the contribution lines described above and the working note in the next paragraph.

Reading a pull request’s commits is the slow part, and the answer only changes when the pull request does, so the bot keeps a note of what it worked out: which accounts contributed, and any commit address it has still to match to an account. The note is filed under the exact commit it was worked out from, so a new commit is always read afresh, and it is thrown away about a month later. It exists so that a page listing your pull requests does not re-read every one of them on every visit.

While the check fails, the bot also posts a comment on the pull request naming the GitHub accounts that have yet to sign for it, so that contributors and reviewers can see what the pull request is waiting on. It names accounts by their login, and nothing more of you than that: no email address, no legal identity, none of what the agreement itself collects.

Where a commit is authored with an address that belongs to no GitHub account, the bot cannot tell whose it is, so it reports that commit by its identifier and asks for the address to be added to an account. It does not print the address, on the pull request or anywhere else: an address put in a git configuration was not put on a public page, and the commit identifier is enough to act on.

There is one such comment per pull request, edited in place as signatures land and rewritten rather than deleted once the check passes, so the thread keeps a record of what was asked for.

Logs

Requests are logged while they are served - method, path, status and duration - so that failures can be diagnosed. Two moments log a little more: signing in records your GitHub user id, and recording a signature logs that id along with the version signed and the time. Webhook deliveries log GitHub’s delivery id and the event type. Sending the confirmation logs the reference of the signature and whether it was accepted, never the recipient email. No log line ever carries what you typed into the form, the PDF, or the access token.

Why we are allowed to hold it

Collecting your identity, checking the contributions are yours and issuing the PDF are how the agreement gets concluded and performed, which is the basis in article 6(1)(b) of the GDPR. Keeping the record afterwards rests on our legitimate interest in being able to prove who licensed what and when, article 6(1)(f), which is also what section 13 of the agreement says. That proof is the entire point of the record: a licence granted for the duration of the copyright is only worth what remains provable about it.

None of it is used for anything else. It is not sold, not shared with anyone for their own purposes, and not used to profile you. The CLA check is automatic, but all it reports is whether a signature exists; it forms no judgement about you.

Where it is stored

The app runs on Cloudflare Workers. Signatures are kept in a Cloudflare D1 database and the PDFs in a Cloudflare R2 bucket, both created in Cloudflare’s European Union jurisdiction, so those rows and those files stay on servers in the EU.

Sessions are kept in Cloudflare KV, which replicates globally. For the twenty-four hours a session lives, the username and email it holds may sit on servers outside the EU. The check’s working note is kept in the same store, so an address it has yet to match to an account may sit there too, for the month that note lives. Signatures and signed copies never do.

The confirmation email carries a copy of the PDF out to a third company, so that claim only holds because that company is European too: Lettermint is Dutch and runs its sending, its backups and its deliverability monitoring on infrastructure in the Netherlands and Germany. Once it leaves them, the message is in your mailbox, with whoever provides it.

Who else touches it

Three companies process this data on our behalf, each under its own terms and none of them free to use it for anything else:

  • Cloudflare hosts the site and holds the database, the sessions, the check’s working notes and the PDFs;
  • GitHub identifies you, and is where the contributions and the check live;
  • Lettermint delivers the confirmation email and the copy of the agreement attached to it.

Cloudflare and GitHub are US companies. Where data reaches them outside the EU, the transfer rests on the European Commission’s standard contractual clauses in their data processing terms. Lettermint is a Dutch company and keeps the sending in Europe. No one else receives any of this.

Who can see it

The maintainer of the Papra project, to check that a contribution is covered by a signature.

In practice the fact that you have signed is public anyway: the check on your pull request says so to anyone looking. The record itself, and everything you typed into the form, is not. It may be produced as evidence where disclosure is required, in a legal dispute for instance.

How long we keep it

Signatures and their PDFs are kept for as long as the project includes the contributions they cover, and after that for as long as we may need them to establish, exercise or defend a legal claim relating to those contributions. In practice that means indefinitely.

Sessions expire twenty-four hours after you sign in, and are deleted the moment you sign out. The check’s working notes expire by themselves about a month after they are written, and are never read again once the pull request they describe has moved on. Request logs are kept for Cloudflare’s Workers Logs retention window, a few days, then dropped for good. Nothing else is kept.

Your rights

The GDPR gives you the right to ask what we hold about you, to have it corrected, to have it erased, to have its use restricted, to object to that use, and to receive a copy in a portable form. Write to cla@papra.app and you will get an answer.

Two honest limits. A mistake in your name or date of birth will always be corrected, but erasing a signature outright is something we may have to refuse for as long as the record is needed to defend a legal claim, which article 17(3)(e) allows. And the name and email address configured in your git client are recorded in the project’s public git history, which is not this app’s to rewrite.

If you are unhappy with how we handle any of this, you can complain to your data protection authority - in France, the CNIL.

Changes

If what we collect or why changes, this page changes with it and the date at the top moves.