Class TokenService

java.lang.Object
com.svenruppert.jsentinel.authentication.TokenService

@ExperimentalJSentinelApi public final class TokenService extends Object
Access + rotating refresh token issuance on top of a RefreshTokenStore.

Three operations:

  1. issue(subject) — issues a fresh TokenService.TokenPair (accessPlain, refreshPlain). Only the refresh token's hash reaches the store; the access token is returned to the caller verbatim and the framework does not persist it (apps that want stateless access tokens hand back a JWT, apps with a session-store cache it themselves).
  2. rotate(refreshPlain) — consumes the old refresh token, marks it replaced, issues a fresh access + refresh pair, emits TokenRotated. Returns empty on every failure mode (unknown, wrong tenant, revoked, replaced, expired) — the caller must not retry with a different reason.
  3. revoke(refreshPlain) — marks a still-active refresh token revoked. No-op when already revoked / replaced / unknown.

Replay defense: when rotate is called with a refresh token that already has replacedByHash, that is a strong signal of replay — the token was already rotated. This service does not by itself chase the full chain (the RefreshTokenStore contract leaves chain-revocation to the application) but it does refuse the request and emits an audit trail through the store's existing state.

Bound to one TenantId at construction.

  • Field Details

    • DEFAULT_TOKEN_BYTES

      public static final int DEFAULT_TOKEN_BYTES
      Default token entropy in bytes (256 bits).
      See Also:
  • Constructor Details

    • TokenService

      public TokenService(RefreshTokenStore store, PasswordHasher hasher, JSentinelAuditService auditService)
      Convenience constructor: tenant TenantId.DEFAULT, system clock, 256-bit token source, 15-min access TTL, 30-day refresh TTL.
      Parameters:
      store - backing store; non-null
      hasher - hasher used to hash refresh tokens; non-null
      auditService - audit sink; non-null
    • TokenService

      public TokenService(RefreshTokenStore store, PasswordHasher hasher, JSentinelAuditService auditService, TenantId tenant, Clock clock, Supplier<String> tokenSource, Duration accessTtl, Duration refreshTtl)
      Full constructor.
      Parameters:
      store - backing store; non-null
      hasher - hasher used to hash refresh tokens; non-null
      auditService - audit sink; non-null
      tenant - tenant scope; null becomes TenantId.DEFAULT
      clock - time source; non-null
      tokenSource - plain-token supplier; non-null
      accessTtl - access-token lifetime; strictly positive
      refreshTtl - refresh-token lifetime; strictly positive
  • Method Details

    • issue

      public TokenService.TokenPair issue(SubjectId subjectId)
      Issues a fresh access + refresh pair. The refresh token is persisted (hash-only); the access token is returned verbatim and not persisted.
      Parameters:
      subjectId - subject the new pair authenticates; non-null
      Returns:
      issued pair
    • rotate

      public Optional<TokenService.TokenPair> rotate(String refreshPlain)
      Rotates the supplied refresh token. The old token is marked replaced; a fresh pair is issued. Returns empty on every failure (unknown, wrong tenant, revoked, replaced, expired).
      Parameters:
      refreshPlain - plain refresh token; null/blank yields empty
      Returns:
      fresh pair on the successful transition
    • revoke

      public boolean revoke(String refreshPlain)
      Marks the refresh token revoked. No-op for unknown / already revoked / replaced / expired tokens.
      Parameters:
      refreshPlain - plain refresh token; null/blank → false
      Returns:
      true when a still-active record was just marked revoked
    • revokeAll

      public int revokeAll(SubjectId subjectId)
      Drops every refresh token issued to subjectId in this service's tenant.
      Parameters:
      subjectId - subject; non-null
      Returns:
      number of records removed
    • purgeExpired

      public int purgeExpired()
      Purges every expired record. Spans all tenants.
      Returns:
      number of records purged