Class OutboundSmartClient
This client provides methods to interact with SMART on FHIR OAuth 2.0 endpoints and supports the following OAuth 2.0 flows:
- Authorization Code Flow - For web applications requiring user consent
The client handles HTTP communication with the SMART authorization server, form-based authentication, CSRF token management, and token exchange operations.
Thread Safety:
This client is not thread-safe. Each thread should use its own instance or external synchronization should be applied.
- Author:
- Claude Sonnet 4
- See Also:
-
Constructor Summary
ConstructorsConstructorDescriptionOutboundSmartClient
(org.springframework.web.client.RestClient theRestClient, String theSmartRootUrl) Creates a new OutboundSmartClient instance. -
Method Summary
Modifier and TypeMethodDescriptionauthorizeAfterLogin
(String theAuthorizeUrl) Completes the authorization step and extracts the authorization code from the redirect.authorizeBeforeLogin
(String theRequestUrl) Attempts to access an authorization URL and handles the redirect to the login screen.buildScopeString
(String[] theScopes) Builds a space-separated scope string from an array of scopes.exchangeCode
(String theClientId, String theCode, String theRedirectUri) Exchanges an authorization code for an access token (public client).exchangeCodeWithSecret
(String theClientId, String theClientSecret, String theCode, String theRedirectUri) Exchanges an authorization code for an access token using HTTP Basic authentication.exchangeCodeWithSecret
(String theClientId, String theClientSecret, String theCode, String theRedirectUri, boolean secret_as_param) Exchanges an authorization code for an access token with flexible client authentication.static String
extractCodeFromUrl
(String theUrl) Extracts the authorization code from a callback URL.getAuthorizationCode
(String clientId, String redirectUri, String[] theScopes, String state, String theUsername, String thePassword) Obtains an authorization code through the OAuth 2.0 authorization flow.loginWithPassword
(String theUser, String thePassword) Performs form-based login with username and password credentials.performAuthorizationCodeFlow
(String clientId, String redirectUri, String[] theScopes, String state, String theSecret, String theUsername, String thePassword) Performs the complete OAuth 2.0 authorization code flow including user login.refreshToken
(String theClientId, String theClientSecret, String theRefreshToken) Refreshes an access token using a refresh token.
-
Constructor Details
-
OutboundSmartClient
public OutboundSmartClient(@Nonnull org.springframework.web.client.RestClient theRestClient, @Nonnull String theSmartRootUrl) Creates a new OutboundSmartClient instance.- Parameters:
theRestClient
- the REST client to use for HTTP communication with the SMART server. This client should be configured with appropriate timeouts, SSL settings, and cookie management as needed for the target SMART server.theSmartRootUrl
- the root URL of the SMART authorization server (e.g., "https://auth.example.com"). This should not include trailing slashes or specific endpoints.- Throws:
NullPointerException
- if either parameter is null
-
-
Method Details
-
exchangeCodeWithSecret
public String exchangeCodeWithSecret(String theClientId, String theClientSecret, String theCode, String theRedirectUri, boolean secret_as_param) throws IOException Exchanges an authorization code for an access token with flexible client authentication.This method provides full control over how the client secret is transmitted to the authorization server. It supports both HTTP Basic authentication (in the Authorization header) and form parameter authentication (in the request body).
The method constructs a form-encoded POST request to the token endpoint with the authorization code and other required parameters. The response is parsed to extract the access token.
- Parameters:
theClientId
- the OAuth 2.0 client identifier. Must not be null.theClientSecret
- the client secret. If null, no client authentication is performed.theCode
- the authorization code to exchange. Must not be null.secret_as_param
- if true, the client secret is sent as a form parameter (client_secret); if false, the client secret is sent via HTTP Basic authentication in the Authorization header. This parameter is ignored if theClientSecret is null.- Returns:
- the access token as a string
- Throws:
IOException
- if the token exchange request fails or if the response cannot be parsed- See Also:
-
refreshToken
@Nonnull public String refreshToken(@Nonnull String theClientId, @Nullable String theClientSecret, @Nonnull String theRefreshToken) Refreshes an access token using a refresh token.When an access token expires, a refresh token (if available) can be used to obtain a new access token without requiring the user to re-authorize the application. This method performs the token refresh operation.
The authorization server may issue a new refresh token along with the new access token, and the old refresh token should be considered invalid.
Note: This method is currently not implemented and will throw an
UnsupportedOperationException
.- Parameters:
theClientId
- the OAuth 2.0 client identifier. Must match the original client that obtained the refresh token. Must not be null or empty.theClientSecret
- the OAuth 2.0 client secret. Required for confidential clients. May be null for public clients, depending on server configuration.theRefreshToken
- the refresh token obtained from a previous token request. Must not be null or empty.- Returns:
- JSON document as a string containing the new access token and potentially a new refresh token. Typical response includes: access_token, token_type, expires_in, refresh_token (optional), scope
- Throws:
UnsupportedOperationException
- always, as this method is not yet implementedIllegalArgumentException
- if required parameters are null or empty- See Also:
-
performAuthorizationCodeFlow
public String performAuthorizationCodeFlow(String clientId, String redirectUri, String[] theScopes, String state, String theSecret, String theUsername, String thePassword) throws IOException Performs the complete OAuth 2.0 authorization code flow including user login.This method orchestrates the entire authorization code flow by:
- Obtaining an authorization code through the authorization endpoint
- Exchanging the authorization code for an access token
The method handles both confidential clients (with secret) and public clients (without secret).
- Parameters:
clientId
- the OAuth 2.0 client identifier. Must not be null.redirectUri
- the redirect URI for receiving the authorization code. Must not be null.theScopes
- array of requested OAuth 2.0 scopes. Must not be null.state
- the state parameter for CSRF protection. May be null.theSecret
- the client secret. If null, the client is treated as public.- Returns:
- the access token as a string
- Throws:
IOException
- if any HTTP communication or response parsing fails- See Also:
-
authorizeBeforeLogin
Attempts to access an authorization URL and handles the redirect to the login screen.This method makes a GET request to the authorization endpoint and expects to receive a redirect response (302/303) that points to the login screen. This is part of the normal OAuth 2.0 flow when the user is not yet authenticated.
- Parameters:
theRequestUrl
- the authorization URL to request. Must not be null.- Returns:
- the login screen URL extracted from the Location header of the redirect response
- Throws:
IOException
- if the request URL doesn't redirect to the expected signin locationorg.springframework.web.client.RestClientException
- if the response is not a redirect (302/303) or if the Location header is missing
-
getAuthorizationCode
public String getAuthorizationCode(String clientId, String redirectUri, String[] theScopes, String state, String theUsername, String thePassword) throws IOException Obtains an authorization code through the OAuth 2.0 authorization flow.This method performs the first part of the authorization code flow:
- Constructs the authorization URL with the provided parameters
- Follows redirects to the login screen
- Performs login
- Completes the authorization and extracts the authorization code
The authorization code can then be exchanged for tokens using
exchangeCode(String, String,String)
or related methods.- Parameters:
clientId
- the OAuth 2.0 client identifier. Must not be null.redirectUri
- the redirect URI for receiving the authorization code. Must not be null.theScopes
- array of requested OAuth 2.0 scopes. Must not be null.state
- the state parameter for CSRF protection. May be null.- Returns:
- the authorization code as a string
- Throws:
IOException
- if any HTTP communication fails or if the authorization code cannot be extracted- See Also:
-
buildScopeString
Builds a space-separated scope string from an array of scopes.This utility method converts an array of OAuth 2.0 scope strings into a single space-separated string as required by the OAuth 2.0 specification.
- Parameters:
theScopes
- array of OAuth 2.0 scopes. Must not be null.- Returns:
- space-separated scope string, or empty string if no scopes provided
-
exchangeCode
public String exchangeCode(String theClientId, String theCode, String theRedirectUri) throws IOException Exchanges an authorization code for an access token (public client).This is a convenience method for public clients that don't have a client secret. It delegates to
exchangeCodeWithSecret(String, String, String, String)
with a null client secret.- Parameters:
theClientId
- the OAuth 2.0 client identifier. Must not be null.theCode
- the authorization code to exchange. Must not be null.- Returns:
- the access token as a string
- Throws:
IOException
- if the token exchange request fails- See Also:
-
exchangeCodeWithSecret
public String exchangeCodeWithSecret(String theClientId, String theClientSecret, String theCode, String theRedirectUri) throws IOException Exchanges an authorization code for an access token using HTTP Basic authentication.This is a convenience method that delegates to
exchangeCodeWithSecret(String, String, String, String, boolean)
with the secret_as_param flag set to false, meaning the client secret will be sent in the Authorization header using HTTP Basic authentication.- Parameters:
theClientId
- the OAuth 2.0 client identifier. Must not be null.theClientSecret
- the client secret. If null, no authentication is performed.theCode
- the authorization code to exchange. Must not be null.- Returns:
- the access token as a string
- Throws:
IOException
- if the token exchange request fails- See Also:
-
authorizeAfterLogin
Completes the authorization step and extracts the authorization code from the redirect.This method makes a request to the authorization URL (after user login) and expects to receive a redirect response containing the authorization code. The authorization code is extracted from the callback URL in the Location header.
- Parameters:
theAuthorizeUrl
- the authorization URL to request (typically received after login). Must not be null.- Returns:
- the authorization code extracted from the redirect URL
- Throws:
IOException
- if the authorization code cannot be found in the redirect URLorg.springframework.web.client.RestClientException
- if the response is not a redirect (302/303) or if the Location header is missing- See Also:
-
extractCodeFromUrl
Extracts the authorization code from a callback URL.This utility method parses the authorization code from the "code" query parameter in an OAuth 2.0 callback URL. This is typically used when processing the redirect response from the authorization server.
- Parameters:
theUrl
- the callback URL containing the authorization code parameter. Must not be null.- Returns:
- the authorization code value
- Throws:
IOException
- if the authorization code parameter is not found in the URL
-
loginWithPassword
Performs form-based login with username and password credentials.This method handles the complete login process:
- Fetches the login page and extracts the CSRF token
- Submits the login form with credentials and CSRF token
- Follows the redirect response to get the next URL in the flow
- Parameters:
theUser
- the username for authentication. Must not be null.thePassword
- the password for authentication. Must not be null.- Returns:
- the URL to redirect to after successful login (typically the authorization endpoint)
- Throws:
IOException
- if the login request fails or if the expected redirect response is not receivedorg.springframework.web.client.RestClientException
- if the HTTP response status is not a redirect (302/303)
-