-
Notifications
You must be signed in to change notification settings - Fork 591
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NIP-98 HTTP Auth #469
NIP-98 HTTP Auth #469
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,68 @@ | ||||||||||
NIP-98 | ||||||||||
====== | ||||||||||
|
||||||||||
HTTP Auth | ||||||||||
------------------------- | ||||||||||
|
||||||||||
`draft` `optional` `author:kieran` `author:melvincarvalho` | ||||||||||
|
||||||||||
This NIP defines an ephemerial event used to authorize requests to HTTP servers using nostr events. | ||||||||||
|
||||||||||
This is useful for HTTP services which are build for Nostr and deal with Nostr user accounts. | ||||||||||
|
||||||||||
## Nostr event | ||||||||||
|
||||||||||
A `kind 27235` (In reference to [RFC 7235](https://www.rfc-editor.org/rfc/rfc7235)) event is used. | ||||||||||
|
||||||||||
The `content` SHOULD be empty. | ||||||||||
|
||||||||||
The following tags are defined as REQUIRED. | ||||||||||
|
||||||||||
* `u` - absolute URL | ||||||||||
* `method` - HTTP Request Method | ||||||||||
|
||||||||||
Example event: | ||||||||||
```json | ||||||||||
{ | ||||||||||
"id": "fe964e758903360f28d8424d092da8494ed207cba823110be3a57dfe4b578734", | ||||||||||
"pubkey": "63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed", | ||||||||||
"content": "", | ||||||||||
"kind": 27235, | ||||||||||
"created_at": 1682327852, | ||||||||||
"tags": [ | ||||||||||
[ | ||||||||||
"u", | ||||||||||
"https://api.snort.social/api/v1/n5sp/list" | ||||||||||
], | ||||||||||
[ | ||||||||||
"method", | ||||||||||
"GET" | ||||||||||
] | ||||||||||
], | ||||||||||
"sig": "5ed9d8ec958bc854f997bdc24ac337d005af372324747efe4a00e24f4c30437ff4dd8308684bed467d9d6be3e5a517bb43b1732cc7d33949a3aaf86705c22184" | ||||||||||
} | ||||||||||
``` | ||||||||||
|
||||||||||
Servers MUST perform the following checks in order to validate the event: | ||||||||||
1. The `kind` MUST be `27235`. | ||||||||||
2. The `created_at` MUST be within a reasonable time window (suggestion 60 seconds). | ||||||||||
3. The `u` tag MUST be exactly the same as the absolute request URL (including query parameters). | ||||||||||
4. The `method` tag MUST be the same HTTP method used for the requested resource. | ||||||||||
|
||||||||||
When the request contains a body (as in POST/PUT/PATCH methods) clients SHOULD include a SHA256 hash of the request body in a `payload` tag as hex (`["payload", "<sha256-hex>"]`), servers MAY check this to validate that the requested payload is authorized. | ||||||||||
|
||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
If one of the checks was to fail the server SHOULD respond with a 401 Unauthorized response code. | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe this should be 403 if the Authorization header was actually sent.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
Sorry, something went wrong. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know what the constraints related to your project are, but if this is the correct usage of 401 that's fine, I'm not 100% clear on the nuances. |
||||||||||
|
||||||||||
All other checks which server MAY do are OPTIONAL, and implementation specific. | ||||||||||
|
||||||||||
## Request Flow | ||||||||||
|
||||||||||
Using the `Authorization` header, the `kind 27235` event MUST be `base64` encoded and use the Authorization scheme `Nostr` | ||||||||||
|
||||||||||
Example HTTP Authorization header: | ||||||||||
``` | ||||||||||
Authorization: Nostr eyJpZCI6ImZlOTY0ZTc1ODkwMzM2MGYyOGQ4NDI0ZDA5MmRhODQ5NGVkMjA3Y2JhODIzMTEwYmUzYTU3ZGZlNGI1Nzg3MzQiLCJwdWJrZXkiOiI2M2ZlNjMxOGRjNTg1ODNjZmUxNjgxMGY4NmRkMDllMThiZmQ3NmFhYmMyNGEwMDgxY2UyODU2ZjMzMDUwNGVkIiwiY29udGVudCI6IiIsImtpbmQiOjI3MjM1LCJjcmVhdGVkX2F0IjoxNjgyMzI3ODUyLCJ0YWdzIjpbWyJ1cmwiLCJodHRwczovL2FwaS5zbm9ydC5zb2NpYWwvYXBpL3YxL241c3AvbGlzdCJdLFsibWV0aG9kIiwiR0VUIl1dLCJzaWciOiI1ZWQ5ZDhlYzk1OGJjODU0Zjk5N2JkYzI0YWMzMzdkMDA1YWYzNzIzMjQ3NDdlZmU0YTAwZTI0ZjRjMzA0MzdmZjRkZDgzMDg2ODRiZWQ0NjdkOWQ2YmUzZTVhNTE3YmI0M2IxNzMyY2M3ZDMzOTQ5YTNhYWY4NjcwNWMyMjE4NCJ9 | ||||||||||
``` | ||||||||||
|
||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replay AttacksWhile this NIP assures that the
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are no relays involved in this flow. It only signs an event to take advantage of NIP-07, but the result is sent over an HTTP header. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A 60 second expiring token scoped to a specific URL is actually significantly better security than OAuth tokens, even with refresh tokens. This is perhaps the most secure HTTP Auth method the world has ever seen. |
||||||||||
## Reference Implementations | ||||||||||
- C# ASP.NET `AuthenticationHandler` [NostrAuth.cs](https://gist.github.com/v0l/74346ae530896115bfe2504c8cd018d3) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why "u" instead of "url"? I think single letter tags are meant to be indexed by relays with filters such as
{ "#u": [...] }
Since the intention is not to index, I don't think it should be a single letter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I second this. I believe
r
would also be valid here.