nostr-access-control v0.1.7
Decentralized Access Control with Nostr (nostr-access-control)
This library implements a decentralized identity model focused on access control with Nostr.
See Decentralized Digital Identity with Nostr for a descriptive overview.
See nac-demo-app for a reference implemention app, which is also useful to get events for debugging.
Developer Guide
Import as npm package:
npm -i nostr-access-control
Run tests (after cloning and npm install):
npm run testornpm run test -t "sample"to run single test
Complile using just
Project Folders
event-functionsfolder contains simple functions that return unsigned Nostr events.event-classesfolder contains TypeScript classes, where methodstoUnsignedEvent()andtoSignedEvent()return Nostr events.verificationfolder contains theverifyEligibility(...)function which determines a user's eligibility based on our model.
You can create Badge Definition, Badge Award, and Classified Listing events using either event-functions or event-classes. Attestation event only exists in event-classes.
- Functions in
event-functionsminimally implement possible event values, and are meant to be copied and expanded in your own project. - Classes in
event-classesare more flexible, and are meant to be used as imported classes within your project.
Event Examples
For these example events, a Nostr client can check if a user has been awarded an Over 21 badge, issued by a indepdendent service (badge issuer), before showing certain content.
Classified Listing
{
"kind": 30402,
"created_at": 1675238400,
"tags": [
["d", "sensitive-content"],
["title", "Sensitive Content"],
["image", "https://ipsum.com/rated-r.png", "256x256"],
["summary", "To view this content, you require an Over 21 badge."],
["a", "30009:<badge issuer pubkey>:over21", "wss://relay"]
],
"pubkey": "<resource owner pubkey>",
"id": "...",
"sig": "..."
}Badge Definition
{
"kind": 30009,
"created_at": 1672560000,
"tags": [
["d", "over21"],
["name", "Over 21"],
["image", "https://ageverifier.com/images/over21.png", "256x256"],
["description", "User is over 21 years of age."]
],
"pubkey": "<badge issuer pubkey>",
"id": "...",
"sig": "..."
}Badge Award
{
"kind": 8,
"created_at": 1677657600,
"tags": [
["a", "30009:<badge issuer pubkey>:over21"],
["p", "<user pubkey>", "wss://relay"]
],
"pubkey": "<badge issuer pubkey>",
"id": "...",
"sig": "..."
}Attestation Event
{
"kind": 1,
"created_at": 1677657600,
"tags": [
["e", "<referenced event id>"],
["a", "30009:<badge issuer pubkey>:over21"]
],
"content": "Attestation for badge definition event (Over 21). Signed on Fri, 17 Nov 2023 09:51:57 GMT",
"pubkey": "<attester pubkey>",
"id": "...",
"sig": "..."
}An Attestation Event is a Kind 1 note, which references another event via e and a tags.
Signed by an application/platform key to attest the information in the referenced event was processed by the application and is correct. Alternative to NIP-03 based on centralized trust.
Verifying Eligibility
The verification folder contain the verifyEligibility(...) function which determines a user's eligibility based on events passed in.
Also returns errors detected during validation of events.
Can run with command: jest -t "sample"
const result = verifyEligibility({
userPublicKey: userPublicKey,
classifiedListingEvent: classifiedListingTemplate,
badgeAwardEvents: [badgeAwardTemplate]
})
const {isEligible, badges, errors} = result
if (isEligible)
{
console.log('user is eligible to access the resource')
}
else {
console.log('user is not eligible to access the resource')
}
type EligibilityResult = {
isEligible: boolean
badges?: ValidateBadgeAwardResult[]
errors?: string[]
}
const verifyEligibility = (props: {
userPublicKey: string
eventWithCriteria: Event
badgeAwardEvents: Event[]
}): EligibilityResult => {...}Interpreting Results
The verifyEligibility function determines if user with userPublicKey is eligible for eventWithCriteria, based on badgeAwardEvents.
The verifyEligibility function returns result as EligilibityResult.
isEligibleboolean is the overall resulterrorsis a string array of non-badge specific reasons why the user is not eligible.badgesis an array of ValidateBadgeAwardResult objects, which contain the reasons why a required badge in the eligibility criteria is not considered awarded.
If isEligible is true, you should expect a ValidateBadgeAwardResult item in badges for each required badge, where isValid is true.
When isElibile is not true, you can check errors in EligibilityResult or ValidateBadgeAwardResult items for the reason why user is not eligible.
It is possible that isEligible is true, but there exists a ValidateBadgeAwardResult where isValid is not true, when the badgeAwardEvents parameter contains a non-relevant badge award event.