Skip to content

Latest commit

 

History

History
229 lines (161 loc) · 5.5 KB

README.md

File metadata and controls

229 lines (161 loc) · 5.5 KB

Ruby Rails

Alfred

Alfred is a proprietary technology for user authentication. This is a standalone application that is used to simplify the authentication process in your client application.

Features

  • Strategy to authenticate with Discord via OAuth2
  • Ability to invite users
  • Custom validations for Cybergizer members
  • Token generation

How to use it?

To authenticate a user through Alfred, follow these steps:

  1. Your application must be registered in Alfred.
ALFRED_HOST = alfred.cybergizer.com

On the frontend

  1. You need to redirect user to Alfred (more info here):

    'https://{ALFRED_HOST}/oauth/authorize?client_id={UID_OF_YOUR_APPLICATION}&redirect_uri={REDIRECT_URI_OF_YOUR_APPLICATION}&response_type=code&scope=user'
  2. After the user is successfully authenticated, Alfred will send the code:

    'https://{HOST_OF_YOUR_APPLICATION}/?code={YOUR_CODE}'
  3. Send the code to the backend with a post request:

    POST 'https://{HOST_OF_BACKEND_APPLICATION}/api/v1/auth'
    {
      "code": "{YOUR_CODE}"
    }

On the backend

  1. Send a request to get a token from alfred using the code you received earlier:

    POST 'https://{ALFRED_HOST}/oauth/token'

    with body:

    {
      "grant_type": "authorization_code",
      "code": "{YOUR_CODE}",
      "client_id": "{UID_OF_YOUR_APPLICATION}",
      "client_secret": "{SECRET_OF_YOUR_APPLICATION}",
      "redirect_uri": "{REDIRECT_URI_OF_YOUR_APPLICATION}",
      "scope": "user"
    }
  2. Submit a request to obtain user data from Alfred:

    GET 'https://{ALFRED_HOST}/api/v1/users/me'

    with header:

    {
      "authorization": "Bearer #{YOUR_CODE}"
    }

    After that, you will receive data about the user in json format, like this:

    {
      "id": 1,
      "uid": "1130004065675965",
      "first_name": "John",
      "last_name": "Doe",
      "email": "[email protected]",
      "dob": "2000-01-01",
      "avatar": "https://{ALFRED_HOST}/rails/active_storage/database/....jpg"
    } 

    Use this data to create a user in your client application.

Documentation

Here you will find more information about Alfred

Installation

Clone repository

git clone [email protected]:cybergizer-hq/alfred.git

Run configuration commands

bundle install
rails db:create db:migrate

Run rails server

rails s

Setup specs

docker compose up -d
RAILS_ENV=test bundle exec rails db:setup

Run specs

bundle exec rspec

Configuration

Alfred uses the following gems:

Environment Version
Ruby 2.7.1
Rails 6.0.2
Omniauth 1.9
Omniauth-discord -
Doorkeeper 5.3
Doorkeeper-openid_connect -
Devise 4.7

Getting started

If you want to implement Alfred using Devise in your application follow the instructions.

Set up Devise in your application. You can use the official guide.

Then add the following line to your Gemfile:

gem 'omniauth-alfred', git: 'https://github.com/cybergizer-hq/omniauth-alfred', branch: 'master'

Run:

bundle install

Update config/initializers/devise.rb with omiauth config:

config.omniauth :alfred, ENV.fetch('ALFRED_KEY', nil), ENV.fetch('ALFRED_SECRET', nil), scope: 'user'

ALFRED_KEY - uid of your Alfred application

ALFRED_SECRET - secret of your Alfred application

Add Routes and Controller

Add omniauth callbacks to config/routes.rb:

devise_for :users, :controllers => { :omniauth_callbacks => "callbacks" }

And create new controller for handle callback:

class OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def alfred
    @user = User.from_omniauth(request.env['omniauth.auth'])
    sign_in_and_redirect @user
  end
end

Add Support Omniauth to Your Model

Add uid and provider fields to users table:

rails g migration AddProviderAndUidToUsers provider uid
bundle exec rake db:migrate

Add omniauthable module and from_omniauth class method to the model:

class User < ApplicationRecord
   devise :database_authenticatable, :registerable,
         :rememberable, :validatable, :omniauthable, omniauth_providers: [:alfred]
  
  def self.from_omniauth(auth)
    if (user = find_by_email(auth.info.email))
      return user if user.uid

      user.update(provider: auth.provider, uid: auth.uid)
      user
    else
      where(provider: auth.provider, uid: auth.uid).first
    end
  end
end