UNPKG

@authcube/pst

Version:

Typescript library implementing Private State Token API (https://wicg.github.io/trust-token-api/)

153 lines (110 loc) 4.67 kB
# Private State Tokens Typescript library implementing Private State Token API (https://wicg.github.io/trust-token-api/) This library depends on [Cloudflare's voprf-ts](https://github.com/cloudflare/voprf-ts) tested implementation to compute the Scalars and transformations. # Security Disclaimer 🚨 This library is offered as-is, and without a guarantee. Therefore, it is expected that changes in the code, repository, and API occur in the future. We recommend to take caution before using this library in a production application since part of its content is experimental. All security issues must be reported, please notify us immediately. ## Install Dependencies and Build ``` npm install npm run build ``` ## Sample Issuer > Sample has been built using Express Library - Start Sample Server ``` npm run example ``` - Running with Docker - build ``` docker-compose build ``` - start ``` docker-compose up ``` #### Running with Static Key-Pair and Expiration - Generate up to 6 KeyPairs ``` node bin/voprf_gen_keys.cjs 1 node bin/voprf_gen_keys.cjs 2 # Keep creating until node bin/voprf_gen_keys.cjs 6 ``` - Export Keys as Environment Variables ``` export PRIVATE_KEY1=<BASE64 PRIVATE KEY 1 GENERATED PREVIOUSLY> export PUBLIC_KEY1=<BASE64 PUBLIC KEY 1 GENERATED PREVIOUSLY> export PRIVATE_KEY2=<BASE64 PRIVATE KEY 2 GENERATED PREVIOUSLY> export PUBLIC_KEY2=<BASE64 PUBLIC KEY 2 GENERATED PREVIOUSLY> # Keep defining until PRIVATE_KEY6 and PUBLIC_KEY6 ``` - Export Key Expiration as Environment Variable ``` export EXPIRY1=1709509052048 export EXPIRY2=1709994102048 # Keep defining until EXPIRY6 ``` > If running with **Docker** define those variables in docker-compose.yaml or -e argument for docker inline ### Endpoints - Key Commitment Endpoint ``` curl http://localhost:3000/.well-known/trust-token/key-commitment ``` ## Resources, Libraries and Specs: - [Google Privacy Sandbox - Private State Tokens](https://developers.google.com/privacy-sandbox/protections/private-state-tokens) - [Private State Tokens API Spec](https://wicg.github.io/trust-token-api/) - [Privacy Pass Issuance Protocol Spec](https://www.ietf.org/archive/id/draft-ietf-privacypass-protocol-10.html) - [Oblivious Pseudorandom Functions (OPRFs) Spec](https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-21.html) - [Batched Tokens Issuance Protocol Spec](https://www.ietf.org/archive/id/draft-robert-privacypass-batched-tokens-01.html) - [CloudFlare - Privacy Pass TypeScript Library](https://github.com/cloudflare/privacypass-ts/) - [CloudFlare - VOPRF TypeScript Library](https://github.com/cloudflare/voprf-ts) ## How to use this library ### Token Issuance To issue a token, you must check for the request header `sec-private-state-token`, after verify it is present and it is not null or empty you can use the Issuer class like the code bellow: ```typescript import { PSTRedeemer, PSTResources } from "@authcube/pst"; const sec_private_state_token = req.headers[ "sec-private-state-token" ] as string; if (sec_private_state_token && !sec_private_state_token.match(BASE64FORMAT)) { return res.sendStatus(400); } try { let issuer = await PSTResources.getIssuer(); const token = await issuer.issueToken(sec_private_state_token); res.statusCode = 200; res.setHeader("Content-Type", "text/html"); res.append("sec-private-state-token", token); res.setHeader("Sec-Private-State-Token", token); res.write("Issuing tokens."); res.send(); return res.end(); } catch (e: any) { // deal with the error as you see fit console.error("Error issuing PST", e); return res.sendStatus(500); } ``` ### Token Redeemption To redeem an issued token the process is similar, your endpoint must check for the request header `sec-private-state-token`, if it is present and it is not null or empty you can proceed to the redeemption ```typescript import { PSTRedeemer, PSTResources } from "@authcube/pst"; try { const redemptionToken = req.headers["sec-private-state-token"] as string; if (redemptionToken && !redemptionToken.match(BASE64FORMAT)) { return res.sendStatus(400); } const redeemer = new PSTRedeemer(); // This call will throw an Error if the token is invalid const resToken = await redeemer.redeemToken(redemptionToken); res.statusCode = 200; res.setHeader("Access-Control-Allow-Origin", "*"); res.append("sec-private-state-token", resToken); res.write("Token redeemed."); return res.send(); } catch (e) { // deal with the error as you see fit console.error(`Error on redemption: ${e}`); return res.sendStatus(400); } ```