{"id":50464322,"url":"https://github.com/vishvish/pgjwt","last_synced_at":"2026-06-01T06:30:32.488Z","repository":{"id":320786900,"uuid":"1083336747","full_name":"vishvish/pgjwt","owner":"vishvish","description":"Modern JWT (JSON Web Tokens) implementation for Postgres that can handle Ed25519","archived":false,"fork":false,"pushed_at":"2026-05-30T15:15:00.000Z","size":97,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-30T17:08:19.529Z","etag":null,"topics":["jwt","jwt-validation","postgresql","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vishvish.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-25T20:09:28.000Z","updated_at":"2026-05-30T15:15:54.000Z","dependencies_parsed_at":"2025-10-25T22:25:44.286Z","dependency_job_id":null,"html_url":"https://github.com/vishvish/pgjwt","commit_stats":null,"previous_names":["vishvish/pgjwt_rs","vishvish/pgjwt"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/vishvish/pgjwt","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vishvish%2Fpgjwt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vishvish%2Fpgjwt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vishvish%2Fpgjwt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vishvish%2Fpgjwt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vishvish","download_url":"https://codeload.github.com/vishvish/pgjwt/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vishvish%2Fpgjwt/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33763647,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-01T02:00:06.963Z","response_time":115,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["jwt","jwt-validation","postgresql","rust"],"created_at":"2026-06-01T06:30:31.846Z","updated_at":"2026-06-01T06:30:32.476Z","avatar_url":"https://github.com/vishvish.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pgjwt\n\n[![CI](https://github.com/vishvish/pgjwt_rs/actions/workflows/tests.yml/badge.svg)](https://github.com/vishvish/pgjwt_rs/actions/workflows/tests.yml)\n\nPostgreSQL extension for JWT verification with RS256 and Ed25519 support.\n\n## Overview\n\nThis extension provides cryptographically secure JWT validation at the database layer using the Rust `jsonwebtoken` crate. Unlike the pure-SQL `pgjwt` extension which only supports HMAC algorithms, `pgjwt_rs` supports asymmetric key algorithms:\n\n- **RS256** (RSA with SHA-256)\n- **Ed25519** (EdDSA)\n\n## Why This Extension?\n\n### The Problem\nThe popular `pgjwt` extension only supports HMAC-based JWT validation (HS256/384/512), which requires sharing secret keys between services. This is insecure for multi-service architectures because:\n- Any service with the shared secret can forge tokens for other services\n- Compromising one service compromises all services\n- No way to cryptographically prove token origin\n\n### The Solution\nAsymmetric key cryptography with `pgjwt_rs`:\n- Each service has a unique private key (never shared)\n- Database stores only public keys\n- Services sign JWTs with their private key\n- Database verifies signatures with public keys\n- **Mathematically impossible** to forge tokens without the private key\n\n## Functions\n\n### `jwt_decode_payload(token TEXT) -\u003e JSONB`\nExtract the payload from a JWT without verification. Useful for getting the issuer to look up the correct public key.\n\n```sql\nSELECT jwt_decode_payload('eyJhbGc...');\n-- Returns: {\"iss\": \"auth_guard\", \"sub\": \"...\", ...}\n```\n\n### `jwt_verify_rs256(token TEXT, public_key TEXT) -\u003e TABLE(header JSONB, payload JSONB, valid BOOLEAN)`\nVerify a JWT token using RS256 algorithm.\n\n```sql\nSELECT * FROM jwt_verify_rs256(\n    'eyJhbGciOiJSUzI1NiI...',\n    '-----BEGIN PUBLIC KEY-----\n    MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...\n    -----END PUBLIC KEY-----'\n);\n```\n\n### `jwt_verify_ed25519(token TEXT, public_key TEXT) -\u003e TABLE(header JSONB, payload JSONB, valid BOOLEAN)`\nVerify a JWT token using Ed25519 algorithm.\n\n```sql\nSELECT * FROM jwt_verify_ed25519(\n    'eyJhbGciOiJFZERTQSI...',\n    '-----BEGIN PUBLIC KEY-----\n    MCowBQYDK2VwAyEAGb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuE=\n    -----END PUBLIC KEY-----'\n);\n```\n\n### `jwt_verify(token TEXT, public_key TEXT, algorithm TEXT) -\u003e TABLE(header JSONB, payload JSONB, valid BOOLEAN)`\nVerify a JWT token with the specified algorithm ('RS256' or 'EdDSA').\n\n```sql\nSELECT * FROM jwt_verify(\n    'eyJhbGc...',\n    '-----BEGIN PUBLIC KEY-----...',\n    'RS256'\n);\n```\n\n## Installation\n\n### Prerequisites\n- Rust toolchain (1.70+)\n- PostgreSQL 18 (or 13-17 with appropriate feature flags)\n- PostgreSQL development headers (`postgresql-server-dev` on Debian/Ubuntu, `postgresql-devel` on RHEL)\n- `cargo-pgrx` version 0.16.1\n\n### Build and Install\n\nThere are three supported ways to build + package the extension:\n\n1. **Docker-based build (recommended)** — produces a fully packaged `pkg/` directory without needing local Postgres dev packages.\n2. **Local `package.sh` build** — requires Postgres dev headers installed locally.\n3. **Manual Rust build** — for advanced users who want to run `cargo build` directly.\n\n#### 1) Docker build (recommended)\n\nThis repository includes a helper script that builds the extension in a container and extracts the resulting `pkg/` output.\n\n```bash\n# Build and extract artifacts into ./out/pkg\n./build.sh\n\n# If you want to customize the image tag or output directory:\n# ./build.sh mytag my-output-dir\n```\n\nThe resulting files will be in `out/pkg/usr/lib/postgresql/` and `out/pkg/usr/share/postgresql/extension/`.\n\n#### 2) Local package.sh build (requires Postgres dev headers)\n\n```bash\n# Install cargo-pgrx (matching pgrx version)\ncargo install --locked cargo-pgrx --version 0.17.0\n\n# Initialize pgrx for PostgreSQL 18 (one-time setup)\ncargo pgrx init --pg18 $(which pg_config)\n\n# Build and package the extension\nchmod +x package.sh\n./package.sh\n```\n\n#### 3) Install into a running PostgreSQL instance\n\n```bash\nsudo cp pkg/usr/lib/postgresql/pgjwt_rs.so $(pg_config --pkglibdir)/\nsudo cp pkg/usr/share/postgresql/extension/* $(pg_config --sharedir)/extension/\n```\n\nOn macOS, the library extension will be `.dylib` instead of `.so`.\n\n### Cutting a Release\n\nThis repository publishes release artifacts when you push a version tag. Steps:\n\n1. Bump the version in `Cargo.toml`.\n2. Commit and push.\n3. Create and push a tag matching the version, e.g. `v0.1.0`.\n\nThe CI release workflow will build the extension and attach a tarball to the GitHub Release.\n\n### Enable in Database\n\n```sql\nCREATE EXTENSION pgjwt_rs;\n```\n\n## Usage Example\n\n```sql\n-- Create a function to validate service JWTs\nCREATE OR REPLACE FUNCTION validate_service_jwt(token TEXT)\nRETURNS TABLE(\n    service_name TEXT,\n    tenant_id UUID,\n    scopes TEXT[],\n    valid BOOLEAN\n) AS $$\nDECLARE\n    payload JSONB;\n    jwt_result RECORD;\n    public_key_pem TEXT;\n    algorithm TEXT;\nBEGIN\n    -- Get unverified payload to find issuer\n    payload := jwt_decode_payload(token);\n    \n    -- Look up public key for the claimed service\n    SELECT pk.public_key, pk.algorithm \n    INTO public_key_pem, algorithm\n    FROM auth_schema.jwt_keys pk\n    WHERE pk.service_name = payload-\u003e\u003e'iss'\n      AND pk.is_active = true;\n    \n    IF public_key_pem IS NULL THEN\n        RETURN QUERY SELECT NULL::TEXT, NULL::UUID, NULL::TEXT[], FALSE;\n        RETURN;\n    END IF;\n    \n    -- Verify JWT with correct algorithm\n    SELECT * INTO jwt_result \n    FROM jwt_verify(token, public_key_pem, algorithm);\n    \n    IF jwt_result.valid THEN\n        payload := jwt_result.payload;\n        RETURN QUERY SELECT \n            (payload-\u003e\u003e'iss')::TEXT,\n            (payload-\u003e\u003e'tenant_id')::UUID,\n            ARRAY(SELECT jsonb_array_elements_text(payload-\u003e'scopes')),\n            TRUE;\n    ELSE\n        RETURN QUERY SELECT NULL::TEXT, NULL::UUID, NULL::TEXT[], FALSE;\n    END IF;\nEND;\n$$ LANGUAGE plpgsql SECURITY DEFINER;\n```\n\n## Security Features\n\n- **Signature Verification**: Always validates cryptographic signatures\n- **Algorithm Enforcement**: Explicitly specify which algorithm to use\n- **Public Key Validation**: Validates PEM format before use\n- **Error Handling**: Safe error messages, no key material leaks\n- **Memory Safety**: Built with Rust's memory safety guarantees\n\n## Security posture\n\n- **No unsafe code**: The crate avoids `unsafe` blocks unless explicitly justified and reviewed.\n- **Secret handling**: JWT keys and tokens are never logged or exposed in error messages.\n- **CI gating**: GitHub Actions validate formatting, linting, tests, dependency advisories, and license policy.\n- **Supply-chain checks**: Run `cargo audit` and `cargo deny check advisories licenses bans sources` locally before merging.\n\n### Validation behavior\n\nThis extension focuses on cryptographic verification and intentionally defers claim validation to SQL so you can express policy close to data:\n\n- Signature validation is always enforced.\n- The default required JWT spec claims (like `exp`) are not enforced by the extension. Tokens without `exp` will be accepted at the cryptographic level.\n- `exp`, `nbf`, and `aud` checks are disabled in Rust and can be applied in SQL, e.g. by checking `now() \u003c to_timestamp((payload-\u003e\u003e'exp')::bigint)` if present.\n\nRationale: application-specific TTLs, audiences, and clock tolerance are often best handled in database logic or service code rather than hard-coded in the extension.\n\n## Performance\n\nBuilt with Rust and compiled to native code, `pgjwt_rs` provides:\n- Fast signature verification (native crypto operations)\n- Minimal overhead compared to SQL-only solutions\n- Efficient JSONB handling\n\n## Development\n\n### Running Tests (Docker — recommended)\n\nNo local PostgreSQL installation needed:\n\n```bash\n./docker-test.sh          # fmt + clippy + unit tests\n./docker-test.sh build    # … then package the extension\n```\n\n### Running Tests (locally)\n\nRequires a local PostgreSQL installation and `cargo-pgrx` initialised.\n\nFirst, generate PKCS#8 test key pairs:\n\n```bash\n# Generate RS256 test keys (PKCS#8 for ring)\nopenssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out test_private.pem\nopenssl pkey -in test_private.pem -pubout -out test_public.pem\n\n# Generate Ed25519 test keys\nopenssl genpkey -algorithm ed25519 -out test_ed25519_private.pem\nopenssl pkey -in test_ed25519_private.pem -pubout -out test_ed25519_public.pem\n```\n\nThen run tests:\n\n```bash\n# Run Rust unit tests (with coverage)\ncargo install cargo-llvm-cov\ncargo llvm-cov --html\n\n# Run PostgreSQL integration tests\ncargo pgrx test pg18\n```\n\n### Building for Development\n\n```bash\n# Run with test database (opens psql with extension loaded)\ncargo pgrx run pg18\n\n# Build for specific PostgreSQL version\ncargo build --release --features pg18 --no-default-features\n```\n\n## License\n\nMIT - see LICENSE file for details.\n\n## Credits\n\nBuilt with:\n- [pgrx](https://github.com/pgcentralfoundation/pgrx) - Rust framework for PostgreSQL extensions\n- [jsonwebtoken](https://github.com/Keats/jsonwebtoken) - JWT encoding/decoding for Rust\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvishvish%2Fpgjwt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvishvish%2Fpgjwt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvishvish%2Fpgjwt/lists"}