# GSC Auth Token Service

Servicio HTTP para obtener el Bearer token del Portal PAS QA usando el flujo real web B2C/MSAL. El servicio cachea tokens en Redis para responder rapido y permite renovacion forzada cuando hace falta.

## URL

```txt
POST https://gsc-auth.bdtglobal.com/token
```

Para ver este instructivo desde navegador:

```txt
GET https://gsc-auth.bdtglobal.com/token
```

## Obtener Token

Enviar usuario y password en JSON:

```bash
curl -X POST "https://gsc-auth.bdtglobal.com/token" \
  -H "Content-Type: application/json" \
  -d '{"username":"TU_USUARIO","password":"TU_PASSWORD"}'
```

Tambien acepta `userName`:

```json
{
  "userName": "TU_USUARIO",
  "password": "TU_PASSWORD"
}
```

Respuesta exitosa:

```json
{
  "tokenType": "Bearer",
  "token": "eyJ...",
  "length": 1661,
  "validationStatus": 200,
  "source": "cache",
  "cachedAt": "2026-06-04T23:57:24.152Z",
  "expiresAt": "2026-06-05T00:57:23.000Z",
  "secondsUntilExpiry": 3589,
  "elapsedMs": 2
}
```

Usar el valor de `token` como:

```txt
Authorization: Bearer <token>
```

## Renovar Forzado

Para ignorar Redis, hacer login nuevamente contra B2C y guardar el token nuevo en Redis:

```bash
curl -X POST "https://gsc-auth.bdtglobal.com/token?renew=true" \
  -H "Content-Type: application/json" \
  -d '{"username":"TU_USUARIO","password":"TU_PASSWORD"}'
```

Tambien se puede enviar `renew` en el body:

```json
{
  "username": "TU_USUARIO",
  "password": "TU_PASSWORD",
  "renew": true
}
```

Cuando se renueva forzado, `source` devuelve:

```json
{
  "source": "renew"
}
```

La llamada con `renew=true` tarda mas porque abre el flujo B2C. Las llamadas siguientes vuelven a salir desde Redis.

## Cache Redis

El token se cachea por hash de:

```txt
PORTAL_URL + username + password
```

No se guarda el password en Redis. Redis guarda el token y metadatos de vencimiento.

Valores configurados:

```txt
TOKEN_REFRESH_INTERVAL_SECONDS=300
TOKEN_REFRESH_BEFORE_EXPIRY_SECONDS=900
TOKEN_CACHE_MIN_VALID_SECONDS=300
```

Esto significa:

- Cada 5 minutos se revisa el token cacheado.
- Solo se renueva automaticamente si faltan 15 minutos o menos para vencer.
- Si todavia esta vigente, no hace login innecesario.

## Estados de `source`

```txt
cache  -> respondio desde Redis
login  -> no habia cache usable y tuvo que loguear
renew  -> se forzo renovacion con renew=true
```

## Errores Comunes

Faltan credenciales:

```json
{
  "error": "missing_credentials",
  "message": "Envia username/password en el body o configura PORTAL_USER/PORTAL_PASSWORD en .env."
}
```

Hay otro login en curso:

```json
{
  "error": "busy",
  "message": "Ya hay un login o refresh en curso. Reintenta en unos segundos."
}
```

Error de login/B2C:

```json
{
  "error": "token_error",
  "message": "..."
}
```

## Health

Si el proxy lo expone:

```bash
curl "https://gsc-auth.bdtglobal.com/health"
```

Respuesta:

```json
{
  "ok": true,
  "redisReady": true,
  "cacheEnabled": true,
  "inFlight": 0,
  "refreshIntervalSeconds": 300,
  "refreshBeforeExpirySeconds": 900
}
```

## Ambiente

Actualmente apunta a Portal PAS QA:

```txt
PORTAL_URL=https://portalpas-qa.sancristobalonline.com.ar/inicio
VERIFY_URL=https://api-qa.sancristobalonline.com.ar/portalpas/api/user/role
```

## Administracion Docker

En el servidor:

```bash
cd ~/portalpas-token-server
docker compose -p portalpas-token-server ps
docker compose -p portalpas-token-server logs -f
docker compose -p portalpas-token-server down
docker compose -p portalpas-token-server up -d --build
```

Servicios del proyecto:

```txt
portalpas-token-server-portalpas-token-1
portalpas-token-server-redis-1
```

Redis es interno del Compose y no publica puerto externo.
