FusionAuth is a platform and framework agnositc modern CIAM tool to integrate authentication, authorization and user management into your applications. FusionAuth supports many applications in one easy to use browser interface. Features are exposed in API's that allow flexibility and customizable user experiences. In this tutorial we will demonstrate integrating FusionAuth with the light-weight Ruby framework Sinatra.
The best way to integrate with Sinatra is using the FusionAuth Ruby client library. The API will provide all of the necessary methods to create user access management.
This tutorial will illustrate creating a Sinatra application, JSCRUM - a Pied Piper Agile Management App by Jared, with FusionAuth that allows users to register, login, view and edit profile information, logout, and delete their accounts. Check out the example FusionAuth Sinatra Application here
- Installing and configuring FusionAuth
- Requiring FusionAuth in Sinatra
- Registering a user
- Log in a user
- Accessing and viewing profile information
- User updates their profile information
- Log out a user
- Delete a user
- Summary
- FusionAuth
- Ruby
- Bundler
- Ruby development environment
- Web browser
To begin you can follow the Setup Guide. For this tutorial there is no need to complete the OAuth settings. It does require creating an API key and an Application. The API key and Application ID will be necessary in the Sinatra application.
After you have created an application and API key you may continue.
Assuming you have bundler installed all you need to do to include FusionAuth is add the gem to your Gemfile as such:
in Gemfile:
source 'https://rubygems.org'
#all other gems needed
gem fusionauth_client
To install the gem simply run bundle
in your command line.
To access FusionAuth in your Sinatra application file simply require it at the top:
in app.rb:
require 'fusionauth/fusionauth_client'
require 'sinatra'
require 'sinatra/flash'
require 'sinatra/json'
require 'sinatra/cookies'
require 'json'
require 'pry'
Tilt.register Tilt::ERBTemplate, 'html.erb'
class FusionAuthApp < Sinatra::Base
helpers Sinatra::Cookies
use Rack::Session::Cookie, :key => 'rack.session',
:path => '/',
:secret => ENV['SECRET']
def fusionauth_client
@client = FusionAuth::FusionAuthClient.new(
'XyF5-fU3a-eeYMCx_PHaGAs18NMIGxRF4UPE1A8dA-U',
'http://localhost:9011'
)
end
def current_user
@current_user ||= fusionauth_client.retrieve_user(session[:user_id]).success_response.user if session[:user_id]
end
def application_id
'9eef04cd-b188-42fa-b535-1962ff788b46'
end
The above code shows the necessary requirements in Sinatra. It also sets the application to allow html.erb
extensions on views, and enable sessions and cookies. The FusionAuth client is defined in a method using the API key and the default address FusionAuth runs on locally (localhost:9011). The application ID will be needed for various API calls so is made available in a method within the class. Current user is helpful for displaying user information in views and in many methods throughout this tutorial.
When registering a user there are two options:
- Full Registration - Provide the User and UserRegistration object to create the user and register them for the application.
- Existing users may be registered by simply providing the UserRegistration object.
You may also provide a user id which allows FusionAuth to look up an existing user for registration or use that ID for the newly created User.
This tutorial will follow Full Registration
The following code shows the app.rb file in the Sinatra application:
get '/register' do
if current_user != nil
erb :'/users/show'
else
erb :'/users/new'
end
end
post '/register' do
user_data = params[:user_data]
id = SecureRandom.uuid
response = fusionauth_client.register(id, {
:user => {
:firstName => user_data[:first_name],
:lastName => user_data[:last_name],
:email => user_data[:email],
:password => user_data[:password]
},
:registration => {
:applicationId => application_id,
:preferredLanguages => %w(en fr),
:roles => %w(user)
}
})
if response.success_response
session[:user_id] = id
erb :'/users/show'
else
flash[:error] = 'Registration unsuccessful. Please try again.'
erb :'/welcome/index'
end
end
The user can click the link on the home page to register. As long as no one is logged in already it will take the user to the registration form.
Clicking the registration link takes the user to the registration form:
As seen in the code above, the register method on FusionAuth client takes in user data as passed in through the form. The Application ID is a necessary parameter for registration. Most others are optional. A random UUID is generated for safer indexing of the user. Remember to use the Registration API as a reference.
Upon successful registration:
With successful registration the user is directed to their profile page where a flash message shows registration was successful and we can see user information displayed on the page. An unsuccessful registration results in an error message and the user is taken back to the registration page.
After completing registration and going to the FusionAuth UI, we can see the new user was added under users.
Attempting to create a user with the same e-mail will result in an error. Using the provided Errors API will help debug issues such as duplicate email error:
Logging in a user is a simple API call. The users loginID (their email or username) as well as the users password are required. All other parameters are optional though it is common use case to provide the Application ID.
post '/login' do
user_data = params[:user_data]
response = fusionauth_client.login({
:loginId => user_data[:email],
:password => user_data[:password],
:applicationId => application_id,
})
if response.success_response
id = response.success_response.user.id
session[:user_id] = id
erb :'/users/show'
else
flash[:error] = "Unsuccessful login. Please try again."
erb :'sessions/new'
end
end
If you wanted to see user information as pure JSON the Ruby client provides retrieve_user methods. You can retrieve user with email, username, verification ID, user ID, change password ID, or JWT. Reference: Retrieve User API
In this tutorial we will retrieve the user by user ID using our current_user method.
get '/user', :provides => :json do
response = fusionauth_client.retrieve_user(current_user.id)
if response.success_response
new_response = response.success_response.user.marshal_dump
registration = new_response[:registrations][0].marshal_dump
new_response[:registrations][0] = registration
json new_response
else
flash[:error] = "Cannot find user information. Please try again."
end
end
By going to /user
when the user is logged in we get a JSON response of the user data:
Above you can see the user data has been retrieved and displayed in JSON format in the browser.
Let's say a user wants to update their profile, we should give them a way to do so! The FusionAuth Ruby client provides a patch_user
method that will do exactly what we need. See the Update a User API here.
In the application within the user profile there is a link to update their profile.
Clicking the link allows the user to update specified information in the user table. For this example we are simply allowing the user to update their name or e-mail.
By submitting the form the updated information is passed into the patch method :
get '/edit' do
erb :'users/edit'
end
patch '/users/:id' do
request = params[:user_data].select {|k,v| v != ''}
patch_request = { user: request }
response = fusionauth_client.patch_user(current_user.id, patch_request)
if response.success_response
flash[:success] = "Update successful!"
erb :'/users/show'
else
flash[:error] = "Update unsuccessful. Please try again."
erb :'/upate'
end
end
Here we pull in the new user information in parameters, and without having any requirements to make sure no fields are left empty, we instead filter which data we want to update by any data passed in that is not an empty string.
The patch request is formatted as a hash, and must have the user:
key. The value of the user key is the hash of updated key value pairs obtained from the params.
Next we call the patch_user
method on the FusionAuth client, with two arguments. The user ID must be provided, as well as the patch request. If we get a successful response, we are able to see the users updated profile and a success message. You may need to refresh the page to see the updated user information.
Success! Gilfoyle's profile just got a little better.
Gilfoyle is a busy guy, so he can't stay logged in forever. We need to give him a way to get back to work and stay ahead of Dinesh. On the profile we have added a logout button.
Simply clicking the logout button will route to the method in the app.rb file that takes care of logging out the user. We use the FusionAuth logout.
get '/logout' do
fusionauth_client.logout(true, nil)
session.clear
cookies.clear
flash[:notice] = "Logout Successful"
erb :'/welcome/index'
end
The method takes two arguments, the first being the param global, which takes a boolean. Setting global to true revokes all refresh tokens attached to the current user. We have not enabled refresh tokens, but for the sake of example we are setting this value to true. The second argument is optional and can be used to provide a specific refresh token. If provided the argument token would take precedence over the refresh token coming in as a cookie.
Without using refresh_tokens we use the manual session.clear
and cookies.clear
to remove any tokens associated in the browser with the user.
Simply clicking the logout button logs the user out and returns them to the welcome page with a success message letting the user know they were logged out.
Dinesh is really getting ahead, so to keep up Gilfoyle has decided to delete his account. We allow him to do so by providing a button on his profile.
In our app.rb file we user the FusionAuth delete to remove the user from our application.
delete '/delete_account' do
fusionauth_client.delete_user(current_user.id)
flash[:notice] = "Account Successfully deleted"
erb :'/welcome/index'
end
Once deleted we see the success message and are returned to the welcome page.
We have integrated FusionAuth with Sinatra and easily introduced user management to our application.
FusionAuth is not intended to replace domain management systems such as Active Directory and does not offer native desktop integration.
FusionAuth is useful when you are managing users among many applications and scales well. There is a multitude of untouched functionality in this tutorial such as e-mail, multi-factor authentication, and reporting. Best of all, the web console provides an easy to use interface to visualize your applications, users and more.