diff --git a/lib/fusionauth/fusionauth_client.rb b/lib/fusionauth/fusionauth_client.rb index 3134839..f7358e6 100644 --- a/lib/fusionauth/fusionauth_client.rb +++ b/lib/fusionauth/fusionauth_client.rb @@ -90,14 +90,33 @@ def add_user_to_family(family_id, request) # @param user_code [string] The end-user verification code. # @return [FusionAuth::ClientResponse] The ClientResponse object. def approve_device(client_id, client_secret, token, user_code) - body = { + form_parameters = { "client_id" => client_id, "client_secret" => client_secret, "token" => token, - "user_code" => user_code + "user_code" => user_code, } start.uri('/oauth2/device/approve') - .body_handler(FusionAuth::FormDataBodyHandler.new(body)) + .body_handler(FusionAuth::FormDataBodyHandler.new(form_parameters)) + .post + .go + end + + # + # Approve a device grant. + # + # @param request [OpenStruct, Hash] The request object containing the device approval information and optional tenantId. + # @return [FusionAuth::ClientResponse] The ClientResponse object. + def approve_device_with_request(request) + form_parameters = { + "client_id" => request.client_id, + "client_secret" => request.client_secret, + "tenantId" => (request.tenantId.to_s unless request.tenantId.nil?), + "token" => request.token, + "user_code" => request.user_code, + } + start.uri('/oauth2/device/approve') + .body_handler(FusionAuth::FormDataBodyHandler.new(form_parameters)) .post .go end @@ -333,14 +352,33 @@ def check_change_password_using_login_id_and_login_id_types_and_ip_address(login # @param scope [string] (Optional) This parameter is used to indicate which target entity you are requesting access. To request access to an entity, use the format target-entity:<target-entity-id>:<roles>. Roles are an optional comma separated list. # @return [FusionAuth::ClientResponse] The ClientResponse object. def client_credentials_grant(client_id, client_secret, scope) - body = { + form_parameters = { "client_id" => client_id, "client_secret" => client_secret, - "grant_type" => "client_credentials", - "scope" => scope + "grant_type" => 'client_credentials', + "scope" => scope, + } + startAnonymous.uri('/oauth2/token') + .body_handler(FusionAuth::FormDataBodyHandler.new(form_parameters)) + .post + .go + end + + # + # Make a Client Credentials grant request to obtain an access token. + # + # @param request [OpenStruct, Hash] The client credentials grant request containing client authentication, scope and optional tenantId. + # @return [FusionAuth::ClientResponse] The ClientResponse object. + def client_credentials_grant_with_request(request) + form_parameters = { + "client_id" => request.client_id, + "client_secret" => request.client_secret, + "grant_type" => request.grant_type, + "scope" => request.scope, + "tenantId" => request.tenantId, } startAnonymous.uri('/oauth2/token') - .body_handler(FusionAuth::FormDataBodyHandler.new(body)) + .body_handler(FusionAuth::FormDataBodyHandler.new(form_parameters)) .post .go end @@ -1386,6 +1424,43 @@ def delete_webhook(webhook_id) .go end + # + # Start the Device Authorization flow using form-encoded parameters + # + # @param client_id [string] The unique client identifier. The client Id is the Id of the FusionAuth Application in which you are attempting to authenticate. + # @param client_secret [string] (Optional) The client secret. This value may optionally be provided in the request body instead of the Authorization header. + # @param scope [string] (Optional) A space-delimited string of the requested scopes. Defaults to all scopes configured in the Application's OAuth configuration. + # @return [FusionAuth::ClientResponse] The ClientResponse object. + def device_authorize(client_id, client_secret, scope) + form_parameters = { + "client_id" => client_id, + "client_secret" => client_secret, + "scope" => scope, + } + startAnonymous.uri('/oauth2/device_authorize') + .body_handler(FusionAuth::FormDataBodyHandler.new(form_parameters)) + .post + .go + end + + # + # Start the Device Authorization flow using a request body + # + # @param request [OpenStruct, Hash] The device authorization request containing client authentication, scope, and optional device metadata. + # @return [FusionAuth::ClientResponse] The ClientResponse object. + def device_authorize_with_request(request) + form_parameters = { + "client_id" => request.client_id, + "client_secret" => request.client_secret, + "scope" => request.scope, + "tenantId" => (request.tenantId.to_s unless request.tenantId.nil?), + } + startAnonymous.uri('/oauth2/device_authorize') + .body_handler(FusionAuth::FormDataBodyHandler.new(form_parameters)) + .post + .go + end + # # Disable two-factor authentication for a user. # @@ -1441,15 +1516,15 @@ def enable_two_factor(user_id, request) # @param redirect_uri [string] The URI to redirect to upon a successful request. # @return [FusionAuth::ClientResponse] The ClientResponse object. def exchange_o_auth_code_for_access_token(code, client_id, client_secret, redirect_uri) - body = { + form_parameters = { "code" => code, "client_id" => client_id, "client_secret" => client_secret, - "grant_type" => "authorization_code", - "redirect_uri" => redirect_uri + "grant_type" => 'authorization_code', + "redirect_uri" => redirect_uri, } startAnonymous.uri('/oauth2/token') - .body_handler(FusionAuth::FormDataBodyHandler.new(body)) + .body_handler(FusionAuth::FormDataBodyHandler.new(form_parameters)) .post .go end @@ -1466,16 +1541,59 @@ def exchange_o_auth_code_for_access_token(code, client_id, client_secret, redire # @param code_verifier [string] The random string generated previously. Will be compared with the code_challenge sent previously, which allows the OAuth provider to authenticate your app. # @return [FusionAuth::ClientResponse] The ClientResponse object. def exchange_o_auth_code_for_access_token_using_pkce(code, client_id, client_secret, redirect_uri, code_verifier) - body = { + form_parameters = { "code" => code, "client_id" => client_id, "client_secret" => client_secret, - "grant_type" => "authorization_code", + "grant_type" => 'authorization_code', "redirect_uri" => redirect_uri, - "code_verifier" => code_verifier + "code_verifier" => code_verifier, + } + startAnonymous.uri('/oauth2/token') + .body_handler(FusionAuth::FormDataBodyHandler.new(form_parameters)) + .post + .go + end + + # + # Exchanges an OAuth authorization code and code_verifier for an access token. + # Makes a request to the Token endpoint to exchange the authorization code returned from the Authorize endpoint and a code_verifier for an access token. + # + # @param request [OpenStruct, Hash] The PKCE OAuth code access token exchange request. + # @return [FusionAuth::ClientResponse] The ClientResponse object. + def exchange_o_auth_code_for_access_token_using_pkce_with_request(request) + form_parameters = { + "client_id" => request.client_id, + "client_secret" => request.client_secret, + "code" => request.code, + "code_verifier" => request.code_verifier, + "grant_type" => request.grant_type, + "redirect_uri" => request.redirect_uri, + "tenantId" => (request.tenantId.to_s unless request.tenantId.nil?), } startAnonymous.uri('/oauth2/token') - .body_handler(FusionAuth::FormDataBodyHandler.new(body)) + .body_handler(FusionAuth::FormDataBodyHandler.new(form_parameters)) + .post + .go + end + + # + # Exchanges an OAuth authorization code for an access token. + # Makes a request to the Token endpoint to exchange the authorization code returned from the Authorize endpoint for an access token. + # + # @param request [OpenStruct, Hash] The OAuth code access token exchange request. + # @return [FusionAuth::ClientResponse] The ClientResponse object. + def exchange_o_auth_code_for_access_token_with_request(request) + form_parameters = { + "client_id" => request.client_id, + "client_secret" => request.client_secret, + "code" => request.code, + "grant_type" => request.grant_type, + "redirect_uri" => request.redirect_uri, + "tenantId" => request.tenantId, + } + startAnonymous.uri('/oauth2/token') + .body_handler(FusionAuth::FormDataBodyHandler.new(form_parameters)) .post .go end @@ -1492,16 +1610,38 @@ def exchange_o_auth_code_for_access_token_using_pkce(code, client_id, client_sec # @param user_code [string] (Optional) The end-user verification code. This code is required if using this endpoint to approve the Device Authorization. # @return [FusionAuth::ClientResponse] The ClientResponse object. def exchange_refresh_token_for_access_token(refresh_token, client_id, client_secret, scope, user_code) - body = { + form_parameters = { "refresh_token" => refresh_token, "client_id" => client_id, "client_secret" => client_secret, - "grant_type" => "refresh_token", + "grant_type" => 'refresh_token', "scope" => scope, - "user_code" => user_code + "user_code" => user_code, } startAnonymous.uri('/oauth2/token') - .body_handler(FusionAuth::FormDataBodyHandler.new(body)) + .body_handler(FusionAuth::FormDataBodyHandler.new(form_parameters)) + .post + .go + end + + # + # Exchange a Refresh Token for an Access Token. + # If you will be using the Refresh Token Grant, you will make a request to the Token endpoint to exchange the user’s refresh token for an access token. + # + # @param request [OpenStruct, Hash] The refresh token access token exchange request. + # @return [FusionAuth::ClientResponse] The ClientResponse object. + def exchange_refresh_token_for_access_token_with_request(request) + form_parameters = { + "client_id" => request.client_id, + "client_secret" => request.client_secret, + "grant_type" => request.grant_type, + "refresh_token" => request.refresh_token, + "scope" => request.scope, + "tenantId" => (request.tenantId.to_s unless request.tenantId.nil?), + "user_code" => request.user_code, + } + startAnonymous.uri('/oauth2/token') + .body_handler(FusionAuth::FormDataBodyHandler.new(form_parameters)) .post .go end @@ -1531,17 +1671,40 @@ def exchange_refresh_token_for_jwt(request) # @param user_code [string] (Optional) The end-user verification code. This code is required if using this endpoint to approve the Device Authorization. # @return [FusionAuth::ClientResponse] The ClientResponse object. def exchange_user_credentials_for_access_token(username, password, client_id, client_secret, scope, user_code) - body = { + form_parameters = { "username" => username, "password" => password, "client_id" => client_id, "client_secret" => client_secret, - "grant_type" => "password", + "grant_type" => 'password', "scope" => scope, - "user_code" => user_code + "user_code" => user_code, + } + startAnonymous.uri('/oauth2/token') + .body_handler(FusionAuth::FormDataBodyHandler.new(form_parameters)) + .post + .go + end + + # + # Exchange User Credentials for a Token. + # If you will be using the Resource Owner Password Credential Grant, you will make a request to the Token endpoint to exchange the user’s email and password for an access token. + # + # @param request [OpenStruct, Hash] The user credentials access token exchange request. + # @return [FusionAuth::ClientResponse] The ClientResponse object. + def exchange_user_credentials_for_access_token_with_request(request) + form_parameters = { + "client_id" => request.client_id, + "client_secret" => request.client_secret, + "grant_type" => request.grant_type, + "password" => request.password, + "scope" => request.scope, + "tenantId" => request.tenantId, + "user_code" => request.user_code, + "username" => request.username, } startAnonymous.uri('/oauth2/token') - .body_handler(FusionAuth::FormDataBodyHandler.new(body)) + .body_handler(FusionAuth::FormDataBodyHandler.new(form_parameters)) .post .go end @@ -1725,12 +1888,29 @@ def import_web_authn_credential(request) # @param token [string] The access token returned by this OAuth provider as the result of a successful client credentials grant. # @return [FusionAuth::ClientResponse] The ClientResponse object. def introspect_access_token(client_id, token) - body = { + form_parameters = { "client_id" => client_id, - "token" => token + "token" => token, } startAnonymous.uri('/oauth2/introspect') - .body_handler(FusionAuth::FormDataBodyHandler.new(body)) + .body_handler(FusionAuth::FormDataBodyHandler.new(form_parameters)) + .post + .go + end + + # + # Inspect an access token issued as the result of the User based grant such as the Authorization Code Grant, Implicit Grant, the User Credentials Grant or the Refresh Grant. + # + # @param request [OpenStruct, Hash] The access token introspection request. + # @return [FusionAuth::ClientResponse] The ClientResponse object. + def introspect_access_token_with_request(request) + form_parameters = { + "client_id" => request.client_id, + "tenantId" => request.tenantId, + "token" => request.token, + } + startAnonymous.uri('/oauth2/introspect') + .body_handler(FusionAuth::FormDataBodyHandler.new(form_parameters)) .post .go end @@ -1741,11 +1921,27 @@ def introspect_access_token(client_id, token) # @param token [string] The access token returned by this OAuth provider as the result of a successful client credentials grant. # @return [FusionAuth::ClientResponse] The ClientResponse object. def introspect_client_credentials_access_token(token) - body = { - "token" => token + form_parameters = { + "token" => token, } startAnonymous.uri('/oauth2/introspect') - .body_handler(FusionAuth::FormDataBodyHandler.new(body)) + .body_handler(FusionAuth::FormDataBodyHandler.new(form_parameters)) + .post + .go + end + + # + # Inspect an access token issued as the result of the Client Credentials Grant. + # + # @param request [OpenStruct, Hash] The client credentials access token. + # @return [FusionAuth::ClientResponse] The ClientResponse object. + def introspect_client_credentials_access_token_with_request(request) + form_parameters = { + "tenantId" => request.tenantId, + "token" => request.token, + } + startAnonymous.uri('/oauth2/introspect') + .body_handler(FusionAuth::FormDataBodyHandler.new(form_parameters)) .post .go end @@ -3586,13 +3782,13 @@ def retrieve_user_by_verification_id(verification_id) # @param user_code [string] The end-user verification code. # @return [FusionAuth::ClientResponse] The ClientResponse object. def retrieve_user_code(client_id, client_secret, user_code) - body = { + form_parameters = { "client_id" => client_id, "client_secret" => client_secret, - "user_code" => user_code + "user_code" => user_code, } startAnonymous.uri('/oauth2/device/user-code') - .body_handler(FusionAuth::FormDataBodyHandler.new(body)) + .body_handler(FusionAuth::FormDataBodyHandler.new(form_parameters)) .get .go end @@ -3607,15 +3803,55 @@ def retrieve_user_code(client_id, client_secret, user_code) # @param user_code [string] The end-user verification code. # @return [FusionAuth::ClientResponse] The ClientResponse object. def retrieve_user_code_using_api_key(user_code) - body = { - "user_code" => user_code + form_parameters = { + "user_code" => user_code, } startAnonymous.uri('/oauth2/device/user-code') - .body_handler(FusionAuth::FormDataBodyHandler.new(body)) + .body_handler(FusionAuth::FormDataBodyHandler.new(form_parameters)) .get .go end + # + # Retrieve a user_code that is part of an in-progress Device Authorization Grant. + # + # This API is useful if you want to build your own login workflow to complete a device grant. + # + # This request will require an API key. + # + # @param request [OpenStruct, Hash] The user code retrieval request including optional tenantId. + # @return [FusionAuth::ClientResponse] The ClientResponse object. + def retrieve_user_code_using_api_key_with_request(request) + form_parameters = { + "tenantId" => (request.tenantId.to_s unless request.tenantId.nil?), + "user_code" => request.user_code, + } + startAnonymous.uri('/oauth2/device/user-code') + .body_handler(FusionAuth::FormDataBodyHandler.new(form_parameters)) + .post + .go + end + + # + # Retrieve a user_code that is part of an in-progress Device Authorization Grant. + # + # This API is useful if you want to build your own login workflow to complete a device grant. + # + # @param request [OpenStruct, Hash] The user code retrieval request. + # @return [FusionAuth::ClientResponse] The ClientResponse object. + def retrieve_user_code_with_request(request) + form_parameters = { + "client_id" => request.client_id, + "client_secret" => request.client_secret, + "tenantId" => (request.tenantId.to_s unless request.tenantId.nil?), + "user_code" => request.user_code, + } + startAnonymous.uri('/oauth2/device/user-code') + .body_handler(FusionAuth::FormDataBodyHandler.new(form_parameters)) + .post + .go + end + # # Retrieves all the comments for the user with the given Id. # @@ -4953,6 +5189,21 @@ def validate_device(user_code, client_id) .go end + # + # Validates the end-user provided user_code from the user-interaction of the Device Authorization Grant. + # If you build your own activation form you should validate the user provided code prior to beginning the Authorization grant. + # + # @param request [OpenStruct, Hash] The device validation request. + # @return [FusionAuth::ClientResponse] The ClientResponse object. + def validate_device_with_request(request) + startAnonymous.uri('/oauth2/device/validate') + .url_parameter('client_id', request.client_id) + .url_parameter('tenantId', request.tenantId.nil? ? nil : request.tenantId.to_s) + .url_parameter('user_code', request.user_code) + .get + .go + end + # # Validates the provided JWT (encoded JWT string) to ensure the token is valid. A valid access token is properly # signed and not expired.