Nostr_Login_Lite
===========
This library is a powerful `window.nostr` provider.
```
```
Just add the above script to your HTML and
get a nice UI for users to login with Nostr Connect (nip46), with an extension, read-only login,
account switching, OAuth-like sign up, etc. Your app just talks to the `window.nostr`, the rest is handled by `nostr-login`.
See it in action on [nostr.band](https://nostr.band).
## Options
You can set these attributes to the `script` tag to customize the behavior:
- `data-dark-mode` - `true`/`false`, default will use the browser's color theme
- `data-bunkers` - the comma-separated list of domain names of Nostr Connect (nip46) providers for sign up, i.e. `nsec.app,highlighter.com`
- `data-perms` - the comma-separated list of [permissions](https://github.com/nostr-protocol/nips/blob/master/46.md#requested-permissions) requested by the app over Nostr Connect, i.e. `sign_event:1,nip04_encrypt`
- `data-theme` - color themes, one of `default`, `ocean`, `lemonade`, `purple`
- `data-no-banner` - if `true`, do not show the `nostr-login` banner, will need to launch the modals using event dispatch, see below
- `data-methods` - comma-separated list of allowed auth methods, method names: `connect`, `extension`, `readOnly`, `local`, all allowed by default.
- `data-otp-request-url` - URL for requesting OTP code
- `data-otp-reply-url` - URL for replying with OTP code
- `data-title` - title for the welcome screen
- `data-description` - description for the welcome screen
- `data-start-screen` - screen shown by default (banner click, window.nostr.* call), options: `welcome`, `welcome-login`, `welcome-signup`, `signup`, `local-signup`, `login`, `otp`, `connect`, `login-bunker-url`, `login-read-only`, `connection-string`, `switch-account`, `import`
- `data-signup-relays` - comma-separated list of relays where nip65 event will be published on local signup
- `data-outbox-relays` - comma-separated list of relays that will be added to nip65 event on local signup
- `data-signup-nstart` - "true" to use start.njump.me instead of local signup
- `data-follow-npubs` - comma-separated list of npubs to follow if njump.me signup is used
Example:
```
```
## Updating the UI
Whenever user performs an auth-related action using `nostr-login`, a `nlAuth` event will be dispatched on the `document`, which you can listen
to in order to update your UI (show user profile, etc):
```
document.addEventListener('nlAuth', (e) => {
// type is login, signup or logout
if (e.detail.type === 'login' || e.detail.type === 'signup') {
onLogin(); // get pubkey with window.nostr and show user profile
} else {
onLogout() // clear local user data, hide profile info
}
})
```
## Launching, logout, etc
The `nostr-login` auth modals will be automatically launched whenever you
make a call to `window.nostr` if user isn't authed yet. However, you can also launch the auth flow by dispatching a custom `nlLaunch` event:
```
document.dispatchEvent(new CustomEvent('nlLaunch', { detail: 'welcome' }));
```
The `detail` event payload can be empty, or can be one of `welcome`, `signup`, `login`, `login-bunker-url`, `login-read-only`, `switch-account`.
To trigger logout in the `nostr-login`, you can dispatch a `nlLogout` event:
```
document.dispatchEvent(new Event("nlLogout"));
```
To change dark mode in the `nostr-login`, you can dispatch a `nlDarkMode` event, with detail as `darkMode` boolean:
```
document.dispatchEvent(new CustomEvent("nlDarkMode", { detail: true }));
```
## Use as a package
Install `nostr-login` package with `npm` and then:
```
import { init as initNostrLogin } from "nostr-login"
// make sure this is called before any
// window.nostr calls are made
initNostrLogin({/*options*/})
```
Now the `window.nostr` will be initialized and on your first call
to it the auth flow will be launched if user isn't authed yet.
You can also launch the auth flow yourself:
```
import { launch as launchNostrLoginDialog } from "nostr-login"
// make sure init() was called
// on your signup button click
function onSignupClick() {
// launch signup screen
launchNostrLoginDialog({
startScreen: 'signup'
})
}
```
### Next.js Fix for Server Side Rendering (SSR)
`nostr-login` calls `document` which is unavailable for server-side rendering. You will have build errors. To fix this, you can import `nostr-login` on the client side in your component with a `useEffect` like this:
```javascript
useEffect(() => {
import('nostr-login')
.then(async ({ init }) => {
init({
// options
})
})
.catch((error) => console.log('Failed to load nostr-login', error));
}, []);
```
Note: even if your component has `"use client"` in the first line, this fix still may be necessary.
---
API:
- `init(opts)` - set mapping of window.nostr to nostr-login
- `launch(startScreen)` - launch nostr-login UI
- `logout()` - drop the current nip46 connection
Options:
- `theme` - same as `data-theme` above
- `startScreen` - same as `startScreen` for `nlLaunch` event above
- `bunkers` - same as `data-bunkers` above
- `devOverrideBunkerOrigin` - for testing, overrides the bunker origin for local setup
- `onAuth: (npub: string, options: NostrLoginAuthOptions)` - a callback to provide instead of listening to `nlAuth` event
- `perms` - same as `data-perms` above
- `darkMode` - same as `data-dark-mode` above
- `noBanner` - same as `data-no-banner` above
- `isSignInWithExtension` - `true` to bring the *Sign in with exception* button into main list of options, `false` to hide to the *Advanced*, default will behave as `true` if extension is detected.
## OTP login
If you supply both `data-otp-request-url` and `data-otp-reply-url` then "Login with DM" button will appear on the welcome screen.
When user enters their nip05 or npub, a GET request is made to `[?&]pubkey=`. Server should send
a DM with one-time code to that pubkey and should return 200.
After user enters the code, a GET request is made to `[?&]pubkey=&code=`. Server should check that code matches the pubkey and hasn't expired, and should return 200 status and an optional payload. Nostr-login will deliver the payload as `otpData` field in `nlAuth` event, and will save the payload in localstore and will deliver it again as `nlAuth` on page reload.
The reply payload may be used to supply the session token. If token is sent by the server as a cookie then payload might be empty, otherwise the payload should be used by the app to extract the token and use it in future API calls to the server.
## Examples
* [Basic HTML Example](./examples/usage.html)
## TODO
- fetch bunker list using NIP-89
- Amber support
- allow use without the UIs
- add timeout handling
- more at [issues](https://github.com/nostrband/nostr-login/issues)