# InfinumId Engine
InfinumId Engine is gem for resource authentication with [InfinumID](https://github.com/infinum/rails-infinum-id) server.
## Table of Contents
- [Installation](#installation)
- [Dependencies](#dependencies)
- [Configuration](#configuration)
* [InfinumID](#infinumid)
* [Secrets](#secrets)
- [Usage](#usage)
- [Features](#features)
## Installation
Add this line to your application's Gemfile:
```ruby
gem 'infinum_id'
```
And then execute:
$ bundle
Or install it yourself as:
$ gem install infinum_id
## Dependencies
* [Blueprinter](https://github.com/procore/blueprinter)
* [Devise](https://github.com/plataformatec/devise)
* [Dry configurable](https://github.com/dry-rb/dry-configurable)
* [Http](https://github.com/httprb/http)
* [Omniauth::InfinumId](https://github.com/infinum/ruby-infinum-id-omniauth)
* [Redis](https://github.com/antirez/redis)
Blueprinter
When new user is being created in application, info of that user is being sent to InfinumID to create user there as well.
Model of user in application might not be the same as on in InfinumID. So parametars need to be changed to match one on InfinumID.
For example, url to profile picture in application is called avatar_remote_url and in InfinumID it's called avatar_url.
```ruby
# app/blueprints/infinum_id/resource_blueprint.rb
module InfinumId
class ResourceBlueprint < Blueprinter::Base
identifier :email
fields :first_name, :last_name, :employee
field :slack_username
field :avatar_url, as: :avatar_remote_url
end
end
```
Default serializator is given, but it can be overridden.
Devise
Devise is used like middleware for authentication that uses Omniauth with infinum_id strategy. Devise should be configured inside model that will be authenticated. When configured all methods of devise can be used (e.g. current_user)
## Configuration
### InfinumID
```ruby
# config/initializers/infinum_id.rb
InfinumId.configure do |config|
config.service_name = 'Revisor'
config.resource_name = 'User'
config.send_invite_request = !Rails.env.test? # to disable in tests
config.resource_attributes = [:uid, :email, :first_name, :last_name, :deactivated_at, :time_zone, :avatar_url, :slack_username, :employee]
end
```
Configuration options:
* Service name - name of application
* Resource name - name of resource on whom authentication is being done
* InfinumID send email - toggle if InfinumID should send invite email or application (false for InfinumID)
* Resource attributes - list of resource attributes that will be send to InfinumID when new user is created
### Secrets
Needed secrets:
```ruby
# config/secrets.yml
infinum_id:
client_id: 'client_id_from_InfinumID'
client_secret: 'client_secret_from_InfinumID'
url: 'InfinumID_url'
redis_server_url: 'redis_server_url'
redis_client_url: 'redis_client_url'
```
## Usage
1. Add columns to resource via migration.
Required columns: email, uid, provider and deactivated_at.
Optional columns: first_name, last_name, avatar_url, slack_username, time_zone
2. Set same columns in resource attribute config of infinum_id engine
3. Add following rows to resource model:
```ruby
devise :omniauthable, omniauth_providers: [:infinum_id]
def active_for_authentication?
super && !deactivated_at
end
```
4. Create AuthenticatedController and inherit it in all controllers that needs to be protected with authentication
```ruby
class AuthenticatedController < ApplicationController
before_action :authenticate_user!
end
```
## Features
Webhooks
In engine there are two webhooks: `UpdateResourceCallback` & `CreateResourceCallback`.
When user is created or updated on InfinumID these webhooks are called and then resource is created or updated accordingly.
After resource is created or updated methods `InfinumId::AfterResourceUpsert` is called. So if resource can't be created before setting role, you can override this class and set role that way.
`intent` is one of `InfinumId::AfterResourceIntent::CREATE` or `InfinumId::AfterResourceIntent::UPDATE.`
```ruby
# app/services/infinum_id/after_resource_create.rb
module InfinumId
class AfterResourceUpsert
def self.call(person, _params = nil, _intent = nil)
person.update(employee: true)
end
end
end
```
infinum_id_profile_edit_path
Path to InfinumID profile of currently logged in user.
Resource::Invite
Resource::Invite calls creates new user by given user parameters and sends request to InfinumID server. If user does not exist on InfinumID server user will be created there. If user existed on InfinumID Welcome email will be sent, if not Invite email with link to InfinumID server will be sent where user can finish his account creation.
```ruby
# app/controllers/users_controller.rb
user = InfinumId::Resources::Invite.call(user_params, current_user)
```
Mailer
There are two mailer: WelcomeMailer & InviteMailer.
WelcomeMailer is being used when user exists on InfinumID and we just invited him to application.
InviteMailer is being used when user doesn't exist on InfinumID and account was just created there and in mail invitation link is sent to finish account creation.
## License
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).