Skip to content

feat(admin): replace password login with NIP-98 HTTP auth#671

Open
Justxd22 wants to merge 1 commit into
cameri:mainfrom
Justxd22:feat/nip98-admin-auth
Open

feat(admin): replace password login with NIP-98 HTTP auth#671
Justxd22 wants to merge 1 commit into
cameri:mainfrom
Justxd22:feat/nip98-admin-auth

Conversation

@Justxd22

@Justxd22 Justxd22 commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Implements NIP-98 HTTP auth for the admin console, fully replacing the temporary password login shipped with the Phase 1 admin backend foundation

  • Nip98AdminAuthProvider: pubkey must be on the new admin.pubkeys allowlist (hex or npub; empty = deny all); Redis replay guard rejects reused event ids (fail-closed). Login mints the existing HMAC session cookie; protected routes also accept a fresh per-request Nostr header.
  • Browser flow: GET /admin/login page asks any connected NIP-07 signer/wallet to sign the auth event; auth middleware now gates all /admin/* traffic, Any unauthenticated browser redirects 302 to the login page, API clients get 401 JSON.
  • Added Minimal authenticated landing page at /admin (placeholder until the dashboard UI )
  • Added POST /admin/logout.
  • Removed: PasswordAdminAuthProvider, admin.passwordHash, ADMIN_PASSWORD, login body schema.
  • Added NIP 98 in supported_nips.

Operators must set admin.pubkeys in settings.yaml to use the admin console; admin.enabled still defaults to false.

Related Issue

closes #670

How Has This Been Tested?

  • New test/unit/utils/nip98.spec.ts (36 cases: parsing, crypto, freshness, u/method/payload matching).
  • Rewritten test/unit/routes/admin.spec.ts (20 cases: login, per-request auth, replay rejection, payload hash, npub allowlist, redirects, dashboard, logout, disabled/401/500 behaviors preserved).
  • Verified live in a browser against a NIP-07 signer: login 200 + cookie, replay rejected.

Screenshots:

recording_2026-07-08_06.52.03.mp4

Types of changes

  • Non-functional change (docs, style, minor refactor)
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my code changes.
  • I added a changeset, or this is docs-only and I added an empty changeset.
  • All new and existing tests passed.

@changeset-bot

changeset-bot Bot commented Jul 8, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 9ce1dc9

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
nostream Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Comment thread src/routes/admin/index.ts
router.post('/login', adminLoginRateLimitMiddleware, raw({ type: () => true, limit: '64kb' }), withAdminController(createPostAdminLoginController))
// Everything below requires NIP-98 authentication; unauthenticated browser
// navigations are redirected to the login page, other requests receive 401.
router.use(adminRateLimitMiddleware, adminAuthMiddleware)
Comment thread src/utils/nip98.ts
return failure('missing authorization header')
}

const match = NOSTR_SCHEME_REGEX.exec(header.trim())
@Anshumancanrock

Copy link
Copy Markdown
Collaborator

Hi @Justxd22, Thank you for the PR and for your contribution!
However, NIP-98 is part of my project and I’m supposed to implement it during this phase (Phase 2). Thanks again for your effort though.

@coveralls

Copy link
Copy Markdown
Collaborator

Coverage Status

coverage: 68.333% (+0.6%) from 67.747% — Justxd22:feat/nip98-admin-auth into cameri:main

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR replaces the admin console’s temporary password-based authentication with NIP-98 (kind 27235) HTTP auth, introducing a pubkey allowlist and replay protection while adding minimal browser-facing login/dashboard/logout flows for the /admin/* area.

Changes:

  • Implement NIP-98 verification utilities and a new Nip98AdminAuthProvider backed by a Redis replay guard and admin.pubkeys allowlist.
  • Update admin routing to gate all /admin/* paths, adding HTML login + placeholder dashboard pages and a logout endpoint.
  • Remove the password login implementation and add/refresh unit tests covering NIP-98 and admin flows.

Reviewed changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
test/unit/utils/nip98.spec.ts New unit tests for NIP-98 parsing and verification logic.
test/unit/routes/admin.spec.ts Updated admin router tests for NIP-98 login/auth, replay protection, redirects, logout.
src/utils/nip98.ts New NIP-98 parsing/verification helpers.
src/utils/http.ts Add getPublicRequestUrl for reconstructing request URLs for signing/verification.
src/utils/admin-password.ts Remove password hashing/verification utilities.
src/schemas/admin-login-schema.ts Remove password login request body schema.
src/routes/admin/index.ts Rework admin routes for NIP-98 login page, raw-body login POST, global auth gate, dashboard, logout.
src/handlers/request-handlers/post-admin-logout-handler.ts New logout handler that clears the admin session cookie.
src/handlers/request-handlers/get-admin-login-page-handler.ts New handler that serves the admin login HTML template.
src/handlers/request-handlers/get-admin-dashboard-page-handler.ts New handler that serves a minimal authenticated admin landing page.
src/handlers/request-handlers/admin-auth-middleware.ts Switch auth middleware to async provider + browser redirect behavior.
src/factories/admin-auth-provider-factory.ts Swap password auth provider for NIP-98 provider + Redis replay guard.
src/constants/base.ts Add NIP-98 event kind and tag constants.
src/admin/redis-nip98-replay-guard.ts New Redis-backed replay guard for NIP-98 event ids.
src/admin/password-admin-auth-provider.ts Remove password-based admin auth provider.
src/admin/nip98-admin-auth-provider.ts New NIP-98 admin auth provider (allowlist + per-request header support + session cookie minting).
src/@types/settings.ts Replace admin password hash setting with admin.pubkeys and add timestamp tolerance setting.
src/@types/admin.ts Make isRequestAuthenticated async and add replay-guard interface type.
resources/default-settings.yaml Add empty default admin.pubkeys allowlist.
resources/admin-login.html Add browser login page that signs a NIP-98 event via NIP-07.
resources/admin-dashboard.html Add minimal authenticated admin landing page + logout action.
README.md Document NIP-98 as supported for admin console login.
package.json Add NIP-98 to supported NIPs list.
.changeset/cool-ways-brake.md Changeset for the new admin auth behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +7 to +16
public async registerEventId(eventId: string, ttlSeconds: number): Promise<boolean> {
const client = this.getClient()
if (!client.isOpen) {
await client.connect()
}

const result = await client.set(`nip98:seen:${eventId}`, '1', { NX: true, EX: ttlSeconds })

return result === 'OK'
}
Comment thread src/utils/http.ts
Comment on lines +165 to +169
const proto = isSecureRequest(request, settings) ? 'https' : 'http'
const prefix = getPublicPathPrefix(request, settings)
const path = request.originalUrl ?? request.url ?? '/'

return `${proto}://${host}${joinPathPrefix(prefix, path)}`
@Justxd22

Justxd22 commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

@Anshumancanrock Only added admin dashboard support, Relay NIP98 still not impl

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Admin console] Implement NIP-98 HTTP auth for the admin console

5 participants