Sign in with Apple in a Rails app
Get Apple API keys #
First of all, you need to create an Apple Developer account. It costs $99/year. Greedy bastards!
-
Create an app ID. Check “Sign in with Apple”; no need to click “Edit”.
Identifier
can be anything, but normally the reverse of your domain likecom.superails
. -
Create a service ID.
Identifier
can be anything, but normally the reverse of your domain likecom.superails.auth
. Check “Sign in with Apple”; click “Configure”.
You will now have access to these oAuth credentials:
Btw, Apple oAuth will not work on localhost, so I added a Ngrok URL for development purposes.
-
Create a key ID. Check “Sign in with Apple”. You will be able to download the
pem
secret key.
oAuth in your Rails app #
Install the gem omniauth-apple
# Gemfile
gem 'omniauth-rails_csrf_protection'
gem 'omniauth-apple'
Add a callback route. Apple login should go via POST, not GET.
# config/routes.rb
- get 'auth/apple/callback', to: 'sessions#create'
+ post 'auth/apple/callback', to: 'sessions#create'
button_to 'Login with Apple', '/auth/apple'
For apple oAuth you will need to set provider_ignores_state: true
.
To fix errors, you will also need to set nonce: :local
, provided by this PR. Use the branch:
- gem 'omniauth-apple'
+ gem 'omniauth-apple', github: 'bvogel/omniauth-apple', branch: 'fix/apple-session-handling'
Next, add your credentials:
# config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
provider :apple,
Rails.application.credentials.dig(:apple, :service_id),
'',
{
scope: 'email name',
team_id: Rails.application.credentials.dig(:apple, :team_id),
key_id: Rails.application.credentials.dig(:apple, :key_id),
pem: Rails.application.credentials.dig(:apple, :pem),
provider_ignores_state: true,
nonce: :local
}
end
Inside credentials.yml
it can look more-less like this:
# credentials.yml
apple:
service_id: serviceid
client_id: com.example.omniauthable
team_id: teamid
key_id: keyid
private_key: |
-----BEGIN PRIVATE KEY-----
foobarfoobarfoobarfoobarfoobar
foobarfoobarfoobarfoobarfoobar
foobarfoobarfoobarfoobarfoobar
foobarfoobarfoobarfoobarfoobar
-----END PRIVATE KEY-----"
Now when you click the “Sign in” button, everything should work and your app should receive a callback request to sessions#create
.
Here’s my SessionsController
.
skip_before_action :verify_authenticity_token, only: :create
is required for the POST request from Apple.
Everything else is applicable for any other oAuth strategy.
# app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
skip_before_action :verify_authenticity_token, only: :create
def create
@user = User.from_omniauth(request.env['omniauth.auth'])
if @user.persisted?
sign_in(@user)
redirect_path = request.env['omniauth.origin'] || user_path(@user)
redirect_to redirect_path, notice: t('sessions.success', name: @user.name)
else
redirect_to root_url, alert: t('sessions.failure')
end
end
def destroy
sign_out
redirect_to root_path, notice: t('sessions.destroy')
end
def failure
redirect_to root_path, alert: t('sessions.failure')
end
private
def sign_in(user)
Current.user = user
reset_session
cookies.encrypted.permanent[:user_id] = user.id
end
def sign_out
Current.user = nil
reset_session
cookies.delete(:user_id)
end
end
You can see how I implemented the from_omniauth
method here.
🤠That’s it! You can try to see how “Sign in with Apple” works on this website.
Did you like this article? Did it save you some time?