@isaias_pv/custos-sdk
v1.5.0
Published
Official JavaScript SDK for Custos authentication
Downloads
78
Maintainers
Readme
Custos SDK
SDK oficial de JavaScript/TypeScript para autenticacion con Custos usando OAuth 2.0 + PKCE.
Contenido
- Instalacion
- Requisitos
- Exportaciones publicas
- Inicio rapido
- Flujo recomendado
- Configuracion
- API de Custos
- Eventos
- Tipos principales
- Utilidades exportadas
- Storage interno
- Endpoints usados por el SDK
- Ejemplos por framework
- Buenas practicas
- Solucion de problemas
Instalacion
npm install @isaias_pv/custos-sdkRequisitos
- Entorno browser moderno (usa Web Crypto API)
- Backend Custos accesible desde el frontend
- Aplicacion OAuth registrada con:
- client_id valido
- redirect_uri permitido
- PKCE habilitado (recomendado)
Exportaciones publicas
El paquete exporta:
CustosStorageApiClient- Todos los tipos de
src/types.ts - Todas las utilidades de
src/utils.ts
Inicio rapido
import { Custos } from '@isaias_pv/custos-sdk';
const auth = new Custos({
clientId: 'my-client-id',
redirectUri: window.location.origin + '/auth/callback',
apiUrl: 'https://custos.alimzen.com',
scope: 'openid profile email',
usePKCE: true,
useSessionStorage: false,
});Login
await auth.login();Callback
if (auth.hasCallbackParams()) {
await auth.handleCallback();
}Recuperar sesion al iniciar app
const restored = await auth.silentAuth();
if (!restored) {
// mostrar vista de login
}Logout
await auth.logout();Revocar tokens + limpiar sesion
await auth.revoke({ accessToken: true, refreshToken: true });Flujo recomendado
- Crear instancia de
Custosal iniciar app. - Registrar listeners con
on(...). - Al entrar a callback, verificar
hasCallbackParams()y llamarhandleCallback(). - En arranque de app, llamar
silentAuth()para restaurar sesion. - Usar
getAccessToken()para requests autenticados. - Cerrar sesion con
logout()orevoke().
Configuracion
Interfaz CustosConfig:
clientId: string(requerido)redirectUri: string(requerido)clientSecret?: string(solo si tu flujo lo requiere)apiUrl?: stringdefault:https://custos.alimzen.comscope?: string | string[]default:openid profileresponseType?: 'code' | 'token'default:codestate?: stringdefault: generado aleatoriamenteusePKCE?: booleandefault:truecodeChallengeMethod?: 'S256' | 'plain'default:S256grantType?: 'authorization_code' | 'refresh_token' | 'client_credentials'default:authorization_codeuseSessionStorage?: booleandefault:false(usa localStorage)
API de Custos
Constructor
new Custos(config: CustosConfig)Metodos de autenticacion
login(additionalParams?: Record<string, string>): Promise<void>
handleCallback(): Promise<void>
logout(): Promise<void>
refreshToken(): Promise<void>
revoke(options?: { accessToken?: boolean; refreshToken?: boolean }): Promise<void>
silentAuth(): Promise<boolean>
validateToken(): Promise<boolean>Estado y usuario
isAuthenticated(): boolean
getState(): AuthState
getUser(): User | null
getAccessToken(): string | null
getRefreshToken(): string | null
getTokenExpiry(): Date | null
hasCallbackParams(): booleanEventos
on(event: AuthEventType, callback: (event: AuthEvent) => void): void
off(event: AuthEventType, callback: (event: AuthEvent) => void): voidUtilidades de ciclo de vida
clearStorage(): void
destroy(): voidEventos
AuthEventType soportados:
loginlogouterrortoken-refreshtoken-expiredsession-restored
Ejemplo:
auth.on('login', (event) => {
console.log('Login:', event.data.user);
});
auth.on('token-refresh', (event) => {
console.log('Nuevo token:', event.data.accessToken);
});
auth.on('session-restored', (event) => {
console.log('Sesion restaurada:', event.data.user);
});
auth.on('error', (event) => {
console.error('Auth error:', event.data);
});Tipos principales
AuthTokens
interface AuthTokens {
accessToken: string;
refreshToken?: string;
tokenType: string;
expiresIn: number;
scope?: string;
}User
interface User {
id: string;
email: string;
username?: string;
name?: string;
firstName?: string;
lastName?: string;
picture?: string;
emailVerified?: boolean;
isVerified?: boolean;
isMfaEnabled?: boolean;
roles?: { tenantId: string; tenantSlug?: string; role: string }[];
permissions?: string[];
[key: string]: any;
}AuthState
interface AuthState {
isAuthenticated: boolean;
user: User | null;
tokens: AuthTokens | null;
tokenExpiry: Date | null;
}Utilidades exportadas
Desde utils:
generateState(): stringgenerateCodeVerifier(): stringgenerateCodeChallenge(codeVerifier: string): Promise<string>parseQueryString(url: string): Record<string, string>normalizeScope(scope?: string | string[]): stringisValidUrl(url: string): booleannormalizeUrl(url: string): stringisTokenExpired(token: string): booleandecodeToken(token: string): any
Storage interno
La clase Storage persiste con prefijo custos_:
custos_tokenscustos_token_issued_atcustos_usercustos_oauth_statecustos_code_verifiercustos_code_challenge
Si useSessionStorage es true, usa sessionStorage; en caso contrario, localStorage.
Endpoints usados por el SDK
ApiClient consume:
POST /api/v1/auth/token(code exchange + refresh)GET /api/v1/auth/validatePOST /api/v1/auth/logoutPOST /api/v1/auth/revokeGET /api/v1/system/users/profile
Notas:
- El SDK soporta respuestas
204 No Content. - Si la respuesta exitosa no es JSON, el request retorna
undefined.
Ejemplos por framework
- Angular:
examples/angular.md - React:
examples/react.md - Vue 3:
examples/vue.md - Browser standalone:
examples/web-login.html
Buenas practicas
- Mantener
usePKCE: true. - Usar
responseType: 'code'. - Llamar
destroy()al desmontar componentes/paginas. - Escuchar
token-expiredyerrorpara manejo UX. - Usar
silentAuth()en bootstrap de app para evitar flicker de login.
Solucion de problemas
Invalid state parameter
Causas comunes:
- Se perdio
custos_oauth_stateantes del callback. - Se abrio callback en otra pestana/sesion.
- Se reutilizo un link viejo de callback.
Code verifier not found
Causas comunes:
- PKCE habilitado pero no se preservo
custos_code_verifier. - Limpieza de storage antes de
handleCallback().
No refresh token available
Causas comunes:
- El servidor no devolvio refresh token.
- El token fue limpiado o sobrescrito.
Login redirige pero no autentica
Checklist:
- Verificar
redirectUriexacto registrado en el backend. - Confirmar que se llama
handleCallback()solo en ruta callback. - Revisar listener de
errorpara detalle del fallo.
Licencia
MIT
