Skip to content

@authentication/passwordless@2.0.0

Compare
Choose a tag to compare
@ForbesLindesay ForbesLindesay released this 22 Jul 18:05
a6f52f2

Breaking Changes

  • The token schema has changed (#18)

    Tokens now look like:

    export default interface Token`State = void> {
      userID: string;
      /**
       * An incrementing integer used for optimistic concurrency
       */
      version: number;
      /**
       * The pass code, that gets sent in the e-mail and entered by
       * the user (or appears as the `code` parameter in "magic" link)
       */
      passCode: string;
      /**
       * The number of attempts remaining before the token is disposed of.
       */
      attemptsRemaining: number;
      /**
       * The time this token was created, represented as milliseconds since
       * the unix epoch.
       */
      created: number;
      /**
       * The time this token expires, represented as milliseconds since the
       * unix epoch.
       */
      expiry: number;
      /**
       * Some arbirary state of your choice. This is a good place to store a
       * redirect URI for after the authentication is complete.
       */
      state: State;
    }

    It is very important that you always check token.version when performing update operations, in order to prevent a malicious attacker making more than the expected number of attempts at a single token.

  • Is is now only possible to use the namespaced version of the Store (#18)

    The type for the store is now:

    export interface TokensStore`State = undefined> {
      insert(token: Token`State>): Promise`string>;
      load(tokenID: string): Promise`Token`State> | null>;
      update(
        tokenID: string,
        token: Token`State>,
        oldToken: Token`State>,
      ): Promise`void>;
      remove(tokenID: string): Promise`void>;
    }
    export default interface PasswordlessStore`State = undefined> {
      tokens: TokensStore`State>;
      rateLimit: RateLimitStore`string>;
    }
  • createToken now requires {userID, ipAddress, state, sendTokenToUser} as input instead of an express request/response pair. It returns the response expected by react-passwordless, and only gives the secret pass code to the sendTokenTouser function. (#18)

  • verifyPassCode has been split into verifyPassCode and verifyPassCodeFromRequest (#18)

    Both functions need to be given both the tokenID and the passCode as cookies are no longer used to store the tokenID. The verifyPassCodeFromRequest can accept either an express request or a koa context object.

  • Removed support for stores with "transactions" (#17)

    They were often implemented incorrectly, which can lead to security vulnerabilities. It is much safer to enforce that optimistic concurrency is used.

Performance Improvements

  • passCodes are no longer hashed before storage because it was expensive and they are short-lived tokens anyway. (#18)

    This allows us to drop a costly native dependency, and reduces the load on your server considerably.