Request#bearer_tokenでBearerトークンを抽出する

RailsでAPIを構築している場合、Authorizationヘッダーからbearerトークンを抽出するコードを書いたことがあるでしょう。Railsはこれをクリーンに行うための組み込みメソッドを提供するようになりました。

変更内容

ActionDispatch::RequestにAuthorizationヘッダーからトークンを抽出するbearer_tokenメソッドが追加されました:

# Authorization: Bearer my-secret-token
request.bearer_token
# => "my-secret-token"

なぜこれが重要か

Bearerトークンは、APIリクエストを認証する標準的な方法です。この変更前は、次のようなコードを書いていました:

class ApiController < ApplicationController
  def authenticate
    token = request.authorization.to_s.split(" ").last
    # または
    token = request.authorization&.gsub(/^Bearer /, "")
    # または
    token = request.headers["Authorization"]&.match(/Bearer (.+)/)&.[](1)
  end
end

各アプローチにはエッジケースがあります。新しいメソッドはそれらすべてを処理します:

token = request.bearer_token

使い方

基本的なAPI認証

class ApiController < ApplicationController
  before_action :authenticate

  private

  def authenticate
    token = request.bearer_token

    unless token && valid_token?(token)
      render json: { error: "認証されていません" }, status: :unauthorized
    end
  end

  def valid_token?(token)
    ApiToken.find_by(token: token)&.active?
  end
end

Deviseまたはカスタム認証と

class ApiController < ApplicationController
  before_action :authenticate_user_from_token!

  private

  def authenticate_user_from_token!
    token = request.bearer_token
    return head :unauthorized unless token

    @current_user = User.find_by(api_token: token)
    head :unauthorized unless @current_user
  end
end

処理されるエッジケース

メソッドは以下の場合にnilを返します:

# Authorizationヘッダーなし
request.bearer_token # => nil

# 異なる認証スキーム
# Authorization: Basic dXNlcjpwYXNz
request.bearer_token # => nil

# 空のヘッダー
# Authorization:
request.bearer_token # => nil

# トークンなしのBearer
# Authorization: Bearer
request.bearer_token # => nil

X-HTTP_AUTHORIZATIONヘッダー(一部のプロキシで使用)でも動作します:

# X-HTTP_AUTHORIZATION: Bearer my-token
request.bearer_token # => "my-token"

注意点

  • メソッドはトークンを抽出するだけで、検証は依然としてあなたの責任です
  • トークンは大文字と小文字を区別します。メソッドは正確なトークン値を保持します
  • “Bearer”プレフィックスのマッチングは大文字と小文字を区別します(RFC 6750に従う)

まとめ

API認証コードのボイラープレートを排除する小さいながらも歓迎すべき追加です。Authorizationヘッダーを手動でパースしている場合は、よりクリーンで信頼性の高いコードのためにrequest.bearer_tokenに切り替えてください。

詳細はcommitPR #56474を参照してください。