Class SignedTokens

java.lang.Object
com.codename1.backend.security.crypto.SignedTokens

public final class SignedTokens extends Object

Makes and checks the tokens a server mails out: the link that confirms an address, the link that resets a password, an invitation. A token names its subject and when it stops working, is signed with HMAC-SHA256, and needs no table: whoever comes back with one that verifies was sent it.

SignedTokens tokens = new SignedTokens(secret);          // 32 random bytes, kept
String link = "/reset?token=" + tokens.create("password-reset", user.getId(), 3600,
        user.getPasswordHash());
// later, from the link:
String userId = tokens.verify("password-reset", token, user.getPasswordHash());

Two things keep a token to the one job it was made for.

  • The purpose is part of what is signed, so a token made to confirm an address is not one that resets a password, though the same secret signed both.
  • The fingerprint, when one is given, is something that changes once the token has done its work: the password hash for a reset link, the address for a confirmation. It is signed and not carried, and the token stops verifying the moment the value moves on -- which is what makes a reset link single-use without a table of used ones. Where the subject has to be known to look the fingerprint up, subject(String) reads it out of a token that has not been checked yet.

The token is opaque to whoever holds it, and not secret from them: the subject is readable. Do not put in it what its holder should not see.

  • Constructor Summary

    Constructors
    Constructor
    Description
    SignedTokens(byte[] secret)
     
  • Method Summary

    Modifier and Type
    Method
    Description
    create(String purpose, String subject, long ttlSeconds)
    A token for subject that works for ttlSeconds.
    create(String purpose, String subject, long ttlSeconds, String fingerprint)
    A token for subject that works for ttlSeconds, and only while fingerprint is what it is now.
    void
    setClock(Clock clock)
    Reads the time from clock instead of the machine.
    static String
    subject(String token)
    The subject a token names, read without checking anything.
    verify(String purpose, String token)
    The subject of token, when it was made by this secret for this purpose and has not expired; null otherwise.
    verify(String purpose, String token, String fingerprint)
    The subject of token, when it was made by this secret for this purpose while the fingerprint was fingerprint, and has not expired; null otherwise.

    Methods inherited from class Object

    clone, equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Constructor Details

    • SignedTokens

      public SignedTokens(byte[] secret)
      Parameters:
      secret - at least 32 bytes that stay the same for as long as the tokens are to verify; Crypto.randomBytes(32), stored
  • Method Details

    • setClock

      public void setClock(Clock clock)
      Reads the time from clock instead of the machine.
    • create

      public String create(String purpose, String subject, long ttlSeconds)
      A token for subject that works for ttlSeconds.
    • create

      public String create(String purpose, String subject, long ttlSeconds, String fingerprint)
      A token for subject that works for ttlSeconds, and only while fingerprint is what it is now.
    • verify

      public String verify(String purpose, String token)
      The subject of token, when it was made by this secret for this purpose and has not expired; null otherwise.
    • verify

      public String verify(String purpose, String token, String fingerprint)
      The subject of token, when it was made by this secret for this purpose while the fingerprint was fingerprint, and has not expired; null otherwise. Why a token is refused is not said: whoever presents a bad one learns nothing from the answer.
    • subject

      public static String subject(String token)
      The subject a token names, read without checking anything. For finding the record whose fingerprint verify(String, String) then needs -- never for deciding anything: this is what the bearer wrote, until verify says otherwise.
      Returns:
      the subject, or null when token does not have a token's shape