# AppleAuth [![Gem Version](https://badge.fury.io/rb/apple_auth.svg)](https://badge.fury.io/rb/apple_auth) ![CI](https://github.com/rootstrap/apple_auth/actions/workflows/ci.yml/badge.svg?branch=master) [![Maintainability](https://api.codeclimate.com/v1/badges/78453501221a76e3806e/maintainability)](https://codeclimate.com/github/rootstrap/apple_sign_in/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/78453501221a76e3806e/test_coverage)](https://codeclimate.com/github/rootstrap/apple_sign_in/test_coverage) ## Installation Add this line to your Gemfile: ```ruby gem 'apple_auth' ``` And then execute: $ bundle install Or install it yourself: $ gem install apple_auth --- After installing the gem, you need to run this generator. $ rails g apple_auth:config This will generate a new initializer: `apple_auth.rb` with the following default configuration: ```ruby AppleAuth.configure do |config| # config.apple_client_id = # config.apple_private_key = # config.apple_key_id = # config.apple_team_id = # config.redirect_uri = end ``` Set your different credentials in the file by uncommenting the lines and adding your keys. --- ## Usage Here's an example of how to configure the gem: ```ruby AppleAuth.configure do |config| config.apple_client_id = 'com.yourapp...' config.apple_private_key = "-----BEGIN PRIVATE KEY-----\nMIGTAgEA....\n-----END PRIVATE KEY-----" config.apple_key_id = 'RTZ...' config.apple_team_id = 'WNU...' config.redirect_uri = 'https://localhost:3000' end ``` We strongly recommend to use environment variables for these values. ### Apple sign-in workflow: ![alt text](https://docs-assets.developer.apple.com/published/360d59b776/rendered2x-1592224731.png) For more information, check the [Apple oficial documentation](https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_rest_api). ### Validate JWT token and get user information: ```ruby # with a valid JWT user_id = '000343.1d22d2937c7a4e56806dfb802b06c430...' valid_jwt_token = 'eyJraWQiOiI4NkQ4OEtmIiwiYWxnIjoiUlMyNTYifQ.eyJpc...' AppleAuth::UserIdentity.new(user_id, valid_jwt_token).validate! >> { exp: 1595279622, email: "user@example.com", email_verified: true , ...} # with an invalid JWT invalid_jwt_token = 'eyJraWQiOiI4NkQsd4OEtmIiwiYWxnIjoiUlMyNTYifQ.edsyJpc...' AppleAuth::UserIdentity.new(user_id, invalid_jwt_token).validate! >> Traceback (most recent call last):.. >> ... >> AppleAuth::Conditions::JWTValidationError ``` ### Verify user identity and get access and refresh tokens: ```ruby code = 'cfb77c21ecd444390a2c214cd33decdfb.0.mr...' AppleAuth::Token.new(code).authenticate! >> { access_token: "a7058d...", expires_at: 1595894672, refresh_token: "r8f1ce..." } ``` ### Handle server to server notifications from the request parameter :payload ```ruby # with a valid JWT params[:payload] = "eyJraWQiOiJZ......" AppleAuth::ServerIdentity.new(params[:payload]).validate! >> {iss: "https://appleid.apple.com", exp: 1632224024, iat: 1632137624, jti: "yctpp1ZHaGCzaNB9PWB4DA",...} # with an invalid JWT params[:payload] = "asdasdasdasd......" AppleAuth::ServerIdentity.new(params[:payload]).validate! >> JWT::VerificationError: Signature verification raised ``` Implementation in a controller would look like this: ```ruby class Hooks::AuthController < ApplicationController skip_before_action :verify_authenticity_token # https://developer.apple.com/documentation/sign_in_with_apple/processing_changes_for_sign_in_with_apple_accounts # NOTE: The Apple documentation states the events attribute as an array but is in fact a stringified json object def apple # will raise an error when the signature is invalid payload = AppleAuth::ServerIdentity.new(params[:payload]).validate! event = JSON.parse(payload[:events]).symbolize_keys uid = event["sub"] user = User.find_by!(provider: 'apple', uid: uid) case event[:type] when "email-enabled", "email-disabled" # Here we should update the user with the relay state when "consent-revoked", "account-delete" user.destroy! else throw event end render plain: "200 OK", status: :ok end end ``` ## Using with Devise If you are using devise_token_auth gem, run this generator. $ rails g apple_sign_in:apple_auth_controller [scope] In the scope you need to write your path from controllers to your existent devise controllers. An example `$ rails g apple_auth:apple_auth_controller api/v1/` This will generate a new controller: `controllers/api/v1/apple_auth_controller.rb`. You should configure the route, you can wrap it in the devise_scope block like: ``` devise_scope :user do resource :user, only: %i[update show] do controller :apple_auth do post :apple_auth, on: :collection, to: 'apple_auth#create' end end end ``` ## Demo You can find a full implementation of this gem in [this demo](https://github.com/rootstrap/apple-sign-in-rails). ## Development After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). ## Contributing Bug reports and pull requests are welcome on GitHub at https://github.com/rootstrap/apple_auth/issues. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/rootstrap/apple_auth/blob/master/CODE_OF_CONDUCT.md). ## License The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). ## Code of Conduct Everyone interacting in the AppleAuth project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/rootstrap/apple_auth/blob/master/CODE_OF_CONDUCT.md). ## Credits apple_auth gem is maintained by [Rootstrap](http://www.rootstrap.com) with the help of our [contributors](https://github.com/rootstrap/apple_auth/contributors). [](http://www.rootstrap.com)