Autenticación en el navegador

El recorrido completo desde el botón hasta la sesión, con Authorization Code y PKCE.

En el navegador tu aplicación es un cliente público: no tiene ni puede tener un secreto. El flujo es Authorization Code con PKCE, y el SDK lo hace entero.

Crear la instancia

andco.tsts
import { createAndcoInstanceForBrowser } from "@andco/sdk/browser";

export const andco = createAndcoInstanceForBrowser({
  clientId: "tu-client-id",
  redirectTo: "https://tuapp.com/",
  initialScopes: ["openid", "email", "profile"],
});

initialScopes son los que se piden cuando no indicas otros. redirectTo debe coincidir exactamente con la URL registrada.

ts
createAndcoInstanceForBrowser(options: AndcoBrowserOptions): AndcoSessionClient
Opción Por omisión Qué hace
clientId requerido
redirectTo requerido, debe coincidir con la URL registrada
initialScopes scopes pedidos cuando signIn no indica otros
detectSessionInUrl true intercambia el código que la redirección dejó en la URL
relayPopupCallback true entrega el callback al opener cuando este documento es una ventana emergente de Andco
replaceUrl History API cómo se limpia la URL después de consumirla
transactionStorage sessionStorage dónde vive la transacción entre la redirección y la vuelta
presenter browserPresenter() cómo se presenta la autorización
storage sessionStorage dónde vive la sesión
initialSession una sesión ya resuelta, para que el primer cuadro sea real

clientSecret está rechazado por tipos: una credencial confidencial no puede llegar a un navegador. El detalle completo está en la referencia.

Presentar la autorización

Hay dos presentaciones y el SDK usa la primera por omisión.

ts
signIn(options?: AndcoSignInOptions): Promise<Result<AndcoSession | null>>
Opción Qué hace
presentation "popup" (por omisión) o "redirect"
scopes reemplaza a initialScopes para esta autorización
authorizations contribuciones de Resource Server Definitions, compuestas en una sola petición
resource uno o varios Resource Indicators
orgId organización sobre la que se autoriza
authorizationDetails detalles RAR de la petición
redirectTo reemplaza el de la instancia para esta llamada
externalId referencia opaca a un destino, propia del OAuth Client
state correlaciona el callback con una presentación ya abierta

Ventana emergente

ts
const { data: session, error } = await andco.auth.signIn();

El documento no se reemplaza, así que la promesa se resuelve con la sesión. Si la persona cierra la ventana, session es null y error también: cerrar no es un fallo.

Redirección

ts
await andco.auth.signIn({ presentation: "redirect" });

Aquí el documento se reemplaza, así que la promesa no devuelve sesión. El resultado llega en la carga siguiente: al construir la instancia, el SDK reconoce el código en la URL, lo intercambia, guarda la sesión y limpia los parámetros. No tienes que escribir una ruta de callback.

Leer la sesión

ts
// Lectura síncrona: tres estados.
const session = andco.session.getSnapshot();

// Esperar a que termine la carga inicial.
const { error } = await andco.session.ready;

// Observar cambios. Devuelve la función para dejar de observar.
const stop = andco.auth.onChange((session) => render(session));
ts
getSnapshot(): AndcoSession | null | undefined

undefined es Instance Readiness: la carga inicial no ha terminado. No es lo mismo que null, que es "no hay sesión" — tratarlos igual muestra un estado desconectado en cada carga. La lectura nunca dispara la carga por sí sola.

ts
get ready: Promise<Result<void>>

Se resuelve cuando termina la carga inicial. Solo hace falta si lees getSnapshot de forma síncrona antes de eso; el resto del SDK espera la carga por su cuenta.

ts
onChange(listener: (session: AndcoSession | null) => void): () => void

Es lo que conectas a tu framework. Devuelve la función de baja, así que en un efecto es una línea: useEffect(() => andco.auth.onChange(setSession), [andco]).

ts
getSession(): Promise<Result<AndcoSession | null>>

Igual que getSnapshot, pero asíncrono: espera la carga inicial y devuelve un Result en vez de distinguir undefined.

ts
refresh(): Promise<Result<AndcoSession>>

Refresca ahora en vez de esperar a que una petición de token encuentre la sesión vencida. Falla si no hay refreshToken.

Ampliar permisos

Un Grant se amplía pidiendo una autorización nueva con más scopes. La sesión resultante reemplaza a la anterior.

ts
await andco.auth.signIn({ scopes: ["openid", "email", "profile", "bank_accounts:read"] });

Cerrar sesión

ts
signOut(): Promise<Result<void>>
ts
await andco.auth.signOut();

Esto olvida la credencial local. Revocar el Grant en Andco es otra cosa y se hace desde el servidor.

Dónde se guarda

Por omisión, en sessionStorage: la sesión vive mientras viva la pestaña. Si necesitas que sobreviva a un cierre del navegador, entrega tu propio almacenamiento.

ts
import { WebStorage } from "@andco/sdk";

createAndcoInstanceForBrowser({
  clientId,
  redirectTo,
  storage: new WebStorage(window.localStorage),
});

El almacenamiento puede ser asíncrono: el SDK espera sus lecturas, así que un almacén cifrado o remoto también sirve.