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

client_id not configured

Error message

client_id not configured

What it means

VerifyAppleToken resolves the expected Apple audience as @client_id || ENV['APPLE_BUNDLE_ID']; when both are blank it raises InvalidToken 'client_id not configured' before decoding anything. AppleID's verify! needs the client (audience) to check the aud claim, so verification is impossible without it - this error is always a server configuration problem, never a bad user token.

Source

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

# 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
    end

View on GitHub (pinned to 97fad417c5)

Solutions

  1. Set APPLE_BUNDLE_ID in the environment where the app runs (e.g. APPLE_BUNDLE_ID=com.example.app) and restart
  2. Or pass client_id explicitly when instantiating the service - required when web (Services ID) and native (bundle id) flows coexist
  3. Verify with a print/日志 of ENV['APPLE_BUNDLE_ID'] presence (never the value) in the target environment
  4. Add the variable to .env.example/deployment templates so new environments fail loudly at boot instead of at sign-in

Example fix

# before
Auth::VerifyAppleToken.new(params[:id_token]).call # APPLE_BUNDLE_ID unset -> raises

# after
Auth::VerifyAppleToken.new(params[:id_token], client_id: ENV['APPLE_WEB_CLIENT_ID']).call
# or ensure ENV['APPLE_BUNDLE_ID'] is set for this deployment
Defensive patterns

Strategy: validation

Validate before calling

# Fail fast at boot or entry, before any Apple round-trip
raise 'APPLE_BUNDLE_ID env var is required for Apple sign-in' if ENV['APPLE_BUNDLE_ID'].blank? && client_id.blank?

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 # 'client_id not configured' = server misconfig, page the ops channel
end

Prevention

When it happens

Trigger: Calling the Apple sign-in endpoint on a server where APPLE_BUNDLE_ID is unset (fresh deployment, missed .env entry, production-only omission) and the caller did not pass client_id: explicitly - e.g. a web client that should pass the Services-Apple-Web client id vs the native bundle id.

Common situations: New environment/missing ENV var after deploying, container orchestration not propagating APPLE_BUNDLE_ID, using the web (Services ID) flow where the bundle id is wrong anyway, credentials-based config where the var lives in credentials but was never exported to ENV.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


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