Skip to content

@yeboid/node SDK — Product Integration Guide

The @yeboid/node SDK enables any Yebo product backend to validate YeboID tokens locally and integrate with the identity system.


Overview

The SDK provides:

  • Token validation middleware — Verify JWTs without API calls
  • User profile fetching — Get full user data from YeboID API
  • Express integration — Drop-in middleware for protected routes

Installation

bash
npm install @yeboid/node

Quick Start

javascript
const { yeboidAuth, getYeboUser } = require('@yeboid/node');
const express = require('express');

const app = express();

// 1. Initialize with shared JWT secret
yeboidAuth.init({
  jwtSecret: process.env.YEBOID_JWT_SECRET
});

// 2. Protect routes
app.get('/api/orders', yeboidAuth.required, async (req, res) => {
  // req.yeboUserId is the authenticated user's UUID
  const orders = await db.orders.find({ userId: req.yeboUserId });
  res.json(orders);
});

// 3. Optional: Fetch full profile
app.get('/api/profile', yeboidAuth.required, async (req, res) => {
  const user = await getYeboUser(req.yeboUserId);
  res.json(user);
});

SDK API Reference

yeboidAuth.init(config)

Initialize the SDK with configuration.

Parameters:

typescript
interface YeboIDConfig {
  jwtSecret: string;           // Required: shared JWT secret
  apiUrl?: string;             // Optional: YeboID API URL
}

Example:

javascript
yeboidAuth.init({
  jwtSecret: process.env.YEBOID_JWT_SECRET,
  apiUrl: 'https://api.yeboid.com'  // default
});

validateToken Middleware

Alias: yeboidAuth.required

Validates the Bearer token and fails with 401 if invalid.

Request Augmentation:

  • req.yeboUserId — User's UUID

Example:

javascript
const { validateToken } = require('@yeboid/node');

// Single route
app.get('/api/protected', validateToken, (req, res) => {
  console.log('User ID:', req.yeboUserId);
});

// Router-level
const apiRouter = express.Router();
apiRouter.use(validateToken);

Error Response (401):

json
{
  "error": "Invalid token"
}

optionalToken Middleware

Alias: yeboidAuth.optional

Extracts user if token present, but doesn't fail if missing.

Example:

javascript
const { optionalToken } = require('@yeboid/node');

app.get('/api/products', optionalToken, (req, res) => {
  if (req.yeboUserId) {
    // Personalized response
  } else {
    // Anonymous response
  }
});

getYeboUser(userId)

Fetches full user profile from YeboID API.

Parameters:

ParamTypeDescription
userIdstringYeboID user UUID

Returns:

typescript
interface YeboUser {
  id: string;
  phone: string;
  handle: string | null;
  name: string | null;
  avatar: string | null;
  kycStatus: 'NONE' | 'PENDING' | 'VERIFIED' | 'REJECTED';
  createdAt: string;
}

Example:

javascript
const { getYeboUser } = require('@yeboid/node');

const user = await getYeboUser('uuid-123');
console.log(user.handle);    // 'laslie'
console.log(user.kycStatus); // 'VERIFIED'

Notes:

  • Requires service-to-service auth (API key)
  • Consider caching for frequently accessed profiles

Token Payload Structure

Access tokens contain:

typescript
interface YeboIDPayload {
  userId: string;      // UUID
  type: 'access';      // Always 'access' for access tokens
  iat: number;         // Issued at (Unix timestamp)
  exp: number;         // Expires (15 min from iat)
}

Environment Variables

env
# Required - shared across ALL Yebo products
YEBOID_JWT_SECRET=your-shared-secret

# Optional - for fetching user profiles via getYeboUser()
YEBOID_API_URL=https://api.yeboid.com
YEBOID_SERVICE_KEY=service-to-service-api-key

Product Integration Pattern

1. Add SDK Dependency

bash
npm install @yeboid/node

2. Update Database Schema

Add yeboidUserId column to link product users to YeboID:

prisma
// In your product's schema.prisma
model User {
  id           String   @id @default(uuid())
  yeboidUserId String   @unique @map("yeboid_user_id")
  
  // Product-specific fields
  shopName     String?  // YeboShops
  resume       Json?    // YeboJobs
  
  // Relations
  orders       Order[]
}

