# 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)

<details>
<summary><big><b>Blueprinter</b></big></summary>
<hr />
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

    field :slack_username
    field :avatar_url, as: :avatar_remote_url
  end
end
```

Default serializator is given, but it can be overridden.
</details>

<details>
<summary><big><b>Devise</b></big></summary>
<hr />
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)
<br/><br/>
</details>

## Configuration

### InfinumID

```ruby
# config/initializers/infinum_id.rb

InfinumId.configure do |config|
  config.service_name = 'Revisor'
  config.resource_name = 'User'
  config.infinum_id_send_email = false
  config.resource_attributes = [:uid, :email, :first_name, :last_name, :deactivated_at, :time_zone, :avatar_url, :slack_username]
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.

    <b>Required columns:</b> email, uid, provider and deactivated_at. <br />
    <b>Optional columns:</b> 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

<details>
<summary><big><b>Webhooks</b></big></summary>
<hr />
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::AfterResourceCreate/InfinumId::AfterResourceUpdate are called. So if resource can't be created before setting role, you can override those methods and set role that way.

```ruby
# app/services/infinum_id/after_resource_create.rb

module InfinumId
  class AfterResourceCreate
    def self.call(person, params=nil)
      person.update(employee: true)
    end
  end
end
```
</details>

<details>
<summary><big><b>infinum_id_profile_edit_path</b></big></summary>
<hr />
Path to InfinumID profile of currently logged in user.
<br /><br />
</details>

<details>
<summary><big><b>Resource::Invite</b></big></summary>
<hr />

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)
```

</details>

<details>
<summary><big><b>Mailer</b></big></summary>
<hr />

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.

</details>

## License

The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).