mirror of
https://github.com/go-gitea/gitea.git
synced 2026-07-15 20:09:18 -05:00
Integration with Nostr Login #14530
Open
opened 2025-11-02 11:15:24 -06:00 by GiteaMirror
·
9 comments
No Branch/Tag Specified
main
release/v1.25
release/v1.24
release/v1.23
release/v1.22
release/v1.21
release/v1.20
release/v1.19
release/v1.18
release/v1.17
release/v1.16
release/v1.15
release/v1.14
release/v1.13
release/v1.12
release/v1.11
release/v1.10
release/v1.9
release/v1.8
v1.25.3
v1.25.2
v1.25.1
v1.25.0
v1.24.7
v1.25.0-rc0
v1.26.0-dev
v1.24.6
v1.24.5
v1.24.4
v1.24.3
v1.24.2
v1.24.1
v1.24.0
v1.23.8
v1.24.0-rc0
v1.25.0-dev
v1.23.7
v1.23.6
v1.23.5
v1.23.4
v1.23.3
v1.23.2
v1.23.1
v1.23.0
v1.23.0-rc0
v1.24.0-dev
v1.22.6
v1.22.5
v1.22.4
v1.22.3
v1.22.2
v1.22.1
v1.22.0
v1.23.0-dev
v1.22.0-rc1
v1.21.11
v1.22.0-rc0
v1.21.10
v1.21.9
v1.21.8
v1.21.7
v1.21.6
v1.21.5
v1.21.4
v1.21.3
v1.21.2
v1.20.6
v1.21.1
v1.21.0
v1.21.0-rc2
v1.21.0-rc1
v1.20.5
v1.22.0-dev
v1.21.0-rc0
v1.20.4
v1.20.3
v1.20.2
v1.20.1
v1.20.0
v1.19.4
v1.21.0-dev
v1.20.0-rc2
v1.20.0-rc1
v1.20.0-rc0
v1.19.3
v1.19.2
v1.19.1
v1.19.0
v1.19.0-rc1
v1.20.0-dev
v1.19.0-rc0
v1.18.5
v1.18.4
v1.18.3
v1.18.2
v1.18.1
v1.18.0
v1.17.4
v1.18.0-rc1
v1.19.0-dev
v1.18.0-rc0
v1.17.3
v1.17.2
v1.17.1
v1.17.0
v1.17.0-rc2
v1.16.9
v1.17.0-rc1
v1.18.0-dev
v1.16.8
v1.16.7
v1.16.6
v1.16.5
v1.16.4
v1.16.3
v1.16.2
v1.16.1
v1.16.0
v1.15.11
v1.17.0-dev
v1.16.0-rc1
v1.15.10
v1.15.9
v1.15.8
v1.15.7
v1.15.6
v1.15.5
v1.15.4
v1.15.3
v1.15.2
v1.15.1
v1.14.7
v1.15.0
v1.15.0-rc3
v1.14.6
v1.15.0-rc2
v1.14.5
v1.16.0-dev
v1.15.0-rc1
v1.14.4
v1.14.3
v1.14.2
v1.14.1
v1.14.0
v1.13.7
v1.14.0-rc2
v1.13.6
v1.13.5
v1.14.0-rc1
v1.15.0-dev
v1.13.4
v1.13.3
v1.13.2
v1.13.1
v1.13.0
v1.12.6
v1.13.0-rc2
v1.14.0-dev
v1.13.0-rc1
v1.12.5
v1.12.4
v1.12.3
v1.12.2
v1.12.1
v1.11.8
v1.12.0
v1.11.7
v1.12.0-rc2
v1.11.6
v1.12.0-rc1
v1.13.0-dev
v1.11.5
v1.11.4
v1.11.3
v1.10.6
v1.12.0-dev
v1.11.2
v1.10.5
v1.11.1
v1.10.4
v1.11.0
v1.11.0-rc2
v1.10.3
v1.11.0-rc1
v1.10.2
v1.10.1
v1.10.0
v1.9.6
v1.9.5
v1.10.0-rc2
v1.11.0-dev
v1.10.0-rc1
v1.9.4
v1.9.3
v1.9.2
v1.9.1
v1.9.0
v1.9.0-rc2
v1.10.0-dev
v1.9.0-rc1
v1.8.3
v1.8.2
v1.8.1
v1.8.0
v1.8.0-rc3
v1.7.6
v1.8.0-rc2
v1.7.5
v1.8.0-rc1
v1.9.0-dev
v1.7.4
v1.7.3
v1.7.2
v1.7.1
v1.7.0
v1.7.0-rc3
v1.6.4
v1.7.0-rc2
v1.6.3
v1.7.0-rc1
v1.7.0-dev
v1.6.2
v1.6.1
v1.6.0
v1.6.0-rc2
v1.5.3
v1.6.0-rc1
v1.6.0-dev
v1.5.2
v1.5.1
v1.5.0
v1.5.0-rc2
v1.5.0-rc1
v1.5.0-dev
v1.4.3
v1.4.2
v1.4.1
v1.4.0
v1.4.0-rc3
v1.4.0-rc2
v1.3.3
v1.4.0-rc1
v1.3.2
v1.3.1
v1.3.0
v1.3.0-rc2
v1.3.0-rc1
v1.2.3
v1.2.2
v1.2.1
v1.2.0
v1.2.0-rc3
v1.2.0-rc2
v1.1.4
v1.2.0-rc1
v1.1.3
v1.1.2
v1.1.1
v1.1.0
v1.0.2
v1.0.1
v1.0.0
v0.9.99
Labels
Clear labels
$20
$250
$50
$500
backport/done
💎 Bounty
docs-update-needed
good first issue
hacktoberfest
issue/bounty
issue/confirmed
issue/critical
issue/duplicate
issue/needs-feedback
issue/not-a-bug
issue/regression
issue/stale
issue/workaround
lgtm/need 2
modifies/api
modifies/translation
outdated/backport/v1.18
outdated/theme/markdown
outdated/theme/timetracker
performance/bigrepo
performance/cpu
performance/memory
performance/speed
pr/breaking
proposal/accepted
proposal/rejected
pr/wip
pull-request
reviewed/wontfix
💰 Rewarded
skip-changelog
status/blocked
topic/accessibility
topic/api
topic/authentication
topic/build
topic/code-linting
topic/commit-signing
topic/content-rendering
topic/deployment
topic/distribution
topic/federation
topic/gitea-actions
topic/issues
topic/lfs
topic/mobile
topic/moderation
topic/packages
topic/pr
topic/projects
topic/repo
topic/repo-migration
topic/security
topic/theme
topic/ui
topic/ui-interaction
topic/ux
topic/webhooks
topic/wiki
type/bug
type/deprecation
type/docs
type/enhancement
type/feature
type/miscellaneous
type/proposal
type/question
type/refactoring
type/summary
type/testing
type/upstream
Mirrored from GitHub Pull Request
No Label
type/proposal
Milestone
No items
No Milestone
Projects
Clear projects
No project
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: github-starred/gitea#14530
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @Zig-VS-TypeScript-VS on GitHub (May 29, 2025).
Feature Description
Overview
We're requesting Gitea Issues to add support for the Nostr protocol for login. This would enable users to securely and privately log into Gitea using their Nostr key pair, leveraging the benefits of Nostr's decentralized authentication.
Why Nostr NIP Login?
Decentralized Identity:
Users wouldn't rely on centralized identity providers (like GitHub or Google). Their identity would be controlled by their own Nostr key pair.
Privacy Protection:
Users wouldn't need to expose personal identifying information (like email addresses or phone numbers) during login. Authentication would occur solely via their public key.
Censorship Resistance:
Nostr's decentralized nature makes it more resistant to censorship, meaning user identities are less likely to be easily blocked or deleted.
Unified Identity:
Users could use the same Nostr identity to log in and interact with various Nostr-enabled applications and services.
Simplified Process:
For users who already have a Nostr key, the login process would be much more convenient, eliminating the need to register new accounts or remember extra passwords.
Feature Description
Login Option
Nostr Key Pair Verification
Initiate Login:
When a user clicks "Log in with Nostr," Gitea would generate a random, time-sensitive challenge.
Challenge Delivery:
Gitea sends this challenge to the user's Nostr client (via a NIP-07 browser extension, mobile app, or desktop application).
User Action:
The user will sign the challenge within their Nostr client using their private key.
Response:
The signed message is returned to the Gitea server.
Verification:
The Gitea server verifies the signature's validity using the user's Nostr public key.
Successful Login:
Upon successful verification, the user is logged into Gitea.
User Association
First-time Login:
Account Creation:
Multiple Nostr Public Key Association:
Display Public Key:
Optional Nostr NIP-05 Verification:
Secure Logout:
Security and Privacy Features
No Password Storage:
User-Controlled Keys:
Challenge-Response Mechanism:
No PII Disclosure:
Privacy-Preserving Public Identity:
Protection Against Identity Theft:
Decentralized Auditability:
Future Extensibility:
Granular Permissions:
Implementation Considerations
NIP-07 Browser Extension Integration:
User Experience:
Error Handling:
Compatibility:
Documentation:
Expected Benefits
We believe integrating Nostr NIP login would be a significant step toward making Gitea even more secure, private, and decentralized.
Screenshots
No response
@techknowlogick commented on GitHub (May 29, 2025):
I'm not so familiar with this protocol, are you aware of any existing libraries that we could use, or even better perhaps an OIDC bridge as that's an existing standard we support?
@raucao commented on GitHub (May 31, 2025):
Nostr is based on serverless identity with nothing but public/private keypairs, so OIDC doesn't make sense for it.
There's a well-maintained Go library, which is also used by the original creator of the Nostr protocol: https://github.com/nbd-wtf/go-nostr
For website logins, you can ignore most of the protocol really. The only things needed are:
When relying solely on NIP-07 extensions, you can also just hide the Nostr login option if no extension is detected on the login page, so it's not confusing for any other users.
Example
Here's a simple implementation I did for an accounts management web app, based on Ruby on Rails and Stimulus JS (which is almost vanilla JS), which should be understandable for anyone wanting to implement it:
The event I'm using is a kind 22242, but with a
sitetag instead of arelayone. It's defined in NIP-42, the rest of which is also irrelevant for this use case.Integration with LDAP
As a bonus, and since I was just fixing a bug with Gitea's LDAP sync before I stumbled upon this issue: if the Nostr key is stored in an LDAP directory, which is the case for our accounts, then Gitea could also make use of that and import the pubkeys from there if configured by the admin. Here's our LDIF for the attribute schema (complete with a registered PEN), which anyone can use for storing Nostr pubkeys in their directories:
@dadofsambonzuki commented on GitHub (Jul 30, 2025):
NIP-98 defines HTTP Auth, which is what most clients use for 'Login with Nostr'.
If implemented, admins would simply have to add the Nostr pubkey (npub) to the user or users could 'sign-up with nostr' and only share their npub.
NIP-98 compatible browser extensions handle the signing of the ephemeral challenge with the users private key (nsec).
@raucao commented on GitHub (Jul 30, 2025):
As far as I understand NIP-98 is for signing every single request, which is unnecessary when you can just log in and then have a normal Gitea login session. Did you have a look at my example above? It works like a charm with browser extensions, and they also show the correct wording/content when connecting a key or logging in.
@dadofsambonzuki commented on GitHub (Aug 6, 2025):
NIP-98 is really just a more robust way to get a signed event specifically for auth purposes. You'd use the NIP-07 approach, but the event inside would be a NIP-98 kind. Gives better, more timely guarantees to the server.
You don't do this on each request, once you auth gitea would handle that lifecycle in the session using whatever mechanisms it currently uses for that.
@raucao commented on GitHub (Aug 7, 2025):
How so? If there's any benefit over kind 22242 events, then I'd be interested in what it is. "Better, more timely guarantees" is not possible, since it's already requiring to sign a challenge and restricting
created_attimes.@dadofsambonzuki commented on GitHub (Aug 7, 2025):
kind 22242 is specifically for nostr relay auth and is done over websockets. Nostr-native if you will.
NIP-98 requires target URL and timestamp within a 'reasonable' (60s) time and so is more tightly scoped.
It's what most services I know of use.
@raucao commented on GitHub (Aug 7, 2025):
We're using a
sitetag instead ofrelay, with the domain of the site to log in to. There's no need to specify an exact URL on the domain, because the log in is valid for the entire domain, regardless of URL.NIP-98 requires a target URL and HTTP verb, but no challenge. Our approach uses a kind that was designed for one-time authentication, whereas NIP-98 was designed for repeated inline authorization.
Thus, both approaches, when used for logging in to a website that then provides its own session, are using the underlying NIPs in a way that they weren't intended for originally. Mine does authentication for sites instead of relays (but both are just domains), while yours does inline authorization on a specific URL for user authentication to a whole site.
Personally, I prefer both the DX and UX of my approach, but if the signing UX is equally good with yours (which I haven't looked into), then I think either one is OK to implement.
@dadofsambonzuki commented on GitHub (Aug 7, 2025):
Agreed.
As long as an event is signed and presented then it doesn't really matter how.