Drop in authorization and authentication suite for Rails APIs.
ApiGuardian includes the following features out of the box:
- User registration (email/pass)
- Password reset workflow
- Roles
- Permissions
- Stateless authentication using OAuth2 (via Doorkeeper and Doorkeeper::JWT)
- Policy enforcement (via Pundit)
- Serialization to JSON API (via AMS)
- Two-factor auth
- External Login (TODO)
What doesn't it include?
- Stateful session support (Cookies)
- HTML/CSS/JS or views of any kind.
- Ruby >= 2.0
- PostgreSQL >= 9.3 (JSON and uuid-ossp support)
Note: For now, your app must use a PostgreSQL database. This is because ApiGuardian is using UUID primary keys for all records.
Put this in your Gemfile:
# Include ApiGuardian from edge
gem 'api_guardian', git: 'https://github.com/lookitsatravis/api_guardian'
# You must also include the prerelease version of active_model_serializers
gem 'active_model_serializers', git: 'https://github.com/rails-api/active_model_serializers.git'
Run this command:
rails generate api_guardian:install
This will add an initializer, mount the routes, and copy the migrations files. You will need to follow this with:
rake db:migrate
rake api_guardian:seed # not yet implemented, see db/seed.rb for example
To Do
To Do
To Do
To Do
To Do
Two-Factor Authentication (2FA) functionality is available out of the box. Requirements:
- Twilio account
To enable this feature, update the ApiGuardian config in config/initializers/api_guardian.rb
:
ApiGuardian.configure do |config|
# Enable two-factor authentication
config.enable_2fa = true
# 2FA header name. This header is used to validate a OTP and can be customized
# to have the app name, for example.
# config.otp_header_name = 'AG-2FA-TOKEN'
# 2FA Send From Number. This is the Twilio number we will send from.
config.twilio_send_from = 'YOUR_NUMBER' # formatted with country code, e.g. +18005551234
# Twilio Account SID and token (used with two-factor authentication). These can be found
# in your account.
config.twilio_id = 'YOUR_TWILIO_SID'
config.twilio_token = 'YOUR_TWILIO_AUTH_TOKEN'
end
Note: Restart your server when done for the changes to take effect.
To enable 2FA for a user, you will post their phone number, country code, and password to the API. You will need a valid access token. The user must supply their password in order to verify that it is the proper person to add a phone number to their record.
curl -X POST \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d \
'{
"data": {
"id": "USER_ID_HERE",
"type": "users",
"attributes": {
"phone_number": "8005551234",
"country_code": "1",
"password": "password"
}
}
}' \
'http://localhost:3000/api/v1/users/USER_ID_HERE/add_phone'
The user will receive an SMS message with a six digit code. You will need to send it to the API in order to verify the phone number. This must be completed within 60 seconds of sending the code.
curl -X POST \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d \
'{
"data": {
"id": "USER_ID_HERE",
"type": "users",
"attributes": {
"otp": "SIX_DIGIT_SMS_CODE",
}
}
}' \
'http://localhost:3000/api/v1/users/USER_ID_HERE/verify_phone'
The user will receive a confirmation SMS and the verification is now complete.
Authenticating with 2FA enabled is mostly the same as standard authentication using a password grant. Make the authentication request like normal:
curl -X POST \
-H "Content-Type: application/json" \
-d \
'{
"email": "[email protected]",
"password": "password",
"grant_type": "password"
}' \
'http://localhost:3000/api/v1/auth/token'
If the user has 2FA enabled, you will get a 402 response with a code of two_factor_required
. The server will send the OTP to the user via SMS, and the client should present the user with a form to submit the code. When this happens, you will resubmit the access token request with an additional header (AG-2FA-TOKEN
is the default value, though this is configurable) where the value is the OTP.
curl -X POST \
-H "Content-Type: application/json" \
-H "AG-2FA-TOKEN: SIX_DIGIT_SMS_CODE" \
-d \
'{
"email": "[email protected]",
"password": "password",
"grant_type": "password"
}' \
'http://localhost:3000/api/v1/auth/token'
If done properly, you should be rewarded with an access token. If the OTP is incorrect or has expired, you will simply get a 401 http status invalid_grant response and you must start again.
- controller actions:
- Assign permissions to role by name
- validate user password
- digits integration
- disallow inactive users
- Multi-tenancy
- Invite users by email to organization
- Users can belong to multiple organizations
- Different roles based on organization? Or permissions?
- Add pepper/salt to bcrypt
- omniauth
- Account lockout (failed login attempts)
- https://github.com/kickstarter/rack-attack
- JWT
- configure issuer
- configure secret key
- 2FA
- review support for https://www.authy.com/product/
- review support for U2F
- 2FA via voice call
- Generate URL for Google Authenticator import
- Backup codes for when device is unavailable
- 16 one time use codes
- Ability to regenerate a new batch of codes
- Activity/Events (User signed in, User authenticated at...)
- Sessions/Devices (attach to tokens)
- Fix for JWT storage: https://github.com/doorkeeper-gem/doorkeeper/wiki/How-to-fix-PostgreSQL-error-on-index-row-size
- Cache
- SSO
- Documentation
- Microservice usage
- Request logging
If you find a bug, please report an Issue.
If you have a question, please post to Stack Overflow.
Thanks!
See CONTRIBUTING.md
ApiGuardian is copyright © 2015 Travis Vignon. It is free software, and may be
redistributed under the terms specified in the MIT-LICENSE
file.