# 🟪 RAuth Provider (v2)

A **production-ready Node.js backend SDK** for the [RAuth v2](https://rauth.io) authentication platform — enabling **OTP-free, secure, and real-time user verification**.

---

## 🚀 Overview

RAuth Provider helps backend developers integrate **Reverse Authentication** (via WhatsApp, Reverse SMS, or the OneID App) and **passkey-based verification** without building complex verification flows.

It also provides **session** and **approval token** management for handling both authentication and authorization with high security.

---

## ✅ Features

- 📲 **Reverse Authentication** – Verify users through WhatsApp, Reverse SMS, or OneID (no OTPs)
- 🔐 **Session Management** – Create, validate, and auto-revoke active sessions
- 📡 **Real-Time Updates** – Instantly sync token status using built-in SSE
- 🧩 **Plug-and-Play API** – Simple, developer-friendly API surface
- ⚡ **Express Middleware Support** – Drop-in integration for Express.js
- 🛡️ **Secure by Design** – Uses JWT validation and authenticated API calls
- 🧠 **Smart Caching** – In-memory tracking with API fallback for resilience
- 🔗 **Fully Compatible with RAuth APIs** – Directly integrates with the `api.rauth.io/v2/` backend
- 💜 **TypeScript Native** – Complete type definitions for modern development

---

## 📦 Installation

```bash
npm install rauth-provider
````

---

## ⚙️ Quick Start (Hybrid ESM + CommonJS)

### ESM / TypeScript (Recommended)

```ts
import { RauthProvider } from 'rauth-provider';

RauthProvider.init({
  api_key: process.env.RAUTH_API_KEY!,
  app_id: process.env.RAUTH_APP_ID!,
});

// Verify a session (phone must match and status must be verified)
const sessionOk = await RauthProvider.verifySession('session-token', '+1234567890');

// Verify an approval (approval_token must map to a verified session for the phone)
const approval = await RauthProvider.verifyApproval('approval-token', '+1234567890');
```

### CommonJS (Legacy Node.js)

```js
const { RauthProvider } = require('rauth-provider');

RauthProvider.init({
  api_key: process.env.RAUTH_API_KEY,
  app_id: process.env.RAUTH_APP_ID,
});

const sessionOk = await RauthProvider.verifySession('session-token', '+1234567890');
const approval = await RauthProvider.verifyApproval('approval-token', '+1234567890');
```

> ℹ️ **Note:** RauthProvider is a singleton instance — once initialized, it maintains shared state across your entire backend.

---

## 🧰 Usage Examples

### ESM / TypeScript (Express + JWT + Approval Token)

The following examples demonstrate how to integrate RAuth with Express.js for login, sensitive actions, and secure routes.

```ts
import express from 'express';
import jwt from 'jsonwebtoken';
import { RauthProvider } from 'rauth-provider';

const app = express();
app.use(express.json());

RauthProvider.init({
  api_key: process.env.RAUTH_API_KEY!,
  app_id: process.env.RAUTH_APP_ID!,
});

// 1) Login: exchange a verified session for your own JWT
app.post('/auth/login', async (req, res) => {
  const { session_token, phone } = req.body;
  const ok = await RauthProvider.verifySession(session_token, phone);
  if (!ok) return res.status(401).json({ error: 'not_verified' });

  const jwtToken = jwt.sign({ phone, session_token }, process.env.JWT_SECRET!, {
    expiresIn: '24h',
  });
  return res.json({ token: jwtToken });
});

// 2) Sensitive action: verify approval token
app.post('/actions/transfer', async (req, res) => {
  const { approval_token, phone, amount } = req.body;
  const result = await RauthProvider.verifyApproval(approval_token, phone);
  if (!result.valid) return res.status(401).json({ error: 'approval_invalid' });

  // Continue with action (e.g., transfer money)
  return res.json({ success: true, action: result.action, amount });
});

// 3) Protected route example (check revocation)
app.get('/secure', async (req, res) => {
  try {
    const token = req.headers.authorization?.replace('Bearer ', '') || '';
    const decoded = jwt.verify(token, process.env.JWT_SECRET!);
    const revoked = await RauthProvider.isSessionRevoked(decoded.session_token, decoded.phone);
    if (revoked) return res.status(401).json({ error: 'session_revoked' });
    return res.json({ ok: true, user: decoded.phone });
  } catch (e) {
    return res.status(401).json({ error: 'invalid_jwt' });
  }
});

app.listen(3000, () => console.log('Server running on 3000'));
```

### CommonJS (Express + JWT + Approval Token)

```js
const express = require('express');
const jwt = require('jsonwebtoken');
const { RauthProvider } = require('rauth-provider');

const app = express();
app.use(express.json());

RauthProvider.init({ api_key: process.env.RAUTH_API_KEY, app_id: process.env.RAUTH_APP_ID });

app.post('/auth/login', async (req, res) => {
  const { session_token, phone } = req.body;
  const ok = await RauthProvider.verifySession(session_token, phone);
  if (!ok) return res.status(401).json({ error: 'not_verified' });
  const token = jwt.sign({ phone, session_token }, process.env.JWT_SECRET, { expiresIn: '24h' });
  res.json({ token });
});

app.post('/actions/transfer', async (req, res) => {
  const { approval_token, phone, amount } = req.body;
  const result = await RauthProvider.verifyApproval(approval_token, phone);
  if (!result.valid) return res.status(401).json({ error: 'approval_invalid' });
  res.json({ success: true, action: result.action, amount });
});
```

---

## 📘 API Reference

### `RauthProvider.init(options)`

Initializes the RAuth Provider with your credentials and optional configuration.

**Parameters:**
- `api_key` (string, required): Your RAuth API key
- `app_id` (string, required): Your RAuth App ID
- `logs` (boolean, optional): Enable console logging for debugging (default: `false`)

```ts
RauthProvider.init({
  api_key: process.env.RAUTH_API_KEY!,
  app_id: process.env.RAUTH_APP_ID!,
  logs: true, // Enable logging for development
});
```

> ℹ️ **Tip:** Set `logs: true` during development to see SSE events and internal state changes. Disable in production for cleaner logs.

---

### `RauthProvider.verifySession(sessionToken, userPhone)`

Verifies that a session is valid, matches the given phone number, and is marked as verified.

```ts
const isValid = await RauthProvider.verifySession('session-token', '+1234567890');
// Returns: Promise<boolean>
```

---

### `RauthProvider.isVerified(sessionToken, userPhone)`

Alias for `verifySession()` that returns a boolean.

```ts
const isVerified = await RauthProvider.isVerified('session-token', '+1234567890');
```

---

### `RauthProvider.isSessionRevoked(sessionToken, userPhone)`

Checks if a given session token has been revoked.

```ts
const isRevoked = await RauthProvider.isSessionRevoked('session-token', '+1234567890');
// Returns: Promise<boolean>
```

---

### `RauthProvider.checkApiHealth()`

Tests connectivity with the RAuth API.

```ts
const isHealthy = await RauthProvider.checkApiHealth();
// Returns: Promise<boolean>
```

> 🧩 Additional helpers:
>
> * `getSessionStatus(sessionToken, phone)`
> * `verifyApproval(approvalToken, phone)`

---

## 🔑 Token Types Explained

### 1️⃣ Session Token (Authentication)

**Purpose:**
Used during user signup or login to verify their mobile number and establish an authenticated session.

**Lifecycle:**
Generated via `/v2/session/init`, becomes `verified` after the user confirms through WhatsApp, Reverse SMS, or OneID.
It’s then exchanged for your app’s own JWT or session.

**Validation:**
Backend verifies `{ session_token, phone }` using `/v2/backend/session/status` or the SDK helper `verifySession()`.

**Example (Login Flow):**

```ts
// Exchange a verified session for your own JWT
app.post('/auth/login', async (req, res) => {
  const { session_token, phone } = req.body;
  const ok = await RauthProvider.verifySession(session_token, phone);
  if (!ok) return res.status(401).json({ error: 'not_verified' });

  const token = jwt.sign({ phone, session_token }, process.env.JWT_SECRET!, { expiresIn: '24h' });
  return res.json({ token });
});
```

**When to use:**

* User signup/login
* Device or browser re-verification
* Session restoration after inactivity

---

### 2️⃣ Approval Token (Authorization / Step-Up Authentication)

**Purpose:**
Authorizes high-risk or sensitive actions (e.g., payments, password reset) after login.
Works seamlessly with **Passkeys** and **OneID** for biometric or in-app confirmation.

**Lifecycle:**
Short-lived and one-time use, bound to an existing verified session.
Generated when the frontend requests approval from the user, then verified by the backend before executing an action.

**Validation:**
Backend verifies `{ approval_token, phone }` using `/v2/approval/verify` or the SDK helper `verifyApproval()`.

**Example (Sensitive Action):**

```ts
// Verify approval token before executing a sensitive operation
app.post('/payments/transfer', async (req, res) => {
  const { approval_token, phone, amount, recipient } = req.body;
  const result = await RauthProvider.verifyApproval(approval_token, phone);
  if (!result.valid) return res.status(401).json({ error: 'approval_invalid' });

  // Proceed with transfer
  return res.json({ success: true, amount, recipient });
});
```

**Passkey & OneID Integration:**

* Passkeys enable biometric 2FA (e.g., FaceID, fingerprint)
* OneID app can prompt users for instant approval; SDK receives these via **SSE events**

**When to use:**

* Financial transactions
* Password or 2FA changes
* KYC submissions or data updates
* Compliance-driven re-authentication

---

## ⚙️ Environment Variables

Create a `.env` file in your root directory:

```
RAUTH_API_KEY=your-rauth-api-key
RAUTH_APP_ID=your-app-id
JWT_SECRET=your-jwt-secret
```

---

## ❗ Error Handling

The SDK throws detailed and structured errors. Wrap all calls in `try/catch` for robust handling.

```ts
try {
  RauthProvider.init({});
} catch (error) {
  console.error(error.message);
  // Example: "RauthProvider.init(): Missing required fields: api_key, app_id"
}
```

> API errors include HTTP context (e.g., `RAuth API error 400: Invalid token`).

---

## 🧩 Compatibility

| Environment          | Supported                | Notes                                                 |
| -------------------- | ------------------------ | ----------------------------------------------------- |
| **ESM / TypeScript** | ✅                        | `import { RauthProvider } from 'rauth-provider'`      |
| **CommonJS**         | ✅                        | `const { RauthProvider } = require('rauth-provider')` |
| **Frameworks**       | Express, NestJS, Fastify | Works out of the box                                  |
| **Node.js**          | ≥ 16.x                   | Required for ESM compatibility                        |

---

## 🧠 Summary

| Token Type         | Purpose                            | Lifespan             | Example Use   |
| ------------------ | ---------------------------------- | -------------------- | ------------- |
| **Session Token**  | Mobile verification & login        | Long (session-bound) | Signup/Login  |
| **Approval Token** | Step-up auth for sensitive actions | Short (one-time use) | Payments, 2FA |

---

**RAuth Provider (v2)** — making **passwordless, OTP-free authentication** effortless for developers.

> 💡 Designed for simplicity. Secured by cryptography. Powered by RAuth.io.

