Skip to content

Instantly share code, notes, and snippets.

@melvincarvalho
Last active January 1, 2026 14:22
Show Gist options
  • Select an option

  • Save melvincarvalho/330aa9badec4b3f3bd4b742811ef36f6 to your computer and use it in GitHub Desktop.

Select an option

Save melvincarvalho/330aa9badec4b3f3bd4b742811ef36f6 to your computer and use it in GitHub Desktop.
Git with Nostr Authentication on JSS

Git with Nostr Authentication on JSS

Use git to clone and push to a JavaScript Solid Server (JSS) pod with Nostr NIP-98 authentication.

Prerequisites

  • Node.js 18+
  • JSS server running with --git flag (or "git": true in config)
  • Git installed

Quick Start

1. Install the credential helper

npm install -g git-credential-nostr

2. Generate a Nostr keypair

git-credential-nostr generate

This outputs:

Generated new Nostr keypair:

  Private key: <64-char-hex>
  Public key:  <64-char-hex>
  WebID:       did:nostr:<pubkey>

Setup:
  git config --global nostr.privkey <privkey>

Save the private key - you'll need it for pushing.

Creating a New Repo

Step 1: Initialize the repo on the server

# On the server (or via sshfs mount)
mkdir -p /path/to/pod/public/myrepo
cd /path/to/pod/public/myrepo
git init
git config receive.denyCurrentBranch ignore  # Required for non-bare repos

Step 2: Set your Nostr private key

git config nostr.privkey <your-64-char-hex-privkey>

Step 3: Create the ACL

Create a .acl file with your Nostr identity and public read access:

git-credential-nostr acl > .acl

Then edit .acl to add public read access. The file should look like:

{
  "@context": {
    "acl": "http://www.w3.org/ns/auth/acl#",
    "foaf": "http://xmlns.com/foaf/0.1/"
  },
  "@graph": [
    {
      "@id": "#owner",
      "@type": "acl:Authorization",
      "acl:agent": { "@id": "did:nostr:<your-pubkey>" },
      "acl:accessTo": { "@id": "./" },
      "acl:default": { "@id": "./" },
      "acl:mode": [
        { "@id": "acl:Read" },
        { "@id": "acl:Write" },
        { "@id": "acl:Control" }
      ]
    },
    {
      "@id": "#public",
      "@type": "acl:Authorization",
      "acl:agentClass": { "@id": "foaf:Agent" },
      "acl:accessTo": { "@id": "./" },
      "acl:default": { "@id": "./" },
      "acl:mode": [
        { "@id": "acl:Read" }
      ]
    }
  ]
}

Note: The ACL uses relative URLs (./) which JSS resolves correctly.

Step 4: Add initial content and commit

echo "# My Project" > README.md
git add -A
git commit -m "Initial commit"

Cloning and Pushing

Clone (public read - no auth needed)

git clone https://example.com/yourpod/public/myrepo
cd myrepo

Configure credentials for push

git config nostr.privkey <your-64-char-hex-privkey>
git config credential.helper nostr

Push changes

echo "Update" >> README.md
git add .
git commit -m "Update README"
git push

Git automatically uses your Nostr key to authenticate via NIP-98.

How It Works

┌─────────────┐     ┌──────────────────────┐     ┌─────────────┐
│   Git       │────▶│ git-credential-nostr │────▶│    JSS      │
│   Client    │     │                      │     │   Server    │
└─────────────┘     └──────────────────────┘     └─────────────┘
                              │                         │
                    Creates NIP-98 token        Verifies signature
                    signed with privkey         Extracts did:nostr:
                              │                         │
                              └─────── Basic Auth ──────┘
                                  username: nostr
                                  password: <base64-token>
  1. Git requests credentials from git-credential-nostr
  2. The helper creates a NIP-98 HTTP Auth event (kind 27235) signed with your Nostr key
  3. The token is sent as Basic Auth password
  4. JSS verifies the Schnorr signature and extracts your pubkey
  5. Your WebID did:nostr:<pubkey> is checked against the ACL

Configuration Options

# Set private key globally
git config --global nostr.privkey <key>

# Set private key per-repo (recommended)
git config nostr.privkey <key>

# Use a keyfile instead
git config nostr.keyfile ~/.nostr/privkey

# Restrict to specific hosts
git config nostr.hosts "solid.social example.com"

Troubleshooting

Push rejected with 403

  • Check that your did:nostr:<pubkey> is in the .acl file
  • Verify the private key matches the public key in the ACL
  • Ensure acl:Write mode is granted

Clone fails with 401/403

  • Add public read access to the ACL (see Step 3)
  • Check that .acl file exists and is valid JSON-LD

Push rejected: "deny updating current branch"

  • Run git config receive.denyCurrentBranch ignore in the server repo

Links

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment