Sistema de Autenticación

Cannahub utiliza un sistema de autenticación avanzado basado en JWT tokens con soporte para múltiples roles de usuario y arquitectura multi-tenant. Esta guía explica cómo funciona la autenticación y cómo implementar diferentes flujos de acceso.

Arquitectura de Autenticación

Cannahub implementa un sistema de autenticación de múltiples capas que soporta diferentes tipos de usuarios y organizaciones:

Flujo de Autenticación

Loading diagram...

Tipos de Autenticación por Rol

1. Autenticación de Miembros (Customers)

Los miembros utilizan el flujo estándar de registro y login:

Login de Miembro

POST
/auth/customer/emailpass
curl -X POST https://api.cannahub.tech/auth/customer/emailpass \
  -H "Content-Type: application/json" \
  -d '{
    "email": "miembro@ejemplo.com",
    "password": "contraseña_segura"
  }'

2. Autenticación de Administradores

Los administradores y staff utilizan un endpoint separado:

Login de Admin

POST
/auth/user/emailpass
curl -X POST https://api.cannahub.tech/auth/user/emailpass \
  -H "Content-Type: application/json" \
  -d '{
    "email": "admin@club.com",
    "password": "admin_password"
  }'

Gestión de Tokens JWT

Estructura de Tokens

Cannahub utiliza dos tipos de tokens JWT almacenados como cookies HTTP-only:

Configuración de Tokens

{
  "adminToken": {
    "name": "cannahubAdminToken",
    "expires": 604800,  // 7 días en segundos
    "httpOnly": true,
    "secure": true,
    "sameSite": "lax"
  },
  "memberToken": {
    "name": "cannahubToken", 
    "expires": 604800,  // 7 días en segundos
    "httpOnly": true,
    "secure": true,
    "sameSite": "lax"
  }
}

Payload del Token

Estructura del JWT

{
  "sub": "user_id_123",
  "email": "usuario@ejemplo.com",
  "role": "member",
  "organization": "high-up",
  "iat": 1634567890,
  "exp": 1635172690
}

Roles de Usuario y Permisos

Jerarquía de Roles

{
  "root": {
    "level": 0,
    "description": "Super administrador de plataforma",
    "access": "Acceso completo a todas las funcionalidades"
  },
  "admin": {
    "level": 1,
    "description": "Administrador de club",
    "access": "Gestión de miembros, pedidos, productos y analytics"
  },
  "doctor": {
    "level": 2,
    "description": "Profesional médico",
    "access": "Gestión de pacientes, prescripciones y consultas"
  },
  "member": {
    "level": 3,
    "description": "Miembro del club",
    "access": "Acceso al dispensario, crear pedidos, actualizar perfil"
  }
}

Middleware de Protección de Rutas

El middleware de Next.js intercepta todas las solicitudes antes de que lleguen a las páginas, validando autenticación, organización y permisos.

Diagrama del Middleware

Loading diagram...

Rutas Excluidas de Autenticación

Las siguientes rutas no requieren autenticación:

Rutas Públicas

const excludedPaths = [
  '/login',
  '/register',
  '/onboarding',
  '/forgot-password',
  '/api/health',
  '/_next',
  '/favicon.ico',
  '/images',
]

Validación en el Middleware

Middleware de Autenticación

export async function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl
  
  // 1. Validación de organización
  const organization = extractOrganization(request)
  if (!organization || !isValidOrganization(organization)) {
    return redirectTo404(request)
  }
  
  // 2. Extracción de tokens
  const memberToken = request.cookies.get('cannahubToken')?.value
  const adminToken = request.cookies.get('cannahubAdminToken')?.value
  
  // 3. Rutas excluidas de autenticación
  if (isExcludedPath(pathname)) {
    return NextResponse.next()
  }
  
  // 4. Validación de tokens
  const token = adminToken || memberToken
  if (!token) {
    return redirectToLogin(request, organization)
  }
  
  // 5. Verificación del perfil
  const profile = await verifyTokenAndGetProfile(token)
  if (!profile) {
    return redirectToLogin(request, organization)
  }
  
  // 6. Verificación de completitud del perfil
  if (!profile.isComplete) {
    return redirectToOnboarding(request, organization)
  }
  
  // 7. Control de acceso basado en roles
  if (!hasPermission(profile.role, pathname)) {
    return redirectToUnauthorized(request)
  }
  
  return NextResponse.next()
}

Integración Multi-Tenant

Header tenant-id para Medusa

Todas las requests a la API de Medusa que pasan por el BFF deben incluir el header tenant-id para aislar datos por organización. El BFF lo inyecta automáticamente desde la sesión del usuario.

Ejemplo con tenant-id

# El BFF agrega este header automáticamente a las llamadas a Medusa
curl https://api.cannahub.tech/admin/products \
  -H "Authorization: Bearer {admin_token}" \
  -H "tenant-id: high-up"

Validación de Organización

Validación de Organización

const supportedOrganizations = [
  'high-up',
  'don-marcelino',
  'circulo-rojo',
  'superfly',
  'blow',
  'weplant'
]

function extractOrganization(request: NextRequest): string | null {
  // Extraer de subdomain, header, o path
  const host = request.headers.get('host')
  const subdomain = host?.split('.')[0]

  if (supportedOrganizations.includes(subdomain)) {
    return subdomain
  }

  // Fallback a path-based org
  const pathOrg = request.nextUrl.pathname.split('/')[1]
  return supportedOrganizations.includes(pathOrg) ? pathOrg : null
}

Seguridad y Mejores Prácticas

Características de Seguridad

  • Cookies HTTP-Only: Previenen ataques XSS al no permitir acceso desde JavaScript
  • Protección CSRF: Integrada en Next.js
  • Expiración de Tokens: Los tokens expiran después de 7 días
  • Aislamiento Multi-Tenant: Separación completa de datos por organización
  • Control de Acceso por Roles: Acceso basado en el rol del usuario

Comportamiento de Sesión

Cuando un token expira después de 7 días:

  1. El usuario es redirigido automáticamente a /login
  2. Las cookies de sesión son eliminadas
  3. El usuario debe volver a iniciar sesión para continuar

Variables de Entorno de Seguridad

Configuración de Seguridad

# JWT Configuration
JWT_SECRET=tu_clave_secreta_muy_larga_y_segura
COOKIE_DOMAIN=.tudominio.com

# Session Configuration
SESSION_TIMEOUT=604800  # 7 días en segundos

# Security Headers
FORCE_HTTPS=true
SECURE_COOKIES=true
SAME_SITE_POLICY=lax

# Development Override (NUNCA en producción)
BYPASS_AUTH=false

Manejo de Errores de Autenticación

Códigos de Error Comunes

Respuestas de Error

{
  "unauthorized": {
    "code": 401,
    "message": "Credenciales inválidas o token expirado",
    "action": "Redirigir a /login"
  },
  "forbidden": {
    "code": 403,
    "message": "No tienes permiso para acceder a este recurso",
    "action": "Mostrar página de acceso denegado"
  },
  "profile_incomplete": {
    "code": 302,
    "message": "Perfil incompleto",
    "action": "Redirigir a /onboarding"
  }
}

Testing y Desarrollo

Modo de Desarrollo (Mock Mode)

Para facilitar el desarrollo, Cannahub incluye un modo mock completo que bypassa la autenticación y utiliza datos de prueba. Se activa con la variable NEXT_PUBLIC_MOCKED:

Variables de Desarrollo

# Solo para desarrollo local
NEXT_PUBLIC_MOCKED=true

# Auth bypass (requiere IS_MOCKED=true)
BYPASS_AUTH=true
IS_MOCKED=true

Cuando NEXT_PUBLIC_MOCKED=true:

  • Todas las rutas API (/api/*) utilizan datos mock en lugar de llamar a Medusa/Strapi
  • Se utiliza un usuario mock predefinido con rol configurable
  • Las rutas protegidas son accesibles sin login real
  • Los datos no se persisten entre reinicios del servidor

Recuperación de Contraseña

Actualmente no existe un flujo de recuperación de contraseña self-service. Si un usuario olvida su contraseña:

  1. Debe contactar al administrador del club
  2. El administrador puede resetear la contraseña desde el panel de gestión de miembros
  3. El usuario recibirá instrucciones para establecer una nueva contraseña

La implementación del sistema de autenticación de Cannahub proporciona seguridad robusta mientras mantiene la flexibilidad necesaria para soportar múltiples organizaciones y roles de usuario complejos.

Was this page helpful?