npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

webba-id-sdk

v2.0.2

Published

SDK officiel pour intégrer l'authentification Webba ID dans vos applications

Downloads

356

Readme

webba-id-sdk

SDK officiel pour intégrer l'authentification Webba ID dans vos applications.

npm version License: MIT

Installation

npm install webba-id-sdk

Fonctionnalités

  • OAuth 2.0 Authorization Code Flow
  • PKCE (Proof Key for Code Exchange) pour les SPAs
  • Protection CSRF avec paramètre state
  • Refresh tokens avec rotation automatique
  • Révocation de tokens
  • Hook React inclus

Utilisation rapide

Côté Client (SPA)

import { createWebbaID } from 'webba-id-sdk'

const webbaId = createWebbaID({
  appKey: 'wba_votre_app_key',
  redirectUri: 'https://votre-app.com/auth/callback',
  usePKCE: true  // Recommandé pour les SPAs
})

// Rediriger vers la page de connexion
await webbaId.login()

Côté Serveur

import { createWebbaID } from 'webba-id-sdk'

const webbaId = createWebbaID({
  appKey: process.env.WEBBA_APP_KEY!,
  appSecret: process.env.WEBBA_APP_SECRET!,
  redirectUri: process.env.APP_URL + '/auth/callback'
})

// Échanger le code contre des tokens
const tokens = await webbaId.exchangeCode(code, codeVerifier)

// Récupérer les infos utilisateur
const user = await webbaId.getUserInfo(tokens.access_token)

PKCE (Recommandé pour les SPAs)

PKCE protège contre les attaques d'interception de code d'autorisation.

const webbaId = createWebbaID({
  appKey: 'wba_xxx',
  redirectUri: '/auth/callback',
  usePKCE: true
})

// login() génère et stocke automatiquement le code_verifier
await webbaId.login()

// Sur la page de callback
const { code, state } = webbaId.getAuthorizationParams()
const codeVerifier = webbaId.getStoredCodeVerifier()

// Envoyer code + codeVerifier au backend
await fetch('/api/auth/callback', {
  method: 'POST',
  body: JSON.stringify({ code, codeVerifier })
})

Protection CSRF (State)

Le SDK génère et vérifie automatiquement le paramètre state.

// Le state est généré automatiquement
await webbaId.login()

// Sur la page de callback
const { code, state, error } = webbaId.getAuthorizationParams()

// Vérifier le state
if (!webbaId.verifyState(state)) {
  console.error('State invalide - possible attaque CSRF')
  return
}

Refresh Tokens

Les access_tokens expirent après 1 heure. Utilisez le refresh_token pour les renouveler.

// Côté serveur
try {
  const newTokens = await webbaId.refreshToken(refreshToken)

  // IMPORTANT: Le refresh_token est à usage unique (rotation)
  // Stockez toujours le nouveau refresh_token
  saveTokens(newTokens)
} catch (error) {
  // Refresh token expiré ou révoqué
  // Rediriger vers la page de connexion
}

Déconnexion

Révoquez les tokens lors de la déconnexion.

// Déconnexion complète (révoque access + refresh tokens)
await webbaId.logout(accessToken, refreshToken)

// Ou révoquer un token spécifique
await webbaId.revokeToken(accessToken)

Hook React

import { useWebbaID } from 'webba-id-sdk'

function LoginButton() {
  const { login } = useWebbaID({
    appKey: 'wba_xxx',
    redirectUri: '/auth/callback',
    usePKCE: true
  })

  return (
    <button onClick={login}>
      Se connecter avec Webba ID
    </button>
  )
}

function AuthCallback() {
  const { getAuthorizationParams, verifyState, getCodeVerifier } = useWebbaID({
    appKey: 'wba_xxx',
    redirectUri: '/auth/callback',
    usePKCE: true
  })

  useEffect(() => {
    const { code, state, error } = getAuthorizationParams()

    if (error || !verifyState(state)) {
      // Gérer l'erreur
      return
    }

    const codeVerifier = getCodeVerifier()
    // Envoyer au backend...
  }, [])

  return <div>Connexion en cours...</div>
}

API Reference

Configuration

| Option | Type | Requis | Description | |--------|------|--------|-------------| | appKey | string | Oui | Clé publique de l'application (wba_xxx) | | appSecret | string | Serveur | Clé secrète (côté serveur uniquement) | | redirectUri | string | Oui | URL de callback après authentification | | usePKCE | boolean | Non | Active PKCE pour les SPAs (défaut: false) | | baseUrl | string | Non | URL de base Webba ID | | apiUrl | string | Non | URL de l'API Webba ID |

Méthodes

| Méthode | Description | Environnement | |---------|-------------|---------------| | login() | Redirige vers la page de connexion (async, gère PKCE/state) | Client | | getLoginUrl(state?, codeChallenge?) | Retourne l'URL de connexion | Client/Serveur | | getAuthorizationParams() | Récupère code, state, error depuis l'URL | Client | | verifyState(state) | Vérifie le state CSRF | Client | | getStoredCodeVerifier() | Récupère le code_verifier PKCE stocké | Client | | exchangeCode(code, codeVerifier?) | Échange un code contre des tokens | Serveur | | refreshToken(refreshToken) | Rafraîchit l'access_token | Client/Serveur | | revokeToken(token) | Révoque un token | Client/Serveur | | logout(accessToken, refreshToken?) | Révoque tous les tokens | Client/Serveur | | getUserInfo(token) | Récupère les infos utilisateur | Client/Serveur | | getProfile(token) | Récupère le profil complet | Client/Serveur | | updateProfile(token, data) | Met à jour le profil | Client/Serveur | | verifyToken(token) | Vérifie si un token est valide | Client/Serveur |

Types

interface TokenResponse {
  access_token: string
  refresh_token: string
  token_type: string
  expires_in: number
  expires_at: string
  user_id: string
}

interface AuthorizationParams {
  code: string | null
  state: string | null
  error?: string | null
  error_description?: string | null
}

interface WebbaIDUser {
  user_id: string
  email: string
  app_id?: string
  profile?: UserProfile
  subscriptions?: Subscription[]
}

interface FullProfile {
  user_id: string
  email?: string
  email_verified?: boolean
  profile: UserProfile
  subscriptions: Subscription[]
  roles: UserRole[]
}

Exemple complet

Variables d'environnement

# Client (.env)
VITE_WEBBA_APP_KEY=wba_xxx
VITE_APP_URL=https://votre-app.com

# Serveur (.env)
WEBBA_APP_KEY=wba_xxx
WEBBA_APP_SECRET=wbs_xxx
APP_URL=https://votre-app.com

Frontend (React)

// src/pages/Login.tsx
import { useWebbaID } from 'webba-id-sdk'

export function Login() {
  const { login } = useWebbaID({
    appKey: import.meta.env.VITE_WEBBA_APP_KEY,
    redirectUri: import.meta.env.VITE_APP_URL + '/auth/callback',
    usePKCE: true
  })

  return (
    <button onClick={login}>
      Se connecter avec Webba ID
    </button>
  )
}

// src/pages/AuthCallback.tsx
import { useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
import { useWebbaID } from 'webba-id-sdk'

export function AuthCallback() {
  const navigate = useNavigate()
  const { getAuthorizationParams, verifyState, getCodeVerifier } = useWebbaID({
    appKey: import.meta.env.VITE_WEBBA_APP_KEY,
    redirectUri: import.meta.env.VITE_APP_URL + '/auth/callback',
    usePKCE: true
  })

  useEffect(() => {
    const { code, state, error } = getAuthorizationParams()

    if (error) {
      navigate('/login?error=' + error)
      return
    }

    if (!verifyState(state)) {
      navigate('/login?error=invalid_state')
      return
    }

    const codeVerifier = getCodeVerifier()

    fetch('/api/auth/callback', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ code, codeVerifier })
    })
      .then(res => res.ok ? navigate('/dashboard') : navigate('/login?error=auth_failed'))
      .catch(() => navigate('/login?error=network_error'))
  }, [])

  return <div>Connexion en cours...</div>
}

Backend (Express)

// server/auth.ts
import { createWebbaID } from 'webba-id-sdk'
import express from 'express'

const app = express()
const webbaId = createWebbaID({
  appKey: process.env.WEBBA_APP_KEY!,
  appSecret: process.env.WEBBA_APP_SECRET!,
  redirectUri: process.env.APP_URL + '/auth/callback'
})

// Callback d'authentification
app.post('/api/auth/callback', async (req, res) => {
  const { code, codeVerifier } = req.body

  try {
    const tokens = await webbaId.exchangeCode(code, codeVerifier)
    const user = await webbaId.getUserInfo(tokens.access_token)

    // Sauvegarder en session/cookie
    req.session.accessToken = tokens.access_token
    req.session.refreshToken = tokens.refresh_token
    req.session.userId = user.user_id

    res.json({ success: true })
  } catch (error) {
    res.status(401).json({ error: 'Authentication failed' })
  }
})

// Middleware pour rafraîchir le token si expiré
app.use(async (req, res, next) => {
  if (!req.session.accessToken) return next()

  const { valid } = await webbaId.verifyToken(req.session.accessToken)

  if (!valid && req.session.refreshToken) {
    try {
      const newTokens = await webbaId.refreshToken(req.session.refreshToken)
      req.session.accessToken = newTokens.access_token
      req.session.refreshToken = newTokens.refresh_token
    } catch {
      // Refresh échoué, déconnecter
      req.session.destroy()
      return res.status(401).json({ error: 'Session expired' })
    }
  }

  next()
})

// Déconnexion
app.post('/api/auth/logout', async (req, res) => {
  const { accessToken, refreshToken } = req.session

  if (accessToken) {
    await webbaId.logout(accessToken, refreshToken)
  }

  req.session.destroy()
  res.json({ success: true })
})

Migration v1 vers v2

Breaking changes

  1. login() est maintenant async

    // v1
    webbaId.login()
    
    // v2
    await webbaId.login()
  2. getCodeFromUrl() est déprécié, utilisez getAuthorizationParams()

    // v1
    const code = webbaId.getCodeFromUrl()
    
    // v2
    const { code, state, error } = webbaId.getAuthorizationParams()
  3. exchangeCode() retourne maintenant aussi refresh_token

    // v1
    const { access_token, user_id } = await webbaId.exchangeCode(code)
    
    // v2
    const { access_token, refresh_token, user_id } = await webbaId.exchangeCode(code, codeVerifier)

Nouvelles fonctionnalités

  • usePKCE: true dans la config pour activer PKCE
  • verifyState(state) pour la protection CSRF
  • getStoredCodeVerifier() pour récupérer le code_verifier PKCE
  • refreshToken(token) pour rafraîchir les tokens
  • revokeToken(token) pour révoquer un token
  • logout(accessToken, refreshToken?) pour la déconnexion

Licence

MIT - Webba Creative Technologies