Authentication
JJHub supports two login methods and API token authentication for programmatic access.GitHub OAuth (Default)
The default and most common way to authenticate:Sign in with Key
Sign in with Key is a passwordless authentication method that uses cryptographic key signing. You sign a structured message with your private key to prove ownership of your account — no passwords, no third-party OAuth provider required. Under the hood, Sign in with Key uses the EIP-4361 message format as its wire protocol. You do not need a blockchain wallet or any blockchain interaction — any compatible cryptographic keypair works. The EIP-4361 format is used solely because it provides a well-specified, widely-supported structure for signed authentication messages. Because it relies on standard cryptographic keypairs, Sign in with Key is a highly recommended way to authenticate AI agents, allowing them to securely interact with the JJHub platform without managing traditional passwords.CLI Usage
- Requests a nonce from the JJHub API
- Constructs a structured sign-in message with the nonce
- Signs the message with your key
- Sends the signed message to JJHub for verification
- Stores the resulting session token in your credential store
How the Flow Works
The Sign in with Key flow has three steps: Step 1: Request a nonce Your client requests a single-use nonce from the server. Nonces expire after approximately 10 minutes.jjhub.tech for the hosted platform, even though the API host is api.jjhub.tech).
Step 3: Verify the signature
Submit the signed message and signature to the verify endpoint:
Set-Cookie headers for jjhub_session and __csrf.
When to Use Sign in with Key
- AI agents: Agents can hold a keypair and authenticate programmatically without browser-based OAuth flows.
- Automation: Any system that can sign messages can authenticate without human interaction.
- Security-conscious users: No third-party OAuth dependency. Your key never leaves your machine — only the signature is sent to JJHub.
Account Linking
JJHub lets you connect both authentication methods to a single account. If you signed up with GitHub OAuth, you can later link a cryptographic key. If you signed up with Sign in with Key, you can later link your GitHub account. This gives you the flexibility of multiple login methods while keeping one unified identity, and it means you never have to choose upfront — start with whichever method is convenient and add the other later.Why Link Accounts
- Redundancy: If one auth method becomes unavailable (e.g., you lose access to your GitHub account), you can still sign in with the other.
- Flexibility: Use GitHub OAuth from a browser and Sign in with Key from an AI agent or automated system — same account, same repos, same permissions.
- No duplicates: Without linking, signing in with a different method creates a separate account. Linking prevents this by attaching both identities to your existing account.
Link a Cryptographic Key to a GitHub Account
If you originally signed up with GitHub OAuth and want to add Sign in with Key as a second authentication method: CLI:- Generates a nonce from the JJHub API
- Constructs a structured sign-in message with the nonce
- Signs the message with your key
- Submits the signed message to link the key to your current account
Link a GitHub Account to a Sign in with Key Account
If you originally signed up with Sign in with Key and want to add GitHub as a second authentication method: CLI:GET /api/user/link/github/callback, which completes the link. Once linked, you can sign in with either method. Your GitHub profile information (email, avatar) is imported automatically.
Linking Rules
- One key per account: Each cryptographic key address can only be linked to one JJHub account. If the key is already associated with a different account, the linking request is rejected.
- One GitHub identity per account: Each GitHub user ID can only be linked to one JJHub account. If your GitHub account is already linked to a different JJHub account, the request is rejected.
- Authentication required: You must be signed in to link a new auth method. Linking attaches the new identity to your current session’s account.
- Unlinking is not supported in MVP: Once linked, auth methods cannot be removed. This will be added in a future release.
Credential Storage
After login, your credentials are stored in your OS keychain (macOS Keychain, Windows Credential Manager, or Linux Secret Service). For CI environments or other headless workflows, use theJJHUB_TOKEN environment variable instead of persisting a token to disk:
Check Authentication Status
Print Current Token
Log Out
Session Management
Every time you sign in (via GitHub OAuth, Sign in with Key, or token), JJHub creates a session. You can view all active sessions across your devices and revoke any session you no longer need.View Active Sessions
List all sessions associated with your account:| Field | Description |
|---|---|
id | Unique session identifier (UUID) |
device | Device or client name (e.g., “CLI”, “Browser - macOS”) |
ip_address | IP address where the session was created |
last_active | Timestamp of the most recent activity on this session |
created_at | Timestamp when the session was created |
--json for machine-readable output:
Revoke a Session
To sign out a specific session (for example, a session on a lost device or a session you no longer recognize):401 Unauthorized response.
API equivalent:
204 No Content.
You cannot revoke your current session through this endpoint — use jjhub auth logout instead.
When to Use Session Revocation
- Lost or stolen device: Immediately revoke sessions associated with the compromised device.
- Shared computer: After using JJHub on a shared machine, revoke that session from your own device.
- Security audit: Periodically review your active sessions and revoke any you do not recognize.
- Rotating credentials: After rotating tokens or keys, revoke old sessions to ensure clean credential state.
Two-Factor Authentication (2FA)
JJHub supports two-factor authentication (2FA) via TOTP (Time-based One-Time Passwords) for GitHub OAuth users. 2FA adds a second layer of security to your account by requiring a short-lived code from an authenticator app in addition to your primary login method. Sign in with Key users do not need 2FA — their authentication is already based on cryptographic key signing, which provides equivalent or stronger security guarantees. 2FA is designed for GitHub OAuth users who want additional protection beyond what OAuth alone provides.How TOTP Works
TOTP generates a new six-digit code every 30 seconds using a shared secret between your authenticator app and the JJHub server. When you log in, JJHub prompts you for the current code. Because the code changes frequently and requires possession of your authenticator device, it protects your account even if your GitHub OAuth session is compromised. Compatible authenticator apps include Google Authenticator, Authy, 1Password, Bitwarden, and any app that supports the TOTP standard (RFC 6238).Enable 2FA
- JJHub generates a TOTP secret and returns it as both a QR code URI and a plain-text secret.
- Scan the QR code with your authenticator app (or manually enter the secret).
- Enter the current six-digit TOTP code from your authenticator app to confirm setup.
secret is the TOTP shared secret. The qr_uri is an otpauth:// URI suitable for rendering as a QR code. The recovery_codes are single-use backup codes (see Recovery Codes below). At this stage, 2FA is not yet active — you must confirm enrollment.
Step 2: Confirm enrollment
204 No Content.
Disable 2FA
204 No Content.
Check 2FA Status
Recovery Codes
When you enable 2FA, JJHub generates a set of eight single-use recovery codes. These codes can be used in place of a TOTP code if you lose access to your authenticator device (for example, if your phone is lost or reset). Important:- Each recovery code can only be used once. After use, it is permanently invalidated.
- Store your recovery codes in a safe, offline location (e.g., a password manager, a printed copy in a secure place).
- If you run out of recovery codes, regenerate a new set before you lose access to your authenticator app.
2FA API Endpoints
| Method | Endpoint | Description |
|---|---|---|
POST | /api/user/2fa/enroll | Start 2FA enrollment (returns secret, QR URI, and recovery codes) |
POST | /api/user/2fa/confirm | Confirm enrollment with a TOTP code (body: {"code": "..."}) |
DELETE | /api/user/2fa | Disable 2FA (body: {"code": "..."}) |
POST | /api/user/2fa/recovery | Regenerate recovery codes (body: {"code": "..."}) |
Who Needs 2FA
| Auth method | 2FA available | Why |
|---|---|---|
| GitHub OAuth | Yes | OAuth delegates authentication to GitHub. 2FA adds a JJHub-level second factor so that a compromised GitHub session alone is not sufficient to access your JJHub account. |
| Sign in with Key | No (not needed) | Authentication is already based on cryptographic key signing. The private key never leaves your device, providing equivalent security to hardware-backed 2FA. |
Email Management
Email addresses on JJHub are optional. You are never required to provide an email to create an account or use the platform. Sign in with Key users may not have an email address at all, and GitHub OAuth users have their verified email imported automatically. However, a verified email is required for certain features:- Email notifications: Mentions, review requests, CI status updates, and other notifications can only be delivered to a verified email address.
- Commit attribution: JJHub matches commit author emails to user accounts. Adding and verifying the email addresses you use in commits ensures your contributions are correctly attributed to your profile.
JJHub’s Email Policy
| Scenario | Email behavior |
|---|---|
| GitHub OAuth signup | Verified email auto-imported from GitHub. Email notifications enabled by default. |
| Sign in with Key signup | No email on account. Prompted to add one in settings. Email notifications disabled until a verified email is added. |
| Multiple emails | You can add multiple email addresses. One is marked as primary (used for notifications). |
Add an Email
Verify an Email
After adding an email, you receive a verification email with a code. Complete verification with the CLI or by clicking the link in the email:List Emails
Set Primary Email
Your primary email is the address used for email notifications. Only verified emails can be set as primary:Remove an Email
204 No Content.
Email API Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET | /api/user/emails | List all email addresses on your account |
POST | /api/user/emails | Add a new email address (body: {"email": "..."}) |
DELETE | /api/user/emails/:id | Remove an email address |
POST | /api/user/emails/:id/verify | Verify an email address (body: {"code": "..."}) |
How Emails Relate to Notifications
JJHub delivers notifications through two channels:- In-app notifications: Always available, regardless of email status. Delivered via SSE in real-time.
- Email notifications: Require at least one verified email address marked as primary. If you have no verified email, email notifications are silently skipped — you still receive in-app notifications.
- @mentions in issues or landing requests
- Review requests on landing requests
- CI/workflow status changes on your changes
- Assignment to an issue
How Emails Relate to Commit Attribution
JJHub matches the author email in commits to user accounts. When you push commits with an email that matches a verified email on your JJHub account, those commits are attributed to your profile. This affects:- Your contribution graph
- Author links in the commit history
- Landing request authorship
API Tokens
For CI/CD pipelines and programmatic access, use personal access tokens. Create tokens via the CLI withjjhub auth token create, or via the API.
Tokens are prefixed with jjhub_ and stored as SHA-256 hashes on the server - the full token is shown only at creation time.
Token Scopes
| Scope | Description |
|---|---|
repo | Full repository access (read + write) |
repo:read | Read repository contents |
repo:write | Push to repositories |
user | Full user access (read + write) |
user:read | Read user profile |
user:write | Update user profile |
admin | Full administrative access |
repo:write includes repo:read).
Environment Variables
JJHUB_TOKEN automatically. No config file needed for CI.
Alternatively, pipe a token directly: