AdonisJSのOpaque Tokenの期限を更新する
AdonisJSのOpaque Tokenの期限を更新する
2022/11/25

Adonis5をAPIサーバーとして扱う場合の認証はAPI tokensというOAT認証方式のトークンが採用されています。

Opaqueトークンは、JWTトークンのように有効期限を更新するためのリフレッシュトークンがない。そのため期限をすぎると再認証が必要になります。

しかし、AdonisにはOpaqueトークンを更新する機能が用意されていないので、トークンの期限を更新をどうしたかを紹介します。

Opaqueトークンの更新タイミング

まずOpaqueトークンの文字列、情報が含まれてないランダムなハッシュデータです。ですから頻繁にネットワーク上に流れてもセキュリティ上問題ありません。
(JWTなんかは30分とか非常に短い期限にするのが一般的です。)

なので、トークン自体の期限を2週間と長く設定して、APIにアクセスする度に期限をチェックして、10日以下になったときに、トークンの期限日を伸ばす仕様にする。

クライアントはトークンを更新する必要がない。なぜなら、DBに保存されているexpired_atを更新するだけでハッシュに変更はないからです。

Opaqueトークンの更新タイミング

実装方法

コードでは以下のようなことを行う。

if (await auth.use('api').check()) {
  const expiresAt = auth.use('api').token?.expiresAt
  const tokenHash = auth.use('api').token?.tokenHash

  if (!!expiresAt && !!tokenHash) {
    // トークンの期限が10日以下になった場合
    if (DateTime.local().plus({day: 10}) > expiresAt) {
      const dateTimeFormat = Database.query().client.dialect.dateTimeFormat
      const newExpiresAt = DateTime.local().plus({day: 14}).toFormat(dateTimeFormat)
      // DBのapi_tokens.expires_atを更新する
      await Database.from('api_tokens').where('token', tokenHash).update({ 'expires_at': newExpiresAt })
    }
  }
  return response.accepted(auth.use('api').user)
} else {
  return response.unauthorized()
}

tokenをアップデートする関数が用意されていないので、DatabaseQueryBuilderで直接api_tokensテーブルを指定してupdateを行っている。

その際に、日付をクエリに入れるときFormatしないとエラーを吐く。

"update `api_tokens` set `expires_at` = 2022-10-19 13:20:32.841 +00:00 where `token` = 'a753bc6e3d3aee20afb19d53d56f87bb9b4d1e415cc70ab0ee009387b57f4dd9' - Unknown column '_zone' in 'field list'"

日時のフォーマットは、Adonisのauthパッケージを参考にdateTimeFormatを取得した。

https://github.com/adonisjs/auth/blob/master/src/TokenProviders/Database/index.ts#L110

const dateTimeFormat = Database.query().client.dialect.dateTimeFormat

これで同じトークンを使っていても定期的にサービスを利用していれば、期限切れを起こすことがなくなる認証ができた。

この他にも、AdonisJS v5へのアップグレードで行ったことをまとめました。
なにか役に立てたら幸いです。