Skip to content
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

Merged
merged 6 commits into from
Jun 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions 98.md
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",
Copy link
Member

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.

Copy link
Member

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.

"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.

Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
When calling an [unsafe](https://developer.mozilla.org/en-US/docs/Glossary/Safe/HTTP) http method (all but GET, HEAD and OPTIONS), server SHOULD keep track of the event id for the above time window duration to prevent reuse.

If one of the checks was to fail the server SHOULD respond with a 401 Unauthorized response code.
Copy link
Member

Choose a reason for hiding this comment

The 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.

This comment was marked as spam.

Copy link
Member

Choose a reason for hiding this comment

The 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
```

Copy link
Contributor

@mikedilger mikedilger May 18, 2023

Choose a reason for hiding this comment

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

Replay Attacks

While this NIP assures that the kind 27235 event guarantees that its author authorizes using the stated HTTP method at the stated HTTP URL within 60 seconds of the created_at timestamp, it does not guarantee to the relay server that the HTTP client supplying this event is the author of that event. That is to say, replay attacks within 60 seconds are possible if the event leaks.

Relays Servers should consider whether any data they return to an authenticated HTTP connection is confidential. If so, it is strongly recommended that they only accept authentication and reply with said confidential information if the connection is secured with TLS (e.g. via https).

Copy link
Member

Choose a reason for hiding this comment

The 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.

Copy link
Member

Choose a reason for hiding this comment

The 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)
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
- [NIP-65: Relay List Metadata](65.md)
- [NIP-78: Application-specific data](78.md)
- [NIP-94: File Metadata](94.md)
- [NIP-98: HTTP Auth](98.md)

## Event Kinds

Expand Down Expand Up @@ -92,6 +93,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
| `23194` | Wallet Request | [47](47.md) |
| `23195` | Wallet Response | [47](47.md) |
| `24133` | Nostr Connect | [46](46.md) |
| `27235` | HTTP Auth | [98](98.md) |
| `30000` | Categorized People List | [51](51.md) |
| `30001` | Categorized Bookmark List | [51](51.md) |
| `30008` | Profile Badges | [58](58.md) |
Expand Down