Ruby on Rails Google Login API only mode
in Development on Rails
Ruby on Rails에서 Social Login을 하기 위해서는 omniauth-oauth2 기반의 gem들을 사용하는게 가장 일반적인 방법이다.
- Google Login : omniauth-google-oauth2
- Facebook Login : omniauth-facebook
- Naver Login : omniauth-naver
- Kakao Login : omniauth-kakao
- Line Login : omniauth-line
잠깐! 위에서 Kakao와 Line은 정상동작하지 않는다. 좀 더 자세히 설명하자면 omniauth-google-oauth2를 정상적으로 사용하려면 omniauth-oauth2 1.6버전 이상이 필요한데, omniauth-kakao 와 omniauth-line은 1.3버전에서 정상동작하게 되어 있다. 그래서 omniauth-kakao와 omniauth-line를 1.7버전 이상에서 정상동작하도록 Fork
떠서 수정하였다. 정상동작하는 gem은 아래에서 확인 가능하다.
- Kakao Login : DevStarSJ/omniauth-kakao
- Line Login : DevStarSJ/omniauth-line
Gemfile
선언시 아래와 같이 하면 된다.
gem 'omniauth-kakao', git: "https://github.com/DevStarSJ/omniauth-kakao"
gem 'omniauth-line', git: "https://github.com/DevStarSJ/omniauth-line"
둘 다 response되는 정보에 email
이 빠져있어서 해당 정보들도 추가하였다.
먼저 검색
위 gem들을 사용해서 Social Login을 구현하기 위해서 자료들을 검색해보았다. 그런데 대부분 MVC로 구현하고 devise를 이용하는 방법밖에 없었다. 참고로 user 인증은 별도로 구현하였으며, API server를 만드는 중이라 View가 필요없다. 해당 gem의 github를 보더라도 MVC로 구현하는 방법은 자세히 나와 있지만, API only에서 활용가능한 방법은 안내가 나와있지 않다. 글 내용을 보면 API only에서는 필요없음 등이 있는 것으로봐서 분명 가능은 하다는 이야기인데 정작 하는 방법에 대해서 설명이 없다. 나와 같이 사용하는 경우에 대해서 안내해주는 글을 못찾았다.
공식 github의 README에 안내해주지 않은 내용 중에 API only로 사용하기 위해서 필요한 내용은 정말 몇가지 2가지 정보만 있으면 된다. 그런데 그게 없다.
- Google Auth를 호출하는 API path
- callback을 받을 API path
callback을 받을 위치는 설정이 가능하므로 굳이 없어도 가능은 하다.
정답부터 말하자면
- Google Auth를 호출하는 API path :
/auth/google_oauth2
- callback을 받을 API path :
auth/google_oauth2/callback
참고로 이 사실을 이미 알고 난 뒤 다시 omniauth-google-oauth2를 보니 관련 내용이 아주 짧게 언급되어 있었다.
You can now access the OmniAuth Google OAuth2 URL:
/auth/google_oauth2
그동안 같은 고민을 하면서 위치를 못 찾은 분들은 위 정보만으로도 충분할 것이다. 아래 내용은 필요없을 것이다. 나는 이걸 어떻게 발견했냐면 Ajay Ramesh라는 분이 쓴 medium 글에 나와있었다.
https://medium.com/@ajayramesh/social-login-with-omniauth-and-rails-5-0-ad2bbd2a998e
위 글을 참고하여 실습을 진행했고, 정상적으로 동작하는 것을 확인하였다. 그럼 지금부터 내용들을 적어보겠다.
1. Google API에 App 등록
https://console.cloud.google.com로 들어가서 API
-> 사용자 인증 정보
를 만든 다음 OAuth 2.0 Client ID
에서 Client ID
와 Client Secret
을 확인한다. 아래에서 필요한 정보이다.
일단 Test는 local에서 실행할 것이며 Rails에서 기본적으로 실행하는 local주소는 http://localhost:3000 이다. 그래서 URIs 정보에 http://localhost:3000
를 넣어주고, Authorized redirect URIs에 http://localhost:3000/auth/google_oauth2/callback
를 추가한다.
2. Gem Install
Gemfile에 아래 줄을 추가한다.
gem 'omniauth-google-oauth2'
Bundle을 실행하여 Install을 한다.
bundle install
3. Model 생성
필자의 경우 User Model과 SocialAuth Model을 분리하였다. 왜냐면 1명의 User에게 여러 Social Login을 가능하게 하기 위해서이다.
3.1 User Model 생성
rails g model User
를 실행하여 Migration 파일을 수정한다.
class CreateUsers < ActiveRecord::Migration[6.0]
def change
create_table :users do |t|
t.string :email, null: false
t.string :password_digest
t.timestamps
end
end
end
password
는 nullable로 설정하였다. 왜냐면 password
가 없는 경우 Social Login만을 허용하기 위해서다. 하지만 Model에서 Null Check를 하므로 validation을 하지 않는 것으로 선언해야 한다.
user.rb
class User < ApplicationRecord include ActiveModel::SecurePassword has_secure_password validations: false end
rails db:migrate
를 실행하여 Model을 생성한다.
3.2 SocialAuth Model 생성
rails g model SocialAuth
를 실행하여 Migration 파일을 생성 후
class CreateSocialAuths < ActiveRecord::Migration[6.0]
def change
create_table :social_auths do |t|
t.string :provider, null: false
t.string :uid, null: false
t.string :first_name
t.string :last_name
t.string :email
t.string :photo
t.references :user, null: false, foreign_key: false
t.timestamps
end
end
end
위 내용과 같이 수정한다.
social_auth.rb
class SocialAuth < ApplicationRecord belongs_to :user end
Model 파일을 수정한 뒤 rails db:migrate
를 실행하여 Model을 생성한다.
4. Initialize 선언
config/initializers/omniauth.rb
파일을 생성하여 아래와 같이 입력한다.
Rails.application.config.middleware.use OmniAuth::Builder do
provider :google_oauth2, ENV['GOOGLE_CLIENT_ID'], ENV['GOOGLE_CLIENT_SECRET']
end
.env
파일에 위에서 확인한 Client ID
와 Client Secret
를 각각 GOOGLE_CLIENT_ID
와 GOOGLE_CLIENT_SECRET
로 등록한다. 참고로 .env
파일을 적용하려면 dotenv-rails를 설치해야 한다.
5. Route 선언
routes.rb
파일에 아래 내용을 추가한다.
get 'auth/google', to: redirect('/auth/google_oauth2')
get 'auth/google_oauth2/callback', to: 'auth#google'
API 주소를 /auth/google_oauth2
에서 auth/google
로 수정하였다.
6. Controller, Service 선언
auth_controller.rb
파일을 생성하여 아래와 같이 입력한다.
class AuthController < ApplicationController
def google
user = SocialAuthService.google(omniauth_params)
render json: user
end
private
def omniauth_params
request.env['omniauth.auth'].except('extra').to_h
end
end
참고로 인증받은 구글에서의 profile정보는 request.env['omniauth.auth']
에서 확인이 가능하다. 예제에서는 User Model을 그대로 response해주는 것으로 해 놓았다. 실제 사용할때는 생성되거나 찾은 사용자 정보에서 JWT Token등을 생성해서 전달해 준다던지, request.env['omniauth.auth']
안에 있는 token을 그대로 사용하는 방법이 있겠다.
social_auth_service.rb
파일을 생성하여 아래와 같이 입력한다.
class SocialAuthService
def self.google(params)
apply(params, 'google')
end
def self.apply(params, provider)
return nil unless params["provider"].present? && params["uid"].present? && params["info"].present?
return nil unless params["provider"].include?(provider)
social_auth = initialize(params, provider)
social_auth.user
end
def self.initialize(params, provider)
SocialAuth.where(provider: provider, uid: params["uid"]).first_or_create do |auth|
auth.provider = provider
auth.uid = params["uid"]
auth.email = params["info"]["email"]
auth.first_name = params["info"]["first_name"] || params["info"]["name"]
auth.last_name = params["info"]["last_name"]
auth.photo = params["info"]["image"]
link_user(auth)
end
end
def self.link_user(auth)
return if auth.user_id.present?
user = User.find_by(email: auth.email)
user = User.create(email: auth.email) if user.blank?
auth.user = user
end
end
.first_or_create
는 앞에 조건에 만족하는 첫번째 instance를 반환하거나 없다면 block에 선언한대로 새로 생성을 한다. 여기서 찾거나 새로 생성한 SocialAuth
에서 전달받은 email
정보를 가지고 User를 검색한 후, 있으면 그 User와 연결을 하고 없다면 User를 새로 생성한다. 이 부분 역시 .first_or_create
를 사용해도 된다.
7. 실행 및 확인
이제 서버를 실행해서 확인해보자.
rails s
로 서버를 실행한 다음 http://localhost:3000/auth/google 를 Browser에서 실행하면 서버를 실행한 로그에 각 Model이 생성되는 SQL문을 볼 수 있으며, 화면에도 새로 생성된 사용자 정보를 볼 수 있다. 참고로 request.env['omniauth.auth']
정보를 확인해보고 싶다면 AuthController.google
의 내용을 render json: omniauth_params
로 수정을 하던지, 아니면 해당 method 안에서 binding.pry
를 걸어서 확인해보면 된다.
아래의 모양으로 되어 있다.
{
"provider"=>"google_oauth2",
"uid"=>"1234567890",
"info"=>
{
"name"=>"Yun Seokjoon",
"email"=>"seokjoon.yun@gmail.com",
"unverified_email"=>"seokjoon.yun@gmail.com",
"email_verified"=>true,
"first_name"=>"Yun",
"last_name"=>"Seokjoon",
"image"=>"https://lh3.googleusercontent.com/a-/AOh14Ghld2CXOEoClXk9ciHU9XdRHpg5j64ZpqYtcn-W=s96-c"
},
"credentials" =>
{
"token"=>"xxxx.xxxxxxxxcxcxcxcxcxcxcxcxcxcxcxcxxcxc",
"refresh_token"=>"x//xcxcxcxcxcxcxcxcxcx-xcxcxcxcxcxcxcxcxcxcxc-xcxcxcxcxcxcxcxcxcxcxxc",
"expires_at"=>1606465984,
"expires"=>true
}
}
마치며…
위에서 소개한 방법을 적용한 예제코드는 아래 Link에서 확인이 가능하다.
https://github.com/DevStarSJ/backend_boilerplates/tree/master/rails
이로서 Google Login
에 대한 안내는 마치겠다.
다른 Social Login의 방법은 아래에서 확인이 가능하다.
- Ruby on Rails Google Login API only mode
- Ruby on Rails Facebook Login API only mode
- Ruby on Rails Naver Login API only mode
- Ruby on Rails Kakao Login API only mode
- Ruby on Rails Line Login API only mode
이 글이 도움이 되셨다면 공감 및 광고 클릭을 부탁드립니다 :)