rauth-provider
Version:
A lightweight, plug-and-play Node.js library for phone number authentication using the Rauth.io reverse verification flow via WhatsApp or SMS.
251 lines (188 loc) ⢠7.19 kB
Markdown
# RauthProvider
A lightweight, plug-and-play Node.js library for phone number authentication using the Rauth.io reverse verification flow via WhatsApp or SMS. It handles everything from session creation to revocation ā with real-time webhook updates and Express.js support, all with minimal setup.
---
## ā
Features
š² **Reverse Authentication** ā Authenticate users via WhatsApp or SMS without sending OTPs
š **Session Management** ā Track sessions, verify tokens, and revoke access automatically
š” **Webhook Support** ā Listen for number verification and session revocation in real-time
š§© **Plug-and-Play API** ā Simple, developer-friendly API surface
ā” **Express Middleware** ā Drop-in Express.js integration
š”ļø **Secure by Design** ā Signature-based verification and session validation
š§ **Smart Caching** ā In-memory session tracking with fallback to API
š **Rauth API Ready** ā Built to connect seamlessly with the Rauth.io platform
šŖ **TypeScript Native** ā Full TypeScript typings included for modern development
---
## Installation
```bash
npm install rauth-provider
```
---
## Quick Start (Hybrid ESM + CommonJS)
### ESM / TypeScript (Recommended)
```js
import { RauthProvider } from 'rauth-provider';
RauthProvider.init({
rauth_api_key: process.env.RAUTH_API_KEY,
app_id: process.env.RAUTH_APP_ID,
webhook_secret: process.env.RAUTH_WEBHOOK_SECRET,
});
app.post('/rauth/webhook', RauthProvider.webhookHandler());
```
### CommonJS (Legacy Node.js)
```js
const { RauthProvider } = require('rauth-provider');
RauthProvider.init({
rauth_api_key: process.env.RAUTH_API_KEY,
app_id: process.env.RAUTH_APP_ID,
webhook_secret: process.env.RAUTH_WEBHOOK_SECRET,
});
app.post('/rauth/webhook', RauthProvider.webhookHandler());
```
> **Note:** This package supports both ESM and CommonJS. The RauthProvider is a singleton object that maintains state across your application.
---
## Usage Examples
### ESM / TypeScript (Express + JWT + Webhook)
```ts
import express from 'express';
import jwt from 'jsonwebtoken';
import { RauthProvider } from 'rauth-provider';
const app = express();
RauthProvider.init({
rauth_api_key: process.env.RAUTH_API_KEY!,
app_id: process.env.RAUTH_APP_ID!,
webhook_secret: process.env.RAUTH_WEBHOOK_SECRET!,
});
// Webhook endpoint
app.post('/rauth/webhook', RauthProvider.webhookHandler());
// Session verification endpoint
app.post('/api/login', async (req, res) => {
const { sessionToken, userPhone } = req.body;
const isVerified = await RauthProvider.verifySession(sessionToken, userPhone);
if (!isVerified) {
return res.status(401).json({ error: 'Phone number not verified' });
}
const jwtToken = jwt.sign({ userPhone, sessionToken }, process.env.JWT_SECRET!);
res.json({ jwtToken });
});
// Protected route
app.get('/api/protected', async (req, res) => {
try {
const jwtToken = req.headers.authorization?.replace('Bearer ', '');
const decoded = jwt.verify(jwtToken, process.env.JWT_SECRET!);
const isRevoked = await RauthProvider.isSessionRevoked(decoded.sessionToken);
if (isRevoked) {
return res.status(401).json({ error: 'Session revoked. Please log in again.' });
}
res.json({ message: 'Protected route accessed', user: decoded.userPhone });
} catch (error) {
res.status(401).json({ error: 'Invalid token' });
}
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
```
### CommonJS (Express + JWT + Webhook)
```js
const express = require('express');
const jwt = require('jsonwebtoken');
const { RauthProvider } = require('rauth-provider');
const app = express();
RauthProvider.init({
rauth_api_key: process.env.RAUTH_API_KEY,
app_id: process.env.RAUTH_APP_ID,
webhook_secret: process.env.RAUTH_WEBHOOK_SECRET,
});
// Webhook endpoint
app.post('/rauth/webhook', RauthProvider.webhookHandler());
// Session verification endpoint
app.post('/api/login', async (req, res) => {
const { sessionToken, userPhone } = req.body;
const isVerified = await RauthProvider.verifySession(sessionToken, userPhone);
if (!isVerified) {
return res.status(401).json({ error: 'Phone number not verified' });
}
const jwtToken = jwt.sign({ userPhone, sessionToken }, process.env.JWT_SECRET);
res.json({ jwtToken });
});
// Protected route
app.get('/api/protected', async (req, res) => {
try {
const jwtToken = req.headers.authorization?.replace('Bearer ', '');
const decoded = jwt.verify(jwtToken, process.env.JWT_SECRET);
const isRevoked = await RauthProvider.isSessionRevoked(decoded.sessionToken);
if (isRevoked) {
return res.status(401).json({ error: 'Session revoked. Please log in again.' });
}
res.json({ message: 'Protected route accessed', user: decoded.userPhone });
} catch (error) {
res.status(401).json({ error: 'Invalid token' });
}
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
```
---
## API Reference
### RauthProvider.init(options)
Initialize the RauthProvider with configuration options.
```js
RauthProvider.init({
rauth_api_key: 'your-api-key',
app_id: 'your-app-id',
webhook_secret: 'your-webhook-secret',
default_session_ttl: 900, // 15 minutes (optional)
default_revoked_ttl: 3600, // 1 hour (optional)
});
```
### RauthProvider.verifySession(sessionToken, userPhone)
Verify if a session is valid and matches the phone number.
```js
const isValid = await RauthProvider.verifySession('session-token', '+1234567890');
// Returns: Promise<boolean>
```
### RauthProvider.isSessionRevoked(sessionToken)
Check if a session has been revoked.
```js
const isRevoked = await RauthProvider.isSessionRevoked('session-token');
// Returns: Promise<boolean>
```
### RauthProvider.checkApiHealth()
Check if the rauth.io API is reachable.
```js
const isHealthy = await RauthProvider.checkApiHealth();
// Returns: Promise<boolean>
```
### RauthProvider.webhookHandler()
Returns Express middleware to handle webhook events.
```js
app.post('/rauth/webhook', RauthProvider.webhookHandler());
```
---
## Environment Variables
Create a `.env` file with the following variables:
```env
RAUTH_API_KEY=your-rauth-api-key
RAUTH_APP_ID=your-app-id
RAUTH_WEBHOOK_SECRET=your-webhook-secret
JWT_SECRET=your-jwt-secret
```
---
## Error Handling
The library provides detailed error messages:
```js
try {
RauthProvider.init({
// missing required fields
});
} catch (error) {
console.error(error.message);
// "RauthProvider.init(): Missing required fields: rauth_api_key, app_id, webhook_secret"
}
```
---
## Hybrid Compatibility
- **ESM/TypeScript:** Use named import (`import { RauthProvider } from 'rauth-provider';`).
- **CommonJS:** Use require with destructuring (`const { RauthProvider } = require('rauth-provider');`).
- RauthProvider is a singleton object that maintains state across your application.