Encrypted Token Migrations

5 min read - Text Only
Table of contents
  • Encrypted Token Migrations
  • Not authenticated for both versioned and unversioned
  • Unversioned and authenticated
  • Versioned and authenticated

If the client is passing back data that you encrypted but may hold onto it for an arbitrary length of time, then you have a few cases:

  • The previous encrypted data is unversioned and not authenticated;
  • The previous encrypted data is unversioned but authenticated;
  • The previous encrypted data is versioned and not authenticated;
  • And the previous encrypted data is versioned and authenticated.

In all cases, the new encrypted data must be versioned and that version must be bound to the message with AEAD. All versions must use different and unique keys.

Adjust your application protocol in a backwards compatible or versioned manner to support delivery and replacement of encrypted tokens. For example, OAUth supports replacing the refresh token. Upon issuing a replacement to a client, if the new token is ever used, the previous token must never be accepted again. The encrypted data may include a hash of the old token so that upon being successfully decrypted the old token hash can be persisted for rejection. In addition, the key for the old token should map to the hash of the new token. Upon receiving an old token after it has been persisted for rejection, the new token mush also be persisted for rejection as the token has been leaked.

Not authenticated for both versioned and unversioned

This is the worst case. It is very risky to use the old decryption path since it is unauthenticated. Should you choose to still decrypt the old data, you may provide a warning or error in the application or out of bounds to the application so that this data gets updated by the user on the other side. If you can, provide a new token to the client to use in future requests. For future issued tokens, prepend the message with the version and check for known prefixes (with simple prefix matching, not parsing) to figure out which decrypt function to use. The decrypt function for that version should be responsible for stripping or unwrapping the versioned message.

Unversioned and authenticated

There is little risk of using the old decryption path because it is authenticated. Prepare a migration plan for clients to receive new tokens in the application or outside the application. If you can, provide a new token to the client to use in future requests. For future issued tokens, prepend the message with the version and check for known prefixes (with simple prefix matching, not parsing) to figure out which decrypt function to use. The decrypt function for that version should be responsible for stripping or unwrapping the versioned message.

Versioned and authenticated

This is the best case. Prepare a migration plan for clients to receive new tokens in the application or outside the application. If you can, provide a new token to the client to use in future requests. For future issued tokens, prepend the message with the version and check for known prefixes (with simple prefix matching, not parsing) to figure out which decrypt function to use. The decrypt function for that version should be responsible for stripping or unwrapping the versioned message.