3. Initialize SDK

javascript
// In your app initialization
const { yeboidAuth } = require('@yeboid/node');

yeboidAuth.init({
  jwtSecret: process.env.YEBOID_JWT_SECRET
});

4. Protect Routes

javascript
const { validateToken } = require('@yeboid/node');

// All /api routes require auth
app.use('/api', validateToken);
javascript
// After token validation, find/create local user
app.use('/api', async (req, res, next) => {
  let user = await prisma.user.findUnique({
    where: { yeboidUserId: req.yeboUserId }
  });
  
  if (!user) {
    // First time user - create local profile
    user = await prisma.user.create({
      data: { yeboidUserId: req.yeboUserId }
    });
  }
  
  req.user = user;  // Attach local user
  next();
});

How Local Validation Works

The SDK validates tokens locally without calling YeboID API:

User request with token


┌───────────────────────────────────┐
│ SDK extracts token from header    │
│ Authorization: Bearer <token>     │
└───────────────────────────────────┘


┌───────────────────────────────────┐
│ SDK verifies JWT signature        │
│ using YEBOID_JWT_SECRET           │
│                                   │
│ jwt.verify(token, secret)         │
└───────────────────────────────────┘

        ├── Valid ──► req.yeboUserId = payload.userId

        └── Invalid ──► 401 Unauthorized

Benefits:

  • Fast — No network call per request
  • 🔒 Secure — Short-lived tokens (15 min)
  • 📦 Scalable — No single point of failure
  • 🔄 Reliable — Works even if YeboID API is down

Shared Secret Distribution

All Yebo products use the same JWT secret stored in GCP Secret Manager:

┌─────────────────────────────────────┐
│ GCP Secret Manager (org level)      │
│                                     │
│ Secret: YEBOID_JWT_SECRET           │
│         │                           │
│         ├─► YeboShops (Cloud Run)   │
│         ├─► YeboJobs (Cloud Run)    │
│         ├─► Eneza (Cloud Run)       │
│         ├─► YeboLink (Cloud Run)    │
│         └─► [All products]          │
│                                     │
└─────────────────────────────────────┘

Cloud Run Secret Mount:

yaml
# In Cloud Run service config
env:
  - name: YEBOID_JWT_SECRET
    valueFrom:
      secretKeyRef:
        name: yeboid-jwt-secret
        key: latest

Complete Integration Example

javascript
// app.js - Full YeboShops integration
const express = require('express');
const { yeboidAuth, getYeboUser } = require('@yeboid/node');
const prisma = require('./prisma');

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

// Initialize YeboID SDK
yeboidAuth.init({
  jwtSecret: process.env.YEBOID_JWT_SECRET
});

// Middleware to attach local user after auth
async function attachUser(req, res, next) {
  let user = await prisma.user.findUnique({
    where: { yeboidUserId: req.yeboUserId }
  });
  
  if (!user) {
    // Fetch profile from YeboID
    const yeboUser = await getYeboUser(req.yeboUserId);
    
    user = await prisma.user.create({
      data: {
        yeboidUserId: req.yeboUserId,
        name: yeboUser.name,
        avatar: yeboUser.avatar
      }
    });
  }
  
  req.user = user;
  next();
}

// Protected routes
app.use('/api', yeboidAuth.required, attachUser);

// Product endpoints
app.get('/api/my-shop', async (req, res) => {
  const shop = await prisma.shop.findFirst({
    where: { ownerId: req.user.id }
  });
  res.json(shop);
});

app.post('/api/products', async (req, res) => {
  const product = await prisma.product.create({
    data: {
      ...req.body,
      sellerId: req.user.id
    }
  });
  res.json(product);
});

// Public routes (optional auth)
app.get('/products', yeboidAuth.optional, async (req, res) => {
  const products = await prisma.product.findMany();
  
  // Personalize if logged in
  if (req.yeboUserId) {
    // Add favorites, recommendations, etc.
  }
  
  res.json(products);
});

app.listen(3000);

SDK Development Roadmap

SDKStatusFeatures
@yeboid/node📋 PlannedToken validation, user fetch
@yeboid/react📋 PlannedHooks, LoginButton, Provider
@yeboid/react-native📋 PlannedSame as React + secure storage

One chat. Everything done.