Casos de uso
Revocar, renovar y gestionar el vencimiento
Corta el acceso, extiende un plazo sin una clave nueva y conoce exactamente qué ve la aplicación al vencer, durante la gracia y tras la revocación — además de en qué se diferencia de una instancia autoalojada que se licencia a sí misma.
Objetivo. Necesitas terminar el acceso de un cliente ahora mismo (una devolución de cargo, un abuso, una emisión por error), extender el plazo de un cliente que paga sin reemitir su clave, y entender con precisión qué muestra la aplicación en ejecución a medida que un plazo se agota.
Cuándo usarlo
- Úsalo si vendes licencias por plazo (anuales/suscripción) y las renuevas, o si alguna vez necesitas revocar una clave.
- Úsalo si estás decidiendo con qué agresividad fallar — con qué rapidez una revocación o un vencimiento alcanza a una máquina que ahora está offline.
- No lo uses si solo distribuyes licencias perpetuas que nunca vencen y nunca se revocan — entonces esta página es solo la vía de revocación «de emergencia». Mover un puesto entre máquinas es activación y desactivación, no revocación.
Dos ciclos de vida comparten esta página y no deben confundirse. El ciclo de vida de la licencia del cliente (las claves de tus usuarios finales) se comporta igual tanto si usas Cloud como autoalojado. El ciclo de vida de la instancia autoalojada es algo distinto — la propia clave de la instancia que le otorga el derecho a ejecutarse — y se trata al final y en Licenciamiento y ediciones.
Qué haces tú (lado del proveedor)
Las tres acciones vuelven a firmar la licencia en el servidor; el cliente conserva la misma clave y simplemente se reactiva (normalmente de forma automática al arrancar) para recoger el cambio.
Revocar — cortar una clave:
curl -X POST $BASE/admin/licenses/LIC-…/revoke -H "X-Admin-Token: $TOKEN"
# the dashboard's per-row Revoke action does the same. Many at once: POST /admin/licenses/bulk-revoke
Renovar / extender un plazo — aleja el vencimiento (y opcionalmente cambia los puestos), sin clave nueva:
curl -X POST $BASE/admin/licenses/LIC-…/renew -H "X-Admin-Token: $TOKEN" -H "content-type: application/json" \
-d '{"expiryUtc":"2028-10-12T00:00:00Z"}'
# seats can be changed here too; a renewal re-signs the license in place. The key is unchanged.
Ambas viven en la propia página de la licencia: Renew (renovar) está en la fila de acciones y Revoke (revocar) está en la Danger zone (zona de peligro).
El vencimiento es simplemente la llegada del expiryUtc de la licencia sin renovación — tú no haces nada; el comportamiento descrito abajo se activa por sí solo. (Un reembolso/cancelación desde un webhook de tienda revoca automáticamente — consulta Emitir claves automáticamente desde una tienda.)
Cada estado de este ciclo de vida se muestra en la lista de Licenses, para que detectes de un vistazo una clave revocada, vencida o a punto de vencer:
LicenseInfo.Status.Con qué rapidez un cambio llega a la máquina
Una revocación o una renovación se aplica en la siguiente comprobación en línea del dispositivo, porque entre comprobaciones la aplicación funciona offline contra un lease en caché. El TTL del lease (por defecto 14 días, KEYRIGHT_LEASE_TTL_DAYS) es exactamente el mando de control: una aplicación conectada que se reactiva al arrancar recoge una revocación dentro de su cadencia de renovación; una máquina que ha estado offline no la verá hasta que vuelva, y no más tarde de cuando expire su ventana de gracia del lease y se vea obligada a volver a comprobar. Acorta el TTL para que las revocaciones y los cambios de puestos surtan efecto antes, a costa de menos tolerancia offline. Para la aplicación offline sin ninguna red, distribuye una lista de revocación firmada con tu compilación (RevocationListJson / RevocationListPath) para que una aplicación puramente offline siga respetando una revocación.
En tu código
Tu aplicación lo lee todo desde LicenseInfo — nunca analiza una clave. Los miembros relevantes, en cada SDK y por HTTP en bruto:
.NET
LicenseInfo info = await License.ActivateAsync(key, ct); // or License.Validate() offline; both fail closed
// Status is the single source of truth — branch on it.
switch (info.Status)
{
case LicenseStatus.Valid: break; // licensed; fall through to the badge below
case LicenseStatus.Expired: return ShowRenewPrompt(info.Message); // term ended, or trial over
case LicenseStatus.Revoked: return ShowUnlicensed(info.Message); // key was revoked
default: return ShowUnlicensed(info.Message); // NoLicense, SeatLimit, SignatureInvalid, …
}
// While valid, surface the countdown and nudge before renewal.
if (info.IsExpiringSoon()) // true inside the renewal window
ShowRenewBanner($"{info.DaysRemaining} days left"); // DaysRemaining counts down to expiryUtc
string badge = info.ExpiryUtc is null
? "Licensed — perpetual" // no expiry
: $"Licensed — expires {info.ExpiryUtc:d}";
Node.js
const { info } = license.validate(); // or: info = await license.activate(key)
switch (info.status) {
case 'valid': break; // licensed
case 'expired': return showRenewPrompt(info.message); // term ended, or trial over
case 'revoked': return showUnlicensed(info.message); // key was revoked
default: return showUnlicensed(info.message); // no_license, machine_mismatch, …
}
if (info.daysRemaining != null && info.daysRemaining <= 14) // nudge before renewal
showRenewBanner(`${info.daysRemaining} days left`);
const badge = info.expiryUtc ? `Licensed — expires ${info.expiryUtc.toLocaleDateString()}`
: 'Licensed — perpetual';
Python
info = license.validate_info() # or: info = license.activate(key)
if info.status == LicenseStatus.VALID:
pass # licensed
elif info.status == LicenseStatus.EXPIRED:
return show_renew_prompt(info.message) # term ended, or trial over
elif info.status == LicenseStatus.REVOKED:
return show_unlicensed(info.message) # key was revoked
else:
return show_unlicensed(info.message) # NO_LICENSE, MACHINE_MISMATCH, …
if info.days_remaining is not None and info.days_remaining <= 14:
show_renew_banner(f"{info.days_remaining} days left")
badge = "Licensed — perpetual" if info.expiry_utc is None else f"Licensed — expires {info.expiry_utc:%x}"
Java
LicenseInfo info = client.validateInfo(); // or: info = client.activate(key)
switch (info.status) {
case VALID: break; // licensed
case EXPIRED: return showRenewPrompt(info.message); // term ended, or trial over
case REVOKED: return showUnlicensed(info.message); // key was revoked
default: return showUnlicensed(info.message); // NO_LICENSE, MACHINE_MISMATCH, …
}
if (info.isExpiringSoon(14)) // nudge before renewal
showRenewBanner(info.daysRemaining() + " days left");
String badge = info.expiryUtc == null ? "Licensed — perpetual"
: "Licensed — expires " + info.expiryUtc;
Cualquier lenguaje (HTTP en bruto)
curl -s -X POST "$BASE/v1/validate" -H "content-type: application/json" \
-d '{"key":"LIC-…","machineId":"<stable-machine-id>","product":"acme-app"}'
# status "revoked" -> drop to Free; "expired" -> prompt to renew; "ok" -> verify the lease and read
# licenseExpiryUtc for the countdown. Fail closed on anything but a valid, in-date lease.
Qué expone cada uno a medida que el plazo se agota:
DaysRemaininghace la cuenta atrás hastaexpiryUtc;IsExpiringSoon()pasa a verdadero dentro de la ventana de renovación, para que puedas avisar antes de que termine el acceso.- Al vencer o tras una revocación,
IsPaidpasa afalsey la aplicación baja a su estado Free/sin licencia — Keyright falla de forma cerrada, no lanza excepciones.Statuste dice cuál es el caso (Expiredfrente aRevoked) para que puedas redactar el aviso («renueva» frente a «contáctanos»). - Tras una renovación, el siguiente
ActivateAsync/Validate()devuelve elExpiryUtcposterior — sin reintroducir la clave, sin diálogo de reactivación.
No hay una «ventana de gracia» en la aplicación para una licencia por plazo: en el momento en que pasa expiryUtc (y la máquina vuelve a validar), la aplicación está en Expired. La ventana de 14 días del lease es un colchón de conectividad — permite que una máquina funcione offline contra un plazo todavía válido — no una gracia adicional después de que termine el plazo pagado. Si quieres que las versiones antiguas sigan funcionando tras caducar una suscripción, eso es la suscripción con fallback de la cobertura de versiones, no una gracia de vencimiento.
Los consumidores de HTTP en bruto ven el mismo ciclo de vida a través del campo status de /v1/validate (revoked, expired) y el licenseExpiryUtc del lease — verifica el lease y falla de forma cerrada ante cualquier cosa que no sea un lease válido y vigente, como en Usar la API HTTP directamente.
El ciclo de vida de la licencia del cliente frente al ciclo de vida de la instancia autoalojada
Son dos claves distintas con reglas distintas. Mantenlas separadas:
| Licencia del cliente (tus usuarios finales) | Licencia de la instancia autoalojada (tu propia clave) | |
|---|---|---|
| De quién | Las claves de tus clientes, emitidas por ti | El derecho de tu instancia a ejecutarse, emitido por Delta1 |
| Se aplica a | Cloud y autoalojado por igual | Solo autoalojado |
| Gracia al vencer | Ninguna — Expired en el momento en que pasa el plazo | De pago: 15 días de gracia de solo lectura tras el vencimiento; prueba: ninguna |
| Al detenerse | La aplicación falla de forma cerrada a Free | La instancia se bloquea — 402 en la mayoría de rutas; los endpoints de estado siguen activos |
| Lo controlas con | /revoke, /renew, expiryUtc | Sustituir KEYRIGHT_SELF_LICENSE + reiniciar |
Todo lo que hay por encima de la tabla es el ciclo de vida del cliente — idéntico en Cloud y autoalojado. La propia clave de la instancia es otra historia: un despliegue autoalojado se licencia a sí mismo, una instancia de pago obtiene 15 días de gracia de solo lectura tras su propio vencimiento antes de bloquearse, y una instancia de prueba se detiene en el momento en que vence. Ese ciclo de vida — instalar, renovar, el campo phase de /admin/self-license y qué significa «bloqueada» — se trata por completo en Licenciamiento y ediciones. No confundas que caduque la suscripción de un cliente (su aplicación pasa a Free) con que caduque la licencia de tu instancia (todo tu servicio de emisión pasa a solo lectura y luego se detiene).
Cloud frente a autoalojado
$BASE/$TOKEN. Cloud:https://keyright.delta1labs.com+ un token de sesión. Autoalojado: la URL de tu instancia +KEYRIGHT_ADMIN_TOKEN.- Revocar, renovar y el vencimiento de las licencias de clientes son idénticos en ambos modos — mismos endpoints, mismo comportamiento del SDK.
- El TTL del lease lo ajustas tú en una instancia autoalojada (
KEYRIGHT_LEASE_TTL_DAYS); en Cloud es el valor predeterminado del servicio. - El ciclo de vida de la instancia solo existe en autoalojado (ver arriba).
Verificar
- Emítete una clave por plazo que venza en uno o dos días; actívala. La insignia muestra el vencimiento y
DaysRemaining. - Revócala, reconecta y deja que el lease se renueve (o llama a
ActivateAsync): la aplicación baja a Free conStatus == Revoked. - Emite una clave nueva, actívala y luego renuévala a una fecha posterior; reactiva —
ExpiryUtcse aleja, misma clave, sin diálogo. - Deja que una clave de plazo corto venza y revalida:
Status == Expired,IsPaid == false, aparece el aviso de renovación. - Temporización offline: revoca una clave mientras esa máquina está offline — confirma que sigue funcionando hasta que reconecta (o hasta que termina su ventana de lease) y entonces baja a Free. Acorta
KEYRIGHT_LEASE_TTL_DAYSsi te parece demasiado lento.
Véase también
- Activación y desactivación — leases, ventanas de gracia, mover puestos entre máquinas.
- Seguridad y el modelo de leases — por qué una revocación no puede editarse para eludirla y cómo el TTL del lease gobierna la propagación.
- Emitir claves automáticamente desde una tienda — reembolsos que revocan automáticamente.
- Licenciamiento y ediciones — el ciclo de vida de la propia licencia de la instancia autoalojada.
- Cobertura de versiones — mantener ejecutables las versiones antiguas tras caducar una suscripción.