A Rails 8 API-only application with OAuth2 authentication using Doorkeeper and Devise, featuring role-based authorization with CanCanCan.
- Rails 8.0.2 - Latest Rails version configured as API-only
- Devise - User authentication
- Doorkeeper - OAuth2 provider
- CanCanCan - Role-based authorization
- MySQL - Database
- Password Grant Flow - Direct username/password authentication
- Refresh Tokens - Automatic token refresh support
- User Roles - Admin and User roles using enum
- RESTful API - Complete Users CRUD with authorization
- Ruby 3.x
- MySQL
- Rails 8.0.2
bundle installConfigure your database credentials in config/database.yml, then run:
rails db:create
rails db:migrate
rails db:seedThe seed file creates:
- Admin user:
admin@example.com/password123 - OAuth application for API access
rails serverA complete Postman collection is available at postman_collection.json with all API endpoints configured.
- Open Postman
- Click Import button
- Select
postman_collection.jsonfile - The collection includes:
- Environment variables (base_url, access_token, refresh_token)
- All authentication endpoints
- All user management endpoints
- Auto-save tokens after authentication
- Get Access Token: Run "Get Access Token" request first
- Tokens are automatically saved to collection variables
- Use API Endpoints: All subsequent requests use the saved token
- Refresh Token: Use "Refresh Token" when access token expires
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=admin@example.com&password=password123Response:
{
"access_token": "...",
"token_type": "Bearer",
"expires_in": 86400,
"refresh_token": "...",
"created_at": 1234567890
}POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&refresh_token=YOUR_REFRESH_TOKENInclude the access token in the Authorization header:
GET /api/your_endpoint
Authorization: Bearer YOUR_ACCESS_TOKENPOST /oauth/revoke
Content-Type: application/x-www-form-urlencoded
token=YOUR_ACCESS_TOKENAll user endpoints require authentication via Bearer token.
GET /api/v1/users/me
Authorization: Bearer YOUR_ACCESS_TOKENResponse:
{
"id": 1,
"email": "admin@example.com",
"name": "Admin User",
"role": "admin",
"created_at": "2025-11-23T10:52:54.000Z",
"updated_at": "2025-11-23T10:52:54.000Z"
}GET /api/v1/users
Authorization: Bearer YOUR_ACCESS_TOKENResponse:
[
{
"id": 1,
"email": "admin@example.com",
"name": "Admin User",
"role": "admin",
"created_at": "2025-11-23T10:52:54.000Z",
"updated_at": "2025-11-23T10:52:54.000Z"
}
]GET /api/v1/users/:id
Authorization: Bearer YOUR_ACCESS_TOKENPOST /api/v1/users
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
{
"user": {
"email": "newuser@example.com",
"name": "New User",
"password": "password123",
"password_confirmation": "password123",
"role": "user"
}
}Response:
{
"id": 2,
"email": "newuser@example.com",
"name": "New User",
"role": "user",
"created_at": "2025-11-23T11:00:00.000Z",
"updated_at": "2025-11-23T11:00:00.000Z"
}PATCH /api/v1/users/:id
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
{
"user": {
"name": "Updated Name"
}
}Note: Regular users can only update their own profile. Admins can update any user.
DELETE /api/v1/users/:id
Authorization: Bearer YOUR_ACCESS_TOKENResponse: 204 No Content
Located in config/initializers/doorkeeper.rb:
- Grant Flow: Password (Resource Owner Password Credentials)
- Token Expiration: 24 hours
- Refresh Tokens: Enabled
- Client Authentication: Skipped for password grant
- API Mode: Enabled
Users have the following attributes:
email- Unique identifier for authenticationname- User's display namerole- Enum with values:user(default),adminpassword- Encrypted with bcrypt via Devise
Role Methods:
user.admin? # Check if admin
user.user? # Check if regular user
user.admin! # Set role to admin
user.user! # Set role to userDefined in app/models/ability.rb:
Admin Users:
- Full access (manage) to all resources
- Can create, read, update, and delete any user
Regular Users:
- Can read all resources
- Can only update their own user profile
- Cannot create or delete users
Guest Users (not authenticated):
- No access (authentication required for all endpoints)
app/
├── controllers/
│ ├── application_controller.rb # Base controller with Doorkeeper & CanCanCan
│ └── api/
│ └── v1/
│ └── users_controller.rb # Users CRUD with authorization
├── models/
│ ├── ability.rb # CanCanCan authorization rules
│ └── user.rb # User model with Devise & roles
├── serializers/
│ └── user_serializer.rb # User JSON serialization
config/
├── initializers/
│ ├── devise.rb # Devise configuration
│ └── doorkeeper.rb # Doorkeeper OAuth2 configuration
├── routes.rb # API routes
└── database.yml # Database configuration
db/
├── migrate/
│ ├── *_devise_create_users.rb
│ ├── *_create_doorkeeper_tables.rb
│ └── *_add_name_and_role_to_users.rb
└── seeds.rb # Admin user & OAuth app seeds
- Password grant flow is enabled for simplicity but has security considerations
- Use HTTPS in production
- Access tokens expire after 24 hours
- Refresh tokens are available for seamless re-authentication
- Passwords are encrypted using bcrypt
- All API endpoints require authentication (Doorkeeper OAuth2 token)
- Authorization is enforced via CanCanCan based on user roles
- Unauthorized access returns
403 Forbiddenerror
User.create!(
email: "user@example.com",
name: "John Doe",
password: "password123",
password_confirmation: "password123",
role: :user
)Doorkeeper::Application.allDoorkeeper::AccessToken.allThe application includes comprehensive integration tests for all API endpoints.
# Run all tests
rails test
# Run specific test file
rails test test/integration/oauth_token_test.rb
rails test test/integration/api/v1/users_test.rb
# Run with verbose output
rails test -vOAuth Token Tests (test/integration/oauth_token_test.rb):
- Get access token with valid credentials
- Reject invalid credentials
- Refresh access token
- Revoke access token
Users API Tests (test/integration/api/v1/users_test.rb):
- Get current user (authenticated)
- List all users (admin & regular user)
- Get user by ID
- Create user (admin only, with authorization checks)
- Update user (own profile & admin permissions)
- Delete user (admin only)
- Authorization error handling
User fixtures are defined in test/fixtures/users.yml:
admin- Admin user (admin@test.com / password123)regular_user- Regular user (user@test.com / password123)
Helper methods in test/test_helper.rb:
create_access_token(user)- Create Doorkeeper access token for testingauth_headers(token)- Generate authorization headers with Bearer token
This project is available as open source under the terms of the MIT License.