{"id":13483282,"url":"https://github.com/msa7/multi_auth","last_synced_at":"2025-04-14T19:36:16.161Z","repository":{"id":21582865,"uuid":"92581932","full_name":"msa7/multi_auth","owner":"msa7","description":"Standardized multi-provider OAuth authentication","archived":false,"fork":false,"pushed_at":"2023-02-22T10:47:37.000Z","size":82,"stargazers_count":111,"open_issues_count":7,"forks_count":23,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-28T08:01:42.040Z","etag":null,"topics":["crystal-lang","multiauth","oauth2","omniauth"],"latest_commit_sha":null,"homepage":"","language":"Crystal","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/msa7.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-05-27T07:55:06.000Z","updated_at":"2024-02-23T18:18:36.000Z","dependencies_parsed_at":"2024-05-02T20:06:42.913Z","dependency_job_id":null,"html_url":"https://github.com/msa7/multi_auth","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/msa7%2Fmulti_auth","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/msa7%2Fmulti_auth/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/msa7%2Fmulti_auth/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/msa7%2Fmulti_auth/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/msa7","download_url":"https://codeload.github.com/msa7/multi_auth/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248946835,"owners_count":21187583,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["crystal-lang","multiauth","oauth2","omniauth"],"created_at":"2024-07-31T17:01:09.692Z","updated_at":"2025-04-14T19:36:16.138Z","avatar_url":"https://github.com/msa7.png","language":"Crystal","funding_links":[],"categories":[":gem: Lucky Shards","Crystal","Framework Components","Marten shards"],"sub_categories":["Authentication"],"readme":"# MultiAuth\n\n![Build Status](https://github.com/msa7/multi_auth/workflows/CI/badge.svg)\n\nMultiAuth is a library that standardizes multi-provider authentication for web applications. Currently supported providers:\n\n- Github.com\n- Gitlab.com (or [own instance](https://github.com/msa7/multi_auth/blob/master/setup.md#gitlab))\n- Facebook.com\n- Vk.com\n- Google.com, [setup google](https://github.com/msa7/multi_auth/blob/master/setup.md#google)\n- Twitter.com\n- Restream.io\n\n## Installation\n\nAdd this to your application's `shard.yml`:\n\n```yaml\ndependencies:\n  multi_auth:\n    github: msa7/multi_auth\n```\n\n## Usage\n\n### MultiAuth public interface\n\n```crystal\n  require \"multi_auth\"\n\n  MultiAuth.config(\"github\", ENV['ID'], ENV['SECRET']) # configuration\n\n  multi_auth = MultiAuth.make(provider, redirect_uri) # initialize engine\n  multi_auth.authorize_uri  # URL to provider authentication dialog\n\n  # on http callback, like /multi_auth/github/callback\n  user = multi_auth.user(params) # get signed in user\n```\n\nMultiAuth build with no dependency, it can be used with any web framework. Information about signed in user described in User class here [src/multi_auth/user.cr](https://github.com/msa7/multi_auth/blob/master/src/multi_auth/user.cr). Supported providers [src/multi_auth/providers](https://github.com/msa7/multi_auth/blob/master/src/multi_auth/providers). I hope it easy to add new providers.\n\n### [Kemal](http://kemalcr.com) integration example\n\n```html\n\u003ca href=\"/multi_auth/github\"\u003eSign in with Github\u003c/a\u003e\n```\n\n```crystal\nMultiAuth.config(\"facebook\", \"facebookClientID\", \"facebookSecretKey\")\nMultiAuth.config(\"google\", \"googleClientID\", \"googleSecretKey\")\n\ndef self.multi_auth(env)\n  provider = env.params.url[\"provider\"]\n  redirect_uri = \"#{Kemal.config.scheme}://#{env.request.host_with_port.as(String)}/multi_auth/#{provider}/callback\"\n  MultiAuth.make(provider, redirect_uri)\nend\n\nget \"/multi_auth/:provider\" do |env|\n  env.redirect(multi_auth(env).authorize_uri)\nend\n\nget \"/multi_auth/:provider/callback\" do |env|\n  user = multi_auth(env).user(env.params.query)\n  p user.email\n  user\nend\n```\n\n### [Lucky](https://github.com/luckyframework/lucky) integration example\n\n```crystal\n# config/watch.yml\nhost: myapp.lvh.me\nport: 5000\n\n# config/multi_auth_handler.cr\nrequire \"multi_auth\"\n\nclass MultiAuthHandler\n  MultiAuth.config(\"facebook\", \"facebookClientID\", \"facebookSecretKey\")\n  MultiAuth.config(\"google\", \"googleClientID\", \"googleSecretKey\")\n\n  def self.authorize_uri(provider : String)\n    MultiAuth.make(provider, \"#{Lucky::RouteHelper.settings.base_uri}/oauth/#{provider}/callback\").authorize_uri(scope: \"email\")\n  end\n\n  def self.user(provider : String, params : Enumerable({String, String}))\n    MultiAuth.make(provider, \"#{Lucky::RouteHelper.settings.base_uri}/oauth/#{provider}/callback\").user(params)\n  end\nend\n\n# src/actions/oauth/handler.cr\nclass OAuth::Handler \u003c BrowserAction\n  get \"/oauth/:provider\" do\n    redirect to: MultiAuthHandler.authorize_uri(provider)\n  end\nend\n\n# src/actions/oauth/handler/callback.cr\nclass OAuth::Handler::Callback \u003c BrowserAction\n  get \"/oauth/:provider/callback\" do\n    user = MultiAuthHandler.user(provider, request.query_params)\n    text user.email.to_s\n  end\nend\n```\n\n### [Amber](https://github.com/amberframework/amber) integration example\n\n```crystal\n# config/initializers/multi_auth.cr\nrequire \"multi_auth\"\n\nMultiAuth.config(\"facebook\", \"facebookClientID\", \"facebookSecretKey\")\nMultiAuth.config(\"google\", \"googleClientID\", \"googleSecretKey\")\n\n# config/routes.cr\nroutes :web do\n  ...\n  get \"/multi_auth/:provider\", MultiAuthController, :new\n  get \"/multi_auth/:provider/callback\", MultiAuthController, :callback\nend\n\n# src/controllers/multi_auth_controller.cr\nclass MultiAuthController \u003c ApplicationController\n  def new\n    redirect_to multi_auth.authorize_uri(scope: \"email\")\n  end\n\n  def callback\n    multi_auth_user = multi_auth.user(request.query_params)\n\n    if user = User.find_by email: multi_auth_user.email\n      login user\n    else\n      user = User.create!(\n        first_name: multi_auth_user.first_name,\n        last_name: multi_auth_user.last_name,\n        email: multi_auth_user.email\n      )\n      login user\n    end\n\n    redirect_to \"/\"\n  end\n\n  def login(user)\n    context.session[\"user_id\"] = user.id\n  end\n\n  def provider\n    params[:provider]\n  end\n\n  def redirect_uri\n    \"#{Amber.settings.secrets[\"base_url\"]}/multi_auth/#{provider}/callback\"\n  end\n\n  def multi_auth\n    MultiAuth.make(provider, redirect_uri)\n  end\nend\n```\n\n### [Marten](https://github.com/martenframework/marten) integration example\n\n```crystal\n# config/initializers/multi_auth.cr\n# ----\n\nrequire \"multi_auth\"\n\nMultiAuth.config(\"github\", \"\u003cgithub_client_id\u003e\", \"\u003cgithub_secret_key\u003e\")\n\n\n# config/routes.cr\n# ----\n\nMarten.routes.draw do\n  path \"/oauth/\u003cprovider:string\u003e\", OAuthInitiateHandler, name: \"oauth_initiate\"\n  path \"/oauth/\u003cprovider:string\u003e/callback\", OAuthCallbackHandler, name: \"oauth_callback\"\nend\n\n\n# src/handlers/concerns/with_oauth.cr\n# ----\n\nmodule WithOAuth\n  def multi_auth\n    MultiAuth.make(provider, redirect_uri)\n  end\n\n  private def provider\n    params[\"provider\"].to_s\n  end\n\n  private def redirect_uri\n    \"#{request.scheme}://#{request.host}#{reverse(\"oauth_callback\", provider: provider)}\"\n  end\nend\n\n\n# src/handlers/oauth_initiate_handler.cr\n# ----\n\nrequire \"./concerns/**\"\n\nclass OAuthInitiateHandler \u003c Marten::Handler\n  include WithOAuth\n\n  def get\n    redirect multi_auth.authorize_uri(scope: \"email\")\n  end\nend\n\n\n# src/handlers/oauth_initiate_callback.cr\n# ----\n\nrequire \"./concerns/**\"\n\nclass OAuthCallbackHandler \u003c Marten::Handler\n  include WithOAuth\n\n  def get\n    user_params = Hash(String, String).new.tap do |params|\n      request.query_params.each { |k, v| params[k] = v.last }\n    end\n    \n    multi_auth_user = multi_auth.user(user_params)\n\n    unless user = Auth::User.get(email: multi_auth_user.email)\n      user = Auth::User.create!(email: multi_auth_user.email) do |new_user|\n        new_user.set_unusable_password\n      end\n    end\n\n    MartenAuth.sign_in(request, user)\n\n    redirect \"/\"\n  end\nend\n```\n\n## Development\n\nInstall docker\n\nSetup everythings\n\n```\nmake setup\n```\n\nRun specs\n\n```\nmake t\nmake t c=spec/providers/twitter_spec.cr\n```\n\nRun code linter\n\n```\nmake l\n```\n\n## Contributors\n\n- [Sergey Makridenkov](https://github.com/msa7) - creator, maintainer\n- [Vitalii Elenhaupt](https://github.com/veelenga) - contributor\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmsa7%2Fmulti_auth","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmsa7%2Fmulti_auth","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmsa7%2Fmulti_auth/lists"}