Calling register_client

Call Client#register_client to POST your application’s metadata to the authorization server’s registration endpoint and receive a client_id in response.

Table of contents

  1. Quick Start
  2. Client Metadata
    1. Common fields
    2. Grant types
    3. Authentication methods
  3. Registration Endpoint
    1. Discovery (default)
    2. Explicit endpoint
  4. Initial Access Token
  5. What’s Next

Quick Start

Create a Safire::Client without a client_id, call register_client with your application’s metadata, and then build a fully configured client using the credentials the server returns.

# Step 1 — temporary client for registration only (no client_id needed)
temp_client = Safire::Client.new({ base_url: 'https://fhir.example.com' })

# Step 2 — register and receive credentials
registration = temp_client.register_client(
  {
    client_name:                'My FHIR App',
    redirect_uris:              ['https://myapp.example.com/callback'],
    grant_types:                ['authorization_code'],
    token_endpoint_auth_method: 'none',
    scope:                      'openid profile patient/*.read'
  }
)
# => { "client_id" => "dyn_abc123", "client_name" => "My FHIR App", ... }

# Step 3 — persist credentials durably (database, secrets manager, etc.)
client_id = registration['client_id']     # always present
secret    = registration['client_secret'] # present for confidential_symmetric only

# Step 4 — build a properly configured client for authorization flows
client = Safire::Client.new(
  {
    base_url:     'https://fhir.example.com',
    client_id:    client_id,
    redirect_uri: 'https://myapp.example.com/callback',
    scopes:       ['openid', 'profile', 'patient/*.read']
  }
)

Client Metadata

The metadata argument is a Hash of RFC 7591 §2 client metadata fields. Keys may be symbols or strings. Any field the server does not recognize is silently ignored; any field the server requires but you omit will produce a RegistrationError.

Common fields

Field Type When required Notes
client_name String Recommended Human-readable application name displayed in authorization prompts
redirect_uris Array<String> Required for authorization_code Exact URIs the server will redirect to after authorization
grant_types Array<String> Recommended See Grant types below
token_endpoint_auth_method String Recommended See Authentication methods below
scope String Optional Space-separated default scopes; may be narrowed per-request at runtime
jwks_uri String Required for private_key_jwt URL of the client’s JWKS endpoint; the server fetches public keys for JWT verification
jwks Hash Alternative to jwks_uri Inline JWKS containing the client’s public key(s)
client_uri String Optional URL of the client’s home page

Grant types

Pass an array containing each grant type the client intends to use.

Value Use
authorization_code SMART App Launch — user-facing authorization with redirect and PKCE
client_credentials Backend Services — system-to-system access with no user interaction
refresh_token Token refresh; include alongside authorization_code when the server should issue refresh tokens

Authentication methods

The token_endpoint_auth_method value tells the server how the client will authenticate at the token endpoint. Safire supports the following methods.

Value Safire client_type How it works
none :public No client authentication; client_id sent in the POST body
client_secret_basic :confidential_symmetric HTTP Basic auth using the client_secret the server issues
private_key_jwt :confidential_asymmetric Signed JWT assertion; requires jwks_uri or inline jwks in metadata

If your client will use private_key_jwt, you must include jwks_uri or jwks in the registration metadata so the server can obtain your public key for JWT verification.


Registration Endpoint

Discovery (default)

When you do not supply registration_endpoint:, Safire fetches the server’s SMART configuration from /.well-known/smart-configuration and reads the registration_endpoint field. Discovery is cached after the first call, so repeated calls on the same Safire::Client instance do not issue another network request.

# Safire discovers the registration endpoint automatically
registration = client.register_client({ client_name: 'My App', ... })

If the server does not advertise a registration_endpoint, Safire raises Safire::Errors::DiscoveryError. The error message explains that you must supply the endpoint explicitly or that the server may not support DCR.

To check before calling register_client, use supports_dynamic_registration? on the server metadata. This is only relevant when you are relying on discovery — if you already hold the endpoint URL, pass it via registration_endpoint: and skip this check.

metadata = client.server_metadata

unless metadata.supports_dynamic_registration?
  raise 'Server does not advertise a registration_endpoint — pass registration_endpoint: explicitly or use manual registration'
end

registration = client.register_client({ client_name: 'My App', ... })

Explicit endpoint

Pass registration_endpoint: to bypass discovery entirely. This is useful when the server advertises the endpoint out-of-band, when you want to skip the discovery request, or when the server does not expose /.well-known/smart-configuration.

registration = client.register_client(
  { client_name: 'My App', ... },
  registration_endpoint: 'https://auth.example.com/register'
)

Initial Access Token

Some authorization servers protect their registration endpoint with a bearer token to prevent unauthorized registrations (RFC 7591 §3.1). If the server requires one, obtain it out-of-band from the server operator and pass the full Authorization header value to authorization:.

registration = client.register_client(
  { client_name: 'My App', ... },
  authorization: 'Bearer eyJhbGciOiJSUzI1NiJ9...'
)

The authorization: parameter accepts any valid header value. Safire passes it verbatim as the Authorization header, so the token type prefix (Bearer, MAC, etc.) must be included.


What’s Next

Registration Response covers what the server returns, how to persist credentials, how to build a runtime client from the response, and error handling.


Back to Top ↑

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