Discovery and Authorization Errors

Table of contents

  1. Discovery and Authorization Errors
    1. Discovery Errors
      1. DiscoveryError: Failed to discover SMART configuration
      2. DiscoveryError: Invalid SMART configuration format
    2. Authorization Errors
      1. ConfigurationError: Missing client_id
      2. ConfigurationError: Missing scopes
      3. State mismatch on callback

Discovery Errors

DiscoveryError: Failed to discover SMART configuration

Safire::Errors::DiscoveryError: Failed to discover SMART configuration from
https://fhir.example.com/.well-known/smart-configuration (HTTP 404)

Causes: the server does not support SMART App Launch, base_url includes an extra path segment, or the server uses a non-standard discovery path.

Verify the endpoint manually:

curl -I https://fhir.example.com/.well-known/smart-configuration

Ensure base_url points to the FHIR root, not a resource path:

# ✅ Correct
base_url: 'https://fhir.example.com/r4'

# ❌ Too specific — strip the resource type
base_url: 'https://fhir.example.com/r4/Patient'

If the server does not support discovery, provide endpoints manually in ClientConfig:

config = Safire::ClientConfig.new(
  base_url:               'https://fhir.example.com',
  client_id:              'my_client',
  redirect_uri:           'https://myapp.com/callback',
  scopes:                 ['openid', 'profile'],
  authorization_endpoint: 'https://fhir.example.com/authorize',
  token_endpoint:         'https://fhir.example.com/token'
)

DiscoveryError: Invalid SMART configuration format

Safire::Errors::DiscoveryError: ... response is not a JSON object

The server returned an HTML error page, a JSON array, or malformed JSON. Inspect the raw response:

curl https://fhir.example.com/.well-known/smart-configuration

The response must be a JSON object ({...}) with at least authorization_endpoint and token_endpoint.


Authorization Errors

ConfigurationError: Missing client_id

Safire::Errors::ConfigurationError: Configuration missing: client_id

client_id is optional at construction but required by every authorization method. It is validated at call time, not when the client is created. Ensure client_id is set in ClientConfig before calling any flow method:

config = Safire::ClientConfig.new(
  base_url:  'https://fhir.example.com',
  client_id: ENV.fetch('SMART_CLIENT_ID'),
  # ...
)

This error is raised by authorization_url, request_access_token, refresh_token, and request_backend_token.


ConfigurationError: Missing scopes

Safire::Errors::ConfigurationError: Configuration missing: scopes

Scopes must be provided either in ClientConfig or when calling authorization_url:

# Option 1 — in config
config = Safire::ClientConfig.new(
  scopes: ['openid', 'profile', 'patient/*.read'],
  # ...
)

# Option 2 — per request
auth_data = client.authorization_url(
  custom_scopes: ['openid', 'profile', 'patient/Patient.read']
)

Backend Services: request_backend_token does not raise this error — it defaults to ["system/*.rs"] when no scopes are configured. Pass scopes: to override: client.request_backend_token(scopes: ['system/Patient.rs']).

State mismatch on callback

Symptom: authorization callback fails or state validation raises an error.

Causes: state not stored in session before redirect, session expired, or multiple tabs in flight.

Always store both state and code_verifier before redirecting, and validate state immediately on callback:

# On launch
auth_data = client.authorization_url
session[:oauth_state]   = auth_data[:state]
session[:code_verifier] = auth_data[:code_verifier]
redirect_to auth_data[:auth_url], allow_other_host: true

# On callback
unless params[:state] == session[:oauth_state]
  render plain: 'Invalid state', status: :unauthorized
  return
end

# Delete immediately after use
session.delete(:oauth_state)

If the session has expired by the time the user returns, redirect them back to the launch endpoint with a user-friendly message rather than showing a raw error.


Back to Top ↑

This site uses Just the Docs, a documentation theme for Jekyll.