Freika/dawarich · error · Auth::VerifyAppleToken::InvalidToken

blank token

Error message

blank token

What it means

Auth::VerifyAppleToken raises InvalidToken 'blank token' when the id_token argument is nil or empty before any Apple library call happens. This is a fail-fast precondition: the Sign in with Apple flow always returns a credential containing an id_token (JWT), so a blank one means the client never completed the Apple handshake or the server-side code read the wrong parameter key.

Source

Thrown at app/services/auth/verify_apple_token.rb:14

# frozen_string_literal: true

module Auth
  class VerifyAppleToken
    class InvalidToken < StandardError; end

    def initialize(id_token, nonce: nil, client_id: nil)
      @id_token = id_token
      @nonce = nonce
      @client_id = client_id
    end

    def call
      raise InvalidToken, 'blank token' if @id_token.blank?
      raise InvalidToken, 'client_id not configured' if effective_client_id.blank?

      decoded = AppleID::IdToken.decode(@id_token)
      verify_args = { client: effective_client_id }
      verify_args[:nonce] = expected_nonce_hash if @nonce.present?

      decoded.verify!(**verify_args)

      log_missing_nonce_breadcrumb if @nonce.blank?

      {
        sub: decoded.sub,
        email: decoded.email,
        email_verified: decoded.email_verified?,
        is_private_email: decoded.is_private_email?
      }
    rescue AppleID::IdToken::VerificationFailed, JSON::JWT::Exception => e
      raise InvalidToken, e.message

View on GitHub (pinned to 97fad417c5)

Solutions

  1. Confirm the client actually obtained an Apple credential and is sending its identityToken/id_token in the request
  2. Check the controller passes the correct param key to VerifyAppleToken.new(params[:id_token], ...)
  3. If the client only has an authorization code, exchange it for tokens first - the code itself is not an id_token
  4. Ensure the request body content-type matches what the controller parses

Example fix

# before
Auth::VerifyAppleToken.new(params[:access_token]).call # wrong token type, often blank

# after
Auth::VerifyAppleToken.new(params[:id_token]).call # Apple's identity token (JWT)
Defensive patterns

Strategy: validation

Validate before calling

def apple_id_token_present?(params)
  params[:id_token].present?
end
# return a 400 with a clear message before entering the OAuth flow when false

Try / catch

begin
  result = Auth::VerifyAppleToken.new(id_token, nonce:, client_id:).call
rescue Auth::VerifyAppleToken::InvalidToken => e
  render json: { error: e.message }, status: :unauthorized
end

Prevention

When it happens

Trigger: Apple OAuth callback where params[:id_token] (or the controller's chosen key) is absent - e.g. the mobile/web client sent only an authorization code, the credential was serialized under a different field name, or a user hit the endpoint directly without going through Apple first.

Common situations: Client confusion between Apple's authorization code flow and id_token flow (code needs a different exchange endpoint before any token exists), frontends sending credential/identityToken under a mismatched param name, POST body parsing dropping the token (form-encoded vs JSON mismatch), Apple returning an error the caller ignored before POSTing.

Related errors


AI-assisted analysis of Freika/dawarich@97fad417c5 (2026-08-21). Data as JSON: /api/errors/8e5754c04ee8fddd. Report an issue: GitHub.