MortalToken, because some tokens shouldn’t live forever

MortalToken is a library for creating tokens that self-destruct after a specified time. No need to store and look up the token; it is self-verifying and self-expiring.

The default lifespan is two of your Earth days. This does not mean “48 hours from when it was created”. It means that the key will be valid throughout “today” and “tomorrow”. If the lifespan were one day, a key created at 23:59 would expire in one minute at 00:00.

My original use case was login auth tokens for some simple Sinatra apps. I can also see it being useful for API auth. Of course there are potential uses outside of HTTP, too.

Steps:

  1. Generate a new token

  2. Give the client the resulting hash and salt

  3. Time passes

  4. Receive a hash and salt from client

  5. Reconstitute the token from the salt, and test if the hashes match. If not, the token has expired (or was forged).

Read the full documentation at jordanhollinger.com/docs/mortal-token/.

Warning

This is, at best, alpha-quality software. It “works” in that it doesn’t usually blow up, but it is not guaranteed to be “right”. Don’t use it in production, or at least not in any important production. May contain traces of peanut oil.

Install

[sudo] gem install mortal-token

Or add it to your Gemfile

gem "mortal-token"

Example with Sinatra

require 'sinatra'
require 'mortal-token'

# You MUST set a secret key! Otherwise, anyone who looks at the source code will be able to forge tokens.
MortalToken.secret = 'asdf092$78roasdjfjfaklmsdadASDFopijf98%2ejA#Df@sdf'

post '/login' do
  if 
    token = MortalToken.new
    session[:token] = token.hash
    session[:salt] = token.salt
    redirect '/secret'
  end
end

get '/secret' do
  token = MortalToken.new(session[:salt])
  if token == session[:token]
    'Nice token!'
  else
    'Your token is expired or forged!'
  end
end

Checking token validity

A token’s == and === methods accept another token or a hash. In the example above, an attempt has been made to reconstitute the original token (using it’s salt) on the left. If successful, it will be able to regenerate the hash on the right. But if too much time has passed, the hashes will differ and we can conclude that the token has expired.

Tweak token parameters

You may tweak certain parameters of the library in order to make it more secure, less, faster, etc. These are the defaults (see the MortalToken class for documentation about each parameter):

MortalToken.rounds = 5            # rounds of hashing
MortalToken.units = :days         # or :hours, :minutes
MortalToken.valid_across = 2      # tokens are valid across N units
MortalToken.max_salt_length = 50
MortalToken.min_salt_length = 10

Multiple configurations

Your application may want to use MortalTokens in various contexts, where the same parameters may not make sense (probably units and valid_across). You may define different scopes and give them each their own config. Always define the default scope first (as above). Other scopes will inherit its secret.

MortalToken.config(:foo) do |config|
  config.units = :minutes
  config.valid_across = 10
end

token = MortalToken.use(:foo).token

License

Copyright 2012 Jordan Hollinger

Licensed under the Apache License