Remove old docs
This commit is contained in:
@@ -1,275 +0,0 @@
|
|||||||
# Rodauth-OAuth Analysis Documents
|
|
||||||
|
|
||||||
This directory contains a comprehensive analysis of rodauth-oauth and how it compares to your custom OIDC implementation in Clinch.
|
|
||||||
|
|
||||||
## Start Here
|
|
||||||
|
|
||||||
### 1. **RODAUTH_DECISION_GUIDE.md** (15-minute read)
|
|
||||||
**Purpose:** Help you make a decision about your OAuth/OIDC implementation
|
|
||||||
|
|
||||||
**Contains:**
|
|
||||||
- TL;DR of three options
|
|
||||||
- Decision flowchart
|
|
||||||
- Feature roadmap scenarios
|
|
||||||
- Effort estimates for each path
|
|
||||||
- Security comparison
|
|
||||||
- Real-world questions to ask your team
|
|
||||||
- Next actions for each option
|
|
||||||
|
|
||||||
**Best for:** Deciding whether to keep your implementation, migrate, or use a hybrid approach
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2. **rodauth-oauth-quick-reference.md** (20-minute read)
|
|
||||||
**Purpose:** Quick lookup guide and architecture overview
|
|
||||||
|
|
||||||
**Contains:**
|
|
||||||
- What Rodauth-OAuth is (concise)
|
|
||||||
- Key statistics and certifications
|
|
||||||
- Feature advantages & disadvantages
|
|
||||||
- Architecture diagrams (text-based)
|
|
||||||
- Database schema comparison
|
|
||||||
- Feature matrix with implementation effort
|
|
||||||
- Performance considerations
|
|
||||||
- Getting started guide
|
|
||||||
- Code examples (minimal setup)
|
|
||||||
|
|
||||||
**Best for:** Understanding what you're looking at, quick decision support
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3. **rodauth-oauth-analysis.md** (45-minute deep-dive)
|
|
||||||
**Purpose:** Comprehensive technical analysis for decision-making
|
|
||||||
|
|
||||||
**Contains:**
|
|
||||||
- Complete architecture breakdown (12 sections)
|
|
||||||
- All 34 features detailed and explained
|
|
||||||
- Full database schema documentation
|
|
||||||
- Request flow diagrams
|
|
||||||
- Feature dependency graphs
|
|
||||||
- Integration paths with Rails
|
|
||||||
- Security analysis
|
|
||||||
- Migration procedures
|
|
||||||
- Code comparisons
|
|
||||||
- Performance metrics
|
|
||||||
|
|
||||||
**Best for:** Deep understanding before making technical decisions, planning migrations
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## How to Use These Documents
|
|
||||||
|
|
||||||
### Scenario 1: "I have 15 minutes"
|
|
||||||
1. Read: RODAUTH_DECISION_GUIDE.md (sections: TL;DR + Decision Matrix)
|
|
||||||
2. Go to: Next Actions for your chosen option
|
|
||||||
3. Done: You have a direction
|
|
||||||
|
|
||||||
### Scenario 2: "I have 45 minutes"
|
|
||||||
1. Read: RODAUTH_DECISION_GUIDE.md (complete)
|
|
||||||
2. Skim: rodauth-oauth-quick-reference.md (focus on code examples)
|
|
||||||
3. Decide: Which path interests you most
|
|
||||||
4. Plan: Team discussion using decision matrix
|
|
||||||
|
|
||||||
### Scenario 3: "I'm doing technical deep-dive"
|
|
||||||
1. Read: RODAUTH_DECISION_GUIDE.md (complete)
|
|
||||||
2. Read: rodauth-oauth-quick-reference.md (complete)
|
|
||||||
3. Read: rodauth-oauth-analysis.md (sections 1-6)
|
|
||||||
4. Reference: rodauth-oauth-analysis.md (sections 7-12 as needed)
|
|
||||||
|
|
||||||
### Scenario 4: "I'm planning a migration"
|
|
||||||
1. Read: RODAUTH_DECISION_GUIDE.md (effort estimates section)
|
|
||||||
2. Read: rodauth-oauth-analysis.md (migration path section)
|
|
||||||
3. Reference: rodauth-oauth-analysis.md (database schema section)
|
|
||||||
4. Plan: Detailed migration steps
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Three Options Explained (Very Brief)
|
|
||||||
|
|
||||||
### Option A: Keep Your Implementation
|
|
||||||
- **Time:** Ongoing (add features incrementally)
|
|
||||||
- **Effort:** 4-6 months to reach feature parity
|
|
||||||
- **Maintenance:** 8-10 hours/month
|
|
||||||
- **Best if:** Auth Code + PKCE is sufficient forever
|
|
||||||
|
|
||||||
### Option B: Switch to Rodauth-OAuth
|
|
||||||
- **Time:** 5-9 weeks (one-time migration)
|
|
||||||
- **Learning:** 1-2 weeks (Roda framework)
|
|
||||||
- **Maintenance:** 1-2 hours/month
|
|
||||||
- **Best if:** Need enterprise features, want low maintenance
|
|
||||||
|
|
||||||
### Option C: Hybrid Approach (Microservices)
|
|
||||||
- **Time:** 3-5 weeks (independent setup)
|
|
||||||
- **Learning:** Low (Roda is isolated)
|
|
||||||
- **Maintenance:** 2-3 hours/month
|
|
||||||
- **Best if:** Want Option B benefits without full Rails→Roda migration
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Key Findings
|
|
||||||
|
|
||||||
**What Rodauth-OAuth Provides That You Don't Have:**
|
|
||||||
- Refresh tokens
|
|
||||||
- Token revocation (RFC 7009)
|
|
||||||
- Token introspection (RFC 7662)
|
|
||||||
- Client Credentials grant (machine-to-machine)
|
|
||||||
- Device Code flow (IoT/smart TV)
|
|
||||||
- JWT Access Tokens (stateless)
|
|
||||||
- Session Management
|
|
||||||
- Front & Back-Channel Logout
|
|
||||||
- Token hashing (bcrypt security)
|
|
||||||
- DPoP support (token binding)
|
|
||||||
- TLS mutual authentication
|
|
||||||
- Dynamic Client Registration
|
|
||||||
- 20+ more optional features
|
|
||||||
|
|
||||||
**Security Differences:**
|
|
||||||
- Your impl: Tokens stored in plaintext (DB breach = token theft)
|
|
||||||
- Rodauth: Tokens hashed with bcrypt (secure even if DB breached)
|
|
||||||
|
|
||||||
**Maintenance Burden:**
|
|
||||||
- Your impl: YOU maintain everything
|
|
||||||
- Rodauth: Community maintains, you maintain config only
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Document Structure
|
|
||||||
|
|
||||||
### RODAUTH_DECISION_GUIDE.md Sections:
|
|
||||||
```
|
|
||||||
1. TL;DR - Three options
|
|
||||||
2. Decision Matrix - Flowchart
|
|
||||||
3. Feature Roadmap Comparison
|
|
||||||
4. Architecture Diagrams (visual)
|
|
||||||
5. Effort Estimates
|
|
||||||
6. Real-World Questions
|
|
||||||
7. Security Comparison
|
|
||||||
8. Cost-Benefit Summary
|
|
||||||
9. Decision Scorecard
|
|
||||||
10. Next Actions
|
|
||||||
```
|
|
||||||
|
|
||||||
### rodauth-oauth-quick-reference.md Sections:
|
|
||||||
```
|
|
||||||
1. What Is It? (overview)
|
|
||||||
2. Key Stats
|
|
||||||
3. Why Consider It? (advantages)
|
|
||||||
4. Architecture Overview (your impl vs rodauth)
|
|
||||||
5. Database Schema Comparison
|
|
||||||
6. Feature Comparison Matrix
|
|
||||||
7. Code Examples
|
|
||||||
8. Integration Paths
|
|
||||||
9. Getting Started
|
|
||||||
10. Next Steps
|
|
||||||
```
|
|
||||||
|
|
||||||
### rodauth-oauth-analysis.md Sections:
|
|
||||||
```
|
|
||||||
1. Executive Summary
|
|
||||||
2. What Rodauth-OAuth Is
|
|
||||||
3. File Structure & Organization
|
|
||||||
4. OIDC/OAuth Features
|
|
||||||
5. Architecture: How It Works
|
|
||||||
6. Database Schema Requirements
|
|
||||||
7. Integration with Rails
|
|
||||||
8. Architectural Comparison
|
|
||||||
9. Feature Matrix
|
|
||||||
10. Integration Complexity
|
|
||||||
11. Key Findings & Recommendations
|
|
||||||
12. Migration Path & Code Examples
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## For Your Team
|
|
||||||
|
|
||||||
### Sharing with Stakeholders
|
|
||||||
- **Non-technical:** Use RODAUTH_DECISION_GUIDE.md (TL;DR section)
|
|
||||||
- **Technical leads:** Use rodauth-oauth-quick-reference.md
|
|
||||||
- **Engineers:** Use rodauth-oauth-analysis.md (sections 1-6)
|
|
||||||
- **Security team:** Use rodauth-oauth-analysis.md (security sections)
|
|
||||||
|
|
||||||
### Team Discussion
|
|
||||||
Print out the decision matrix from RODAUTH_DECISION_GUIDE.md and:
|
|
||||||
1. Walk through each option
|
|
||||||
2. Discuss team comfort with framework learning
|
|
||||||
3. Check against feature roadmap
|
|
||||||
4. Decide on maintenance philosophy
|
|
||||||
5. Vote on preferred option
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Next Steps After Reading
|
|
||||||
|
|
||||||
### If Choosing Option A (Keep Custom):
|
|
||||||
- [ ] Plan feature roadmap (refresh tokens first)
|
|
||||||
- [ ] Allocate team capacity
|
|
||||||
- [ ] Add token hashing security
|
|
||||||
- [ ] Set up security monitoring
|
|
||||||
|
|
||||||
### If Choosing Option B (Full Migration):
|
|
||||||
- [ ] Assign team member to learn Roda/Rodauth
|
|
||||||
- [ ] Run examples from `/tmp/rodauth-oauth/examples`
|
|
||||||
- [ ] Plan database migration
|
|
||||||
- [ ] Prepare rollback plan
|
|
||||||
- [ ] Schedule migration window
|
|
||||||
|
|
||||||
### If Choosing Option C (Hybrid):
|
|
||||||
- [ ] Evaluate microservices capability
|
|
||||||
- [ ] Review service communication plan
|
|
||||||
- [ ] Set up service infrastructure
|
|
||||||
- [ ] Plan gradual deployment
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Bonus: Running the Example
|
|
||||||
|
|
||||||
Rodauth-OAuth includes a working OIDC server example you can run:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd /Users/dkam/Development/clinch/tmp/rodauth-oauth/examples/oidc
|
|
||||||
ruby authentication_server.rb
|
|
||||||
|
|
||||||
# Then visit: http://localhost:9292
|
|
||||||
# Login with: foo@bar.com / password
|
|
||||||
# See: Full OIDC provider in action
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Questions?
|
|
||||||
|
|
||||||
These documents should answer:
|
|
||||||
- What is rodauth-oauth?
|
|
||||||
- How does it compare to my implementation?
|
|
||||||
- What features would we gain?
|
|
||||||
- What would we lose?
|
|
||||||
- How much effort is a migration?
|
|
||||||
- Should we switch?
|
|
||||||
|
|
||||||
If questions remain, reference the specific section in the analysis documents.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Document Generation Info
|
|
||||||
|
|
||||||
**Generated:** November 12, 2025
|
|
||||||
**Analysis Duration:** Complete codebase exploration of rodauth-oauth gem
|
|
||||||
**Sources Analyzed:**
|
|
||||||
- 34 feature files (10,000+ lines of code)
|
|
||||||
- 7 database migrations
|
|
||||||
- 6 complete example applications
|
|
||||||
- Comprehensive test suite
|
|
||||||
- README and migration guides
|
|
||||||
|
|
||||||
**Analysis Includes:**
|
|
||||||
- Line-by-line code structure review
|
|
||||||
- Database schema comparison
|
|
||||||
- Feature cross-reference analysis
|
|
||||||
- Integration complexity assessment
|
|
||||||
- Security analysis
|
|
||||||
- Effort estimation models
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Start with RODAUTH_DECISION_GUIDE.md and go from there!**
|
|
||||||
@@ -1,426 +0,0 @@
|
|||||||
# Rodauth-OAuth Decision Guide
|
|
||||||
|
|
||||||
## TL;DR - Make Your Choice Here
|
|
||||||
|
|
||||||
### Option A: Keep Your Rails Implementation
|
|
||||||
**Best if:** Authorization Code + PKCE is all you need, forever
|
|
||||||
- Keep your current 450 lines of OIDC controller code
|
|
||||||
- Maintain incrementally as needs change
|
|
||||||
- Stay 100% in Rails ecosystem
|
|
||||||
- Time investment: Ongoing (2-3 months to feature parity)
|
|
||||||
- Learning curve: None (already know Rails)
|
|
||||||
|
|
||||||
### Option B: Switch to Rodauth-OAuth
|
|
||||||
**Best if:** You need enterprise features, standards compliance, low maintenance
|
|
||||||
- Replace 450 lines with plugin config
|
|
||||||
- Get 34 optional features on demand
|
|
||||||
- OpenID Certified, production-hardened
|
|
||||||
- Time investment: 4-8 weeks (one-time)
|
|
||||||
- Learning curve: Medium (learn Roda/Rodauth)
|
|
||||||
|
|
||||||
### Option C: Hybrid (Recommended if Option B appeals you)
|
|
||||||
**Best if:** You want rodauth-oauth benefits without framework change
|
|
||||||
- Run Rodauth-OAuth as separate microservice
|
|
||||||
- Keep your Rails app unchanged
|
|
||||||
- Services talk via HTTP APIs
|
|
||||||
- Time investment: 2-3 weeks (independent services)
|
|
||||||
- Learning curve: Low (Roda is isolated)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Decision Matrix
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────────────────────────┐
|
|
||||||
│ Do you need features beyond Authorization Code + PKCE? │
|
|
||||||
├─────────────────────────────────────────────────────────────────┤
|
|
||||||
│ YES ─→ Go to Question 2 │
|
|
||||||
│ NO ─→ KEEP YOUR IMPLEMENTATION │
|
|
||||||
└─────────────────────────────────────────────────────────────────┘
|
|
||||||
↓
|
|
||||||
┌─────────────────────────────────────────────────────────────────┐
|
|
||||||
│ Can your team learn Roda (different from Rails)? │
|
|
||||||
├─────────────────────────────────────────────────────────────────┤
|
|
||||||
│ YES ─→ SWITCH TO RODAUTH-OAUTH │
|
|
||||||
│ NO ─→ Go to Question 3 │
|
|
||||||
└─────────────────────────────────────────────────────────────────┘
|
|
||||||
↓
|
|
||||||
┌─────────────────────────────────────────────────────────────────┐
|
|
||||||
│ Can you run separate services (microservices)? │
|
|
||||||
├─────────────────────────────────────────────────────────────────┤
|
|
||||||
│ YES ─→ USE HYBRID APPROACH │
|
|
||||||
│ NO ─→ KEEP YOUR IMPLEMENTATION │
|
|
||||||
└─────────────────────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Feature Roadmap Comparison
|
|
||||||
|
|
||||||
### Scenario 1: You Need Refresh Tokens (Common)
|
|
||||||
|
|
||||||
**Option A (Keep Custom):**
|
|
||||||
- Implement refresh token endpoints
|
|
||||||
- Add refresh_token columns to DB
|
|
||||||
- Token rotation logic
|
|
||||||
- Estimate: 1-2 weeks of work
|
|
||||||
- Ongoing: Maintain refresh token security
|
|
||||||
|
|
||||||
**Option B (Rodauth-OAuth):**
|
|
||||||
- Already built and tested
|
|
||||||
- Just enable: `:oauth_authorization_code_grant` (includes refresh)
|
|
||||||
- Token rotation: Configurable options
|
|
||||||
- Estimate: Already included
|
|
||||||
- Ongoing: Community maintains
|
|
||||||
|
|
||||||
**Option C (Hybrid):**
|
|
||||||
- Rodauth-OAuth handles it
|
|
||||||
- Your app unchanged
|
|
||||||
- Same as Option B for this feature
|
|
||||||
|
|
||||||
### Scenario 2: You Need Token Revocation
|
|
||||||
|
|
||||||
**Option A (Keep Custom):**
|
|
||||||
- Build `/oauth/revoke` endpoint
|
|
||||||
- Implement token blacklist or DB update
|
|
||||||
- Handle race conditions
|
|
||||||
- Estimate: 1-2 weeks
|
|
||||||
- Ongoing: Monitor revocation leaks
|
|
||||||
|
|
||||||
**Option B (Rodauth-OAuth):**
|
|
||||||
- Enable `:oauth_token_revocation` feature
|
|
||||||
- RFC 7009 compliant out of the box
|
|
||||||
- Estimate: Already included
|
|
||||||
- Ongoing: Community handles RFC updates
|
|
||||||
|
|
||||||
**Option C (Hybrid):**
|
|
||||||
- Same as Option B
|
|
||||||
|
|
||||||
### Scenario 3: You Need Client Credentials Grant
|
|
||||||
|
|
||||||
**Option A (Keep Custom):**
|
|
||||||
- New endpoint logic
|
|
||||||
- Client authentication (different from user auth)
|
|
||||||
- Token generation for apps without users
|
|
||||||
- Estimate: 2-3 weeks
|
|
||||||
- Ongoing: Test with external clients
|
|
||||||
|
|
||||||
**Option B (Rodauth-OAuth):**
|
|
||||||
- Enable `:oauth_client_credentials_grant` feature
|
|
||||||
- All edge cases handled
|
|
||||||
- Estimate: Already included
|
|
||||||
- Ongoing: Community maintains
|
|
||||||
|
|
||||||
**Option C (Hybrid):**
|
|
||||||
- Same as Option B
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Architecture Diagrams
|
|
||||||
|
|
||||||
### Current Setup (Your Implementation)
|
|
||||||
```
|
|
||||||
┌─────────────────────────────┐
|
|
||||||
│ Your Rails Application │
|
|
||||||
├─────────────────────────────┤
|
|
||||||
│ app/controllers/ │
|
|
||||||
│ oidc_controller.rb │ ← 450 lines of OAuth logic
|
|
||||||
│ │
|
|
||||||
│ app/models/ │
|
|
||||||
│ OidcAuthorizationCode │
|
|
||||||
│ OidcAccessToken │
|
|
||||||
│ OidcUserConsent │
|
|
||||||
│ │
|
|
||||||
│ app/services/ │
|
|
||||||
│ OidcJwtService │
|
|
||||||
├─────────────────────────────┤
|
|
||||||
│ Rails ActiveRecord │
|
|
||||||
├─────────────────────────────┤
|
|
||||||
│ PostgreSQL Database │
|
|
||||||
│ - oidc_authorization_codes
|
|
||||||
│ - oidc_access_tokens
|
|
||||||
│ - oidc_user_consents
|
|
||||||
│ - applications
|
|
||||||
└─────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
### Option B: Full Migration
|
|
||||||
```
|
|
||||||
┌──────────────────────────────┐
|
|
||||||
│ Roda + Rodauth-OAuth App │
|
|
||||||
├──────────────────────────────┤
|
|
||||||
│ lib/rodauth_app.rb │ ← Config (not code!)
|
|
||||||
│ enable :oidc, │
|
|
||||||
│ enable :oauth_pkce, │
|
|
||||||
│ enable :oauth_token_... │
|
|
||||||
│ │
|
|
||||||
│ [Routes auto-mounted] │
|
|
||||||
│ /.well-known/config │
|
|
||||||
│ /oauth/authorize │
|
|
||||||
│ /oauth/token │
|
|
||||||
│ /oauth/userinfo │
|
|
||||||
│ /oauth/revoke │
|
|
||||||
│ /oauth/introspect │
|
|
||||||
├──────────────────────────────┤
|
|
||||||
│ Sequel ORM │
|
|
||||||
├──────────────────────────────┤
|
|
||||||
│ PostgreSQL Database │
|
|
||||||
│ - accounts (rodauth)
|
|
||||||
│ - oauth_applications
|
|
||||||
│ - oauth_grants (unified!)
|
|
||||||
│ - optional feature tables
|
|
||||||
└──────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
### Option C: Microservices Architecture (Hybrid)
|
|
||||||
```
|
|
||||||
┌──────────────────────────┐ ┌──────────────────────────┐
|
|
||||||
│ Your Rails App │ │ Rodauth-OAuth Service │
|
|
||||||
├──────────────────────────┤ ├──────────────────────────┤
|
|
||||||
│ Normal Rails Controllers │ │ lib/rodauth_app.rb │
|
|
||||||
│ & Business Logic │ │ [OAuth Features] │
|
|
||||||
│ │ │ │
|
|
||||||
│ HTTP Calls to →──────────┼─────→ /.well-known/config │
|
|
||||||
│ OAuth Service OAuth │ │ /oauth/authorize │
|
|
||||||
│ HTTP API │ │ /oauth/token │
|
|
||||||
│ │ │ /oauth/userinfo │
|
|
||||||
│ Verify Tokens via →──────┼─────→ /oauth/introspect │
|
|
||||||
│ /oauth/introspect │ │ │
|
|
||||||
├──────────────────────────┤ ├──────────────────────────┤
|
|
||||||
│ Rails ActiveRecord │ │ Sequel ORM │
|
|
||||||
├──────────────────────────┤ ├──────────────────────────┤
|
|
||||||
│ PostgreSQL │ │ PostgreSQL │
|
|
||||||
│ [business tables] │ │ [oauth tables] │
|
|
||||||
└──────────────────────────┘ └──────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Effort Estimates
|
|
||||||
|
|
||||||
### Option A: Keep & Enhance Custom Implementation
|
|
||||||
```
|
|
||||||
Refresh Tokens: 1-2 weeks
|
|
||||||
Token Revocation: 1-2 weeks
|
|
||||||
Token Introspection: 1-2 weeks
|
|
||||||
Client Credentials: 2-3 weeks
|
|
||||||
Device Code: 3-4 weeks
|
|
||||||
JWT Access Tokens: 1-2 weeks
|
|
||||||
Session Management: 2-3 weeks
|
|
||||||
Front-Channel Logout: 1-2 weeks
|
|
||||||
Back-Channel Logout: 2-3 weeks
|
|
||||||
─────────────────────────────────
|
|
||||||
TOTAL FOR PARITY: 15-25 weeks
|
|
||||||
(4-6 months of work)
|
|
||||||
|
|
||||||
ONGOING MAINTENANCE: ~8-10 hours/month
|
|
||||||
(security updates, RFC changes, bug fixes)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Option B: Migrate to Rodauth-OAuth
|
|
||||||
```
|
|
||||||
Learn Roda/Rodauth: 1-2 weeks
|
|
||||||
Migrate Database Schema: 1-2 weeks
|
|
||||||
Replace OIDC Code: 1-2 weeks
|
|
||||||
Test & Validation: 2-3 weeks
|
|
||||||
─────────────────────────────────
|
|
||||||
ONE-TIME EFFORT: 5-9 weeks
|
|
||||||
(1-2 months)
|
|
||||||
|
|
||||||
ONGOING MAINTENANCE: ~1-2 hours/month
|
|
||||||
(dependency updates, config tweaks)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Option C: Hybrid Approach
|
|
||||||
```
|
|
||||||
Set up Rodauth service: 1-2 weeks
|
|
||||||
Configure integration: 1-2 weeks
|
|
||||||
Test both services: 1 week
|
|
||||||
─────────────────────────────────
|
|
||||||
ONE-TIME EFFORT: 3-5 weeks
|
|
||||||
(less than Option B)
|
|
||||||
|
|
||||||
ONGOING MAINTENANCE: ~2-3 hours/month
|
|
||||||
(maintain two services, but Roda handles OAuth)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Real-World Questions to Ask Your Team
|
|
||||||
|
|
||||||
### Question 1: Feature Needs
|
|
||||||
- "Do we need refresh tokens?"
|
|
||||||
- "Will clients ask for token revocation?"
|
|
||||||
- "Do we support service-to-service auth (client credentials)?"
|
|
||||||
- "Will we ever need device code flow (IoT)?"
|
|
||||||
|
|
||||||
If YES to any: **Option B or C makes sense**
|
|
||||||
|
|
||||||
### Question 2: Maintenance Philosophy
|
|
||||||
- "Do we want to own the OAuth code?"
|
|
||||||
- "Can we afford to maintain OAuth compliance?"
|
|
||||||
- "Do we have experts in OAuth/OIDC?"
|
|
||||||
|
|
||||||
If NO to all: **Option B or C is better**
|
|
||||||
|
|
||||||
### Question 3: Framework Flexibility
|
|
||||||
- "Is Rails non-negotiable for this company?"
|
|
||||||
- "Can our team learn a new framework?"
|
|
||||||
- "Can we run microservices?"
|
|
||||||
|
|
||||||
If Rails is required: **Option C (hybrid)**
|
|
||||||
|
|
||||||
### Question 4: Time Constraints
|
|
||||||
- "Do we have 4-8 weeks for a migration?"
|
|
||||||
- "Can we maintain OAuth for years?"
|
|
||||||
- "What if specs change?"
|
|
||||||
|
|
||||||
If time-constrained: **Option B is fastest path to full features**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Security Comparison
|
|
||||||
|
|
||||||
### Your Implementation
|
|
||||||
- ✓ PKCE support
|
|
||||||
- ✓ JWT signing
|
|
||||||
- ✓ HTTPS recommended
|
|
||||||
- ✗ Token hashing (stores tokens in plaintext)
|
|
||||||
- ✗ Token rotation
|
|
||||||
- ✗ DPoP (token binding)
|
|
||||||
- ✗ Automatic spec compliance
|
|
||||||
- Risk: Token theft if DB compromised
|
|
||||||
|
|
||||||
### Rodauth-OAuth
|
|
||||||
- ✓ PKCE support
|
|
||||||
- ✓ JWT signing
|
|
||||||
- ✓ Token hashing (bcrypt by default)
|
|
||||||
- ✓ Token rotation policies
|
|
||||||
- ✓ DPoP support (RFC 9449)
|
|
||||||
- ✓ TLS mutual authentication
|
|
||||||
- ✓ Automatic spec updates
|
|
||||||
- ✓ Certified compliance
|
|
||||||
- Risk: Minimal (industry-standard)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Cost-Benefit Summary
|
|
||||||
|
|
||||||
### Keep Your Implementation
|
|
||||||
```
|
|
||||||
Costs:
|
|
||||||
- 15-25 weeks to feature parity
|
|
||||||
- Ongoing security monitoring
|
|
||||||
- Spec compliance tracking
|
|
||||||
- Bug fixes & edge cases
|
|
||||||
|
|
||||||
Benefits:
|
|
||||||
- No framework learning
|
|
||||||
- Full code understanding
|
|
||||||
- Rails-native patterns
|
|
||||||
- Minimal dependencies
|
|
||||||
```
|
|
||||||
|
|
||||||
### Switch to Rodauth-OAuth
|
|
||||||
```
|
|
||||||
Costs:
|
|
||||||
- 5-9 weeks migration effort
|
|
||||||
- Learn Roda/Rodauth
|
|
||||||
- Database schema changes
|
|
||||||
- Test all flows
|
|
||||||
|
|
||||||
Benefits:
|
|
||||||
- Get 34 features immediately
|
|
||||||
- Certified compliance
|
|
||||||
- Community-maintained
|
|
||||||
- Security best practices
|
|
||||||
- Ongoing support
|
|
||||||
```
|
|
||||||
|
|
||||||
### Hybrid Approach
|
|
||||||
```
|
|
||||||
Costs:
|
|
||||||
- 3-5 weeks setup
|
|
||||||
- Learn Roda basics
|
|
||||||
- Operate two services
|
|
||||||
- Service communication
|
|
||||||
|
|
||||||
Benefits:
|
|
||||||
- All Rodauth-OAuth features
|
|
||||||
- Rails app unchanged
|
|
||||||
- Independent scaling
|
|
||||||
- Clear separation of concerns
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Decision Scorecard
|
|
||||||
|
|
||||||
| Factor | Option A | Option B | Option C |
|
|
||||||
|--------|----------|----------|----------|
|
|
||||||
| Initial Time | Low | Medium | Medium-Low |
|
|
||||||
| Ongoing Effort | High | Low | Medium |
|
|
||||||
| Feature Completeness | Low | High | High |
|
|
||||||
| Framework Learning | None | Medium | Low |
|
|
||||||
| Standards Compliance | Manual | Auto | Auto |
|
|
||||||
| Deployment Complexity | Simple | Simple | Complex |
|
|
||||||
| Team Preference | ??? | ??? | ??? |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Next Actions
|
|
||||||
|
|
||||||
### For Option A (Keep Custom):
|
|
||||||
1. Plan feature roadmap (refresh tokens first)
|
|
||||||
2. Allocate team capacity for implementation
|
|
||||||
3. Document OAuth decisions
|
|
||||||
4. Set up security monitoring
|
|
||||||
|
|
||||||
### For Option B (Full Migration):
|
|
||||||
1. Assign someone to learn Roda/Rodauth
|
|
||||||
2. Run rodauth-oauth examples
|
|
||||||
3. Plan database migration
|
|
||||||
4. Schedule migration window
|
|
||||||
5. Prepare rollback plan
|
|
||||||
|
|
||||||
### For Option C (Hybrid):
|
|
||||||
1. Evaluate microservices capability
|
|
||||||
2. Run Rodauth-OAuth example
|
|
||||||
3. Plan service boundaries
|
|
||||||
4. Set up service communication
|
|
||||||
5. Plan infrastructure for two services
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Still Can't Decide?
|
|
||||||
|
|
||||||
Ask these questions:
|
|
||||||
1. **Will you add features beyond Auth Code + PKCE in next 12 months?**
|
|
||||||
- YES → Option B or C
|
|
||||||
- NO → Option A
|
|
||||||
|
|
||||||
2. **Do you have maintenance bandwidth?**
|
|
||||||
- YES → Option A
|
|
||||||
- NO → Option B or C
|
|
||||||
|
|
||||||
3. **Can you run multiple services?**
|
|
||||||
- YES → Option C (best of both)
|
|
||||||
- NO → Option B (if framework is OK) or Option A (stay Rails)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Document Files
|
|
||||||
|
|
||||||
You now have three documents:
|
|
||||||
1. **rodauth-oauth-analysis.md** - Deep technical analysis (12 sections)
|
|
||||||
2. **rodauth-oauth-quick-reference.md** - Quick lookup guide
|
|
||||||
3. **RODAUTH_DECISION_GUIDE.md** - This decision framework
|
|
||||||
|
|
||||||
Read in this order:
|
|
||||||
1. This guide (make a decision)
|
|
||||||
2. Quick reference (understand architecture)
|
|
||||||
3. Analysis (deep dive on your choice)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Made Your Decision?** Create an issue/commit to document your choice and next steps!
|
|
||||||
@@ -1,913 +0,0 @@
|
|||||||
# Rodauth-OAuth Analysis: Comprehensive Comparison with Clinch's Custom Implementation
|
|
||||||
|
|
||||||
## Executive Summary
|
|
||||||
|
|
||||||
**Rodauth-OAuth** is a production-ready Ruby gem that implements the OAuth 2.0 framework and OpenID Connect on top of the `rodauth` authentication library. It's architected as a modular feature-based system that integrates with Roda (a routing library) and provides extensive OAuth/OIDC capabilities.
|
|
||||||
|
|
||||||
Your current Clinch implementation is a **custom, minimalist Rails-based OIDC provider** focusing on the authorization code grant with PKCE support. Switching to rodauth-oauth would provide significantly more features and standards compliance but requires architectural changes.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1. What Rodauth-OAuth Is
|
|
||||||
|
|
||||||
### Core Identity
|
|
||||||
- **Type**: Ruby gem providing OAuth 2.0 & OpenID Connect implementation
|
|
||||||
- **Framework**: Built on top of `rodauth` (a dedicated authentication library)
|
|
||||||
- **Web Framework**: Designed for Roda framework (lightweight, routing-focused)
|
|
||||||
- **Rails Support**: Available via `rodauth-rails` wrapper
|
|
||||||
- **Maturity**: Production-ready, OpenID-Certified for multiple profiles
|
|
||||||
- **Author**: Tiago Cardoso (tiago.cardoso@gmail.com)
|
|
||||||
- **License**: Apache 2.0
|
|
||||||
|
|
||||||
### Architecture Philosophy
|
|
||||||
- **Feature-based**: Modular "features" that can be enabled/disabled
|
|
||||||
- **Database-agnostic**: Uses Sequel ORM, works with any SQL database
|
|
||||||
- **Highly configurable**: Override methods to customize behavior
|
|
||||||
- **Standards-focused**: Implements RFCs and OpenID specs strictly
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. File Structure and Organization
|
|
||||||
|
|
||||||
### Directory Layout in `/tmp/rodauth-oauth`
|
|
||||||
|
|
||||||
```
|
|
||||||
rodauth-oauth/
|
|
||||||
├── lib/
|
|
||||||
│ └── rodauth/
|
|
||||||
│ ├── oauth.rb # Main module entry point
|
|
||||||
│ ├── oauth/
|
|
||||||
│ │ ├── version.rb
|
|
||||||
│ │ ├── database_extensions.rb
|
|
||||||
│ │ ├── http_extensions.rb
|
|
||||||
│ │ ├── jwe_extensions.rb
|
|
||||||
│ │ └── ttl_store.rb
|
|
||||||
│ └── features/ # 34 feature files!
|
|
||||||
│ ├── oauth_base.rb # Foundation
|
|
||||||
│ ├── oauth_authorization_code_grant.rb
|
|
||||||
│ ├── oauth_pkce.rb
|
|
||||||
│ ├── oauth_jwt*.rb # JWT support (5 files)
|
|
||||||
│ ├── oidc.rb # OpenID Core
|
|
||||||
│ ├── oidc_*logout.rb # Logout flows (3 files)
|
|
||||||
│ ├── oauth_client_credentials_grant.rb
|
|
||||||
│ ├── oauth_device_code_grant.rb
|
|
||||||
│ ├── oauth_token_revocation.rb
|
|
||||||
│ ├── oauth_token_introspection.rb
|
|
||||||
│ ├── oauth_dynamic_client_registration.rb
|
|
||||||
│ ├── oauth_dpop.rb # DPoP support
|
|
||||||
│ ├── oauth_tls_client_auth.rb
|
|
||||||
│ ├── oauth_pushed_authorization_request.rb
|
|
||||||
│ ├── oauth_assertion_base.rb
|
|
||||||
│ └── ... (more features)
|
|
||||||
├── test/
|
|
||||||
│ ├── migrate/ # Database migrations
|
|
||||||
│ │ ├── 001_accounts.rb
|
|
||||||
│ │ ├── 003_oauth_applications.rb
|
|
||||||
│ │ ├── 004_oauth_grants.rb
|
|
||||||
│ │ ├── 005_pushed_requests.rb
|
|
||||||
│ │ ├── 006_saml_settings.rb
|
|
||||||
│ │ └── 007_dpop_proofs.rb
|
|
||||||
│ └── [multiple test directories with hundreds of tests]
|
|
||||||
├── examples/ # Full working examples
|
|
||||||
│ ├── authorization_server/
|
|
||||||
│ ├── oidc/
|
|
||||||
│ ├── jwt/
|
|
||||||
│ ├── device_grant/
|
|
||||||
│ ├── saml_assertion/
|
|
||||||
│ └── mtls/
|
|
||||||
├── templates/ # HTML/ERB templates
|
|
||||||
├── locales/ # i18n translations
|
|
||||||
├── doc/
|
|
||||||
└── [Gemfile, README, MIGRATION-GUIDE, etc.]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Feature Count: 34 Features!
|
|
||||||
|
|
||||||
The gem is completely modular. Each feature can be independently enabled:
|
|
||||||
|
|
||||||
**Core OAuth Features:**
|
|
||||||
- `oauth_base` - Foundation
|
|
||||||
- `oauth_authorization_code_grant` - Authorization Code Flow
|
|
||||||
- `oauth_implicit_grant` - Implicit Flow
|
|
||||||
- `oauth_client_credentials_grant` - Client Credentials Flow
|
|
||||||
- `oauth_device_code_grant` - Device Code Flow
|
|
||||||
|
|
||||||
**Token Management:**
|
|
||||||
- `oauth_token_revocation` - RFC 7009
|
|
||||||
- `oauth_token_introspection` - RFC 7662
|
|
||||||
- `oauth_refresh_token` - Refresh tokens
|
|
||||||
|
|
||||||
**Security & Advanced:**
|
|
||||||
- `oauth_pkce` - RFC 7636 (what Clinch is using!)
|
|
||||||
- `oauth_jwt` - JWT Access Tokens
|
|
||||||
- `oauth_jwt_bearer_grant` - RFC 7523
|
|
||||||
- `oauth_saml_bearer_grant` - RFC 7522
|
|
||||||
- `oauth_tls_client_auth` - Mutual TLS
|
|
||||||
- `oauth_dpop` - Demonstrating Proof-of-Possession
|
|
||||||
- `oauth_jwt_secured_authorization_request` - Request Objects
|
|
||||||
- `oauth_resource_indicators` - RFC 8707
|
|
||||||
- `oauth_pushed_authorization_request` - RFC 9126
|
|
||||||
|
|
||||||
**OpenID Connect:**
|
|
||||||
- `oidc` - Core OpenID Connect
|
|
||||||
- `oidc_session_management` - Session Management
|
|
||||||
- `oidc_rp_initiated_logout` - RP-Initiated Logout
|
|
||||||
- `oidc_frontchannel_logout` - Front-Channel Logout
|
|
||||||
- `oidc_backchannel_logout` - Back-Channel Logout
|
|
||||||
- `oidc_dynamic_client_registration` - Dynamic Registration
|
|
||||||
- `oidc_self_issued` - Self-Issued Provider
|
|
||||||
|
|
||||||
**Management & Discovery:**
|
|
||||||
- `oauth_application_management` - Client app dashboard
|
|
||||||
- `oauth_grant_management` - Grant management dashboard
|
|
||||||
- `oauth_dynamic_client_registration` - RFC 7591/7592
|
|
||||||
- `oauth_jwt_jwks` - JWKS endpoint
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. OIDC/OAuth Features Provided
|
|
||||||
|
|
||||||
### Grant Types Supported (15 types!)
|
|
||||||
|
|
||||||
| Grant Type | Status | RFC/Spec |
|
|
||||||
|-----------|--------|----------|
|
|
||||||
| Authorization Code | Yes | RFC 6749 |
|
|
||||||
| Implicit | Optional | RFC 6749 |
|
|
||||||
| Client Credentials | Optional | RFC 6749 |
|
|
||||||
| Device Code | Optional | RFC 8628 |
|
|
||||||
| Refresh Token | Yes | RFC 6749 |
|
|
||||||
| JWT Bearer | Optional | RFC 7523 |
|
|
||||||
| SAML Bearer | Optional | RFC 7522 |
|
|
||||||
|
|
||||||
### Response Types & Modes
|
|
||||||
|
|
||||||
**Response Types:**
|
|
||||||
- `code` (Authorization Code) - Default
|
|
||||||
- `id_token` (OIDC Implicit) - Optional
|
|
||||||
- `token` (Implicit) - Optional
|
|
||||||
- `id_token token` (Hybrid) - Optional
|
|
||||||
- `code id_token` (Hybrid) - Optional
|
|
||||||
- `code token` (Hybrid) - Optional
|
|
||||||
- `code id_token token` (Hybrid) - Optional
|
|
||||||
|
|
||||||
**Response Modes:**
|
|
||||||
- `query` (URL parameters)
|
|
||||||
- `fragment` (URL fragment)
|
|
||||||
- `form_post` (HTML form)
|
|
||||||
- `jwt` (JWT-based response)
|
|
||||||
|
|
||||||
### OpenID Connect Features
|
|
||||||
|
|
||||||
✓ **Certified for:**
|
|
||||||
- Basic OP (OpenID Provider)
|
|
||||||
- Implicit OP
|
|
||||||
- Hybrid OP
|
|
||||||
- Config OP (Discovery)
|
|
||||||
- Dynamic OP (Dynamic Client Registration)
|
|
||||||
- Form Post OP
|
|
||||||
- 3rd Party-Init OP
|
|
||||||
- Session Management OP
|
|
||||||
- RP-Initiated Logout OP
|
|
||||||
- Front-Channel Logout OP
|
|
||||||
- Back-Channel Logout OP
|
|
||||||
|
|
||||||
✓ **Standard Claims Support:**
|
|
||||||
- `openid`, `email`, `profile`, `address`, `phone` scopes
|
|
||||||
- Automatic claim mapping per OpenID spec
|
|
||||||
- Custom claims via extension
|
|
||||||
|
|
||||||
✓ **Token Features:**
|
|
||||||
- JWT ID Tokens
|
|
||||||
- JWT Access Tokens
|
|
||||||
- Encrypted JWTs (JWE support)
|
|
||||||
- HMAC-SHA256 signing
|
|
||||||
- RSA/EC signing
|
|
||||||
- Custom token formats
|
|
||||||
|
|
||||||
### Security Features
|
|
||||||
|
|
||||||
| Feature | Details |
|
|
||||||
|---------|---------|
|
|
||||||
| PKCE | RFC 7636 - Proof Key for Public Clients |
|
|
||||||
| Token Hashing | Bcrypt-based token storage (plain text optional) |
|
|
||||||
| DPoP | RFC 9449 - Demonstrating Proof-of-Possession |
|
|
||||||
| TLS Client Auth | RFC 8705 - Mutual TLS authentication |
|
|
||||||
| Request Objects | JWT-signed/encrypted authorization requests |
|
|
||||||
| Pushed Auth Requests | RFC 9126 - Pushed Authorization Requests |
|
|
||||||
| Token Introspection | RFC 7662 - Token validation without DB lookup |
|
|
||||||
| Token Revocation | RFC 7009 - Revoke tokens on demand |
|
|
||||||
|
|
||||||
### Scopes & Authorization
|
|
||||||
|
|
||||||
- Configurable scope list per application
|
|
||||||
- Offline access support (refresh tokens)
|
|
||||||
- Scope-based access control
|
|
||||||
- Custom scope handlers
|
|
||||||
- Consent UI for user authorization
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4. Architecture: How It Works
|
|
||||||
|
|
||||||
### As a Plugin System
|
|
||||||
|
|
||||||
Rodauth-OAuth integrates with Roda as a **plugin**:
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
# This is how you configure it
|
|
||||||
class AuthServer < Roda
|
|
||||||
plugin :rodauth do
|
|
||||||
db database_connection
|
|
||||||
|
|
||||||
# Enable features
|
|
||||||
enable :login, :logout, :create_account, :oidc, :oidc_session_management,
|
|
||||||
:oauth_pkce, :oauth_authorization_code_grant
|
|
||||||
|
|
||||||
# Configure
|
|
||||||
oauth_application_scopes %w[openid email profile]
|
|
||||||
oauth_require_pkce true
|
|
||||||
hmac_secret "SECRET"
|
|
||||||
|
|
||||||
# Customize with blocks
|
|
||||||
oauth_jwt_keys("RS256" => [private_key])
|
|
||||||
oauth_jwt_public_keys("RS256" => [public_key])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
### Request Flow Architecture
|
|
||||||
|
|
||||||
```
|
|
||||||
1. Authorization Request
|
|
||||||
↓
|
|
||||||
rodauth validates params
|
|
||||||
↓
|
|
||||||
(if not auth'd) user logs in via rodauth
|
|
||||||
↓
|
|
||||||
(if first use) consent page rendered
|
|
||||||
↓
|
|
||||||
create oauth_grant (code, nonce, PKCE challenge, etc.)
|
|
||||||
↓
|
|
||||||
redirect with auth code
|
|
||||||
|
|
||||||
2. Token Exchange
|
|
||||||
↓
|
|
||||||
rodauth validates client (Basic/POST auth)
|
|
||||||
↓
|
|
||||||
validates code, redirect_uri, PKCE verifier
|
|
||||||
↓
|
|
||||||
creates access token (plain or JWT)
|
|
||||||
↓
|
|
||||||
creates refresh token
|
|
||||||
↓
|
|
||||||
returns JSON with tokens
|
|
||||||
|
|
||||||
3. UserInfo
|
|
||||||
↓
|
|
||||||
validate access token
|
|
||||||
↓
|
|
||||||
lookup grant/account
|
|
||||||
↓
|
|
||||||
return claims as JSON
|
|
||||||
```
|
|
||||||
|
|
||||||
### Feature Composition
|
|
||||||
|
|
||||||
Features depend on each other. For example:
|
|
||||||
- `oidc` depends on: `active_sessions`, `oauth_jwt`, `oauth_jwt_jwks`, `oauth_authorization_code_grant`, `oauth_implicit_grant`
|
|
||||||
- `oauth_pkce` depends on: `oauth_authorization_code_grant`
|
|
||||||
- `oidc_rp_initiated_logout` depends on: `oidc`
|
|
||||||
|
|
||||||
This is a **strong dependency injection pattern**.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5. Database Schema Requirements
|
|
||||||
|
|
||||||
### Rodauth-OAuth Tables
|
|
||||||
|
|
||||||
#### `accounts` table (from rodauth)
|
|
||||||
```sql
|
|
||||||
CREATE TABLE accounts (
|
|
||||||
id INTEGER PRIMARY KEY,
|
|
||||||
status_id INTEGER DEFAULT 1, -- unverified/verified/closed
|
|
||||||
email VARCHAR UNIQUE NOT NULL,
|
|
||||||
-- password-related columns (added by rodauth features)
|
|
||||||
password_hash VARCHAR,
|
|
||||||
-- other rodauth-managed columns
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### `oauth_applications` table (75+ columns!)
|
|
||||||
```sql
|
|
||||||
CREATE TABLE oauth_applications (
|
|
||||||
id INTEGER PRIMARY KEY,
|
|
||||||
account_id INTEGER FOREIGN KEY,
|
|
||||||
|
|
||||||
-- Basic info
|
|
||||||
name VARCHAR NOT NULL,
|
|
||||||
description VARCHAR,
|
|
||||||
homepage_url VARCHAR,
|
|
||||||
logo_uri VARCHAR,
|
|
||||||
tos_uri VARCHAR,
|
|
||||||
policy_uri VARCHAR,
|
|
||||||
|
|
||||||
-- OAuth credentials
|
|
||||||
client_id VARCHAR UNIQUE NOT NULL,
|
|
||||||
client_secret VARCHAR UNIQUE NOT NULL,
|
|
||||||
registration_access_token VARCHAR,
|
|
||||||
|
|
||||||
-- OAuth config
|
|
||||||
redirect_uri VARCHAR NOT NULL,
|
|
||||||
scopes VARCHAR NOT NULL,
|
|
||||||
token_endpoint_auth_method VARCHAR,
|
|
||||||
grant_types VARCHAR,
|
|
||||||
response_types VARCHAR,
|
|
||||||
response_modes VARCHAR,
|
|
||||||
|
|
||||||
-- JWT/JWKS
|
|
||||||
jwks_uri VARCHAR,
|
|
||||||
jwks TEXT,
|
|
||||||
jwt_public_key TEXT,
|
|
||||||
|
|
||||||
-- OIDC-specific
|
|
||||||
sector_identifier_uri VARCHAR,
|
|
||||||
application_type VARCHAR,
|
|
||||||
initiate_login_uri VARCHAR,
|
|
||||||
subject_type VARCHAR,
|
|
||||||
|
|
||||||
-- Token encryption algorithms
|
|
||||||
id_token_signed_response_alg VARCHAR,
|
|
||||||
id_token_encrypted_response_alg VARCHAR,
|
|
||||||
id_token_encrypted_response_enc VARCHAR,
|
|
||||||
userinfo_signed_response_alg VARCHAR,
|
|
||||||
userinfo_encrypted_response_alg VARCHAR,
|
|
||||||
userinfo_encrypted_response_enc VARCHAR,
|
|
||||||
|
|
||||||
-- Request object handling
|
|
||||||
request_object_signing_alg VARCHAR,
|
|
||||||
request_object_encryption_alg VARCHAR,
|
|
||||||
request_object_encryption_enc VARCHAR,
|
|
||||||
request_uris VARCHAR,
|
|
||||||
require_signed_request_object BOOLEAN,
|
|
||||||
|
|
||||||
-- PAR (Pushed Auth Requests)
|
|
||||||
require_pushed_authorization_requests BOOLEAN DEFAULT FALSE,
|
|
||||||
|
|
||||||
-- DPoP
|
|
||||||
dpop_bound_access_tokens BOOLEAN DEFAULT FALSE,
|
|
||||||
|
|
||||||
-- TLS Client Auth
|
|
||||||
tls_client_auth_subject_dn VARCHAR,
|
|
||||||
tls_client_auth_san_dns VARCHAR,
|
|
||||||
tls_client_auth_san_uri VARCHAR,
|
|
||||||
tls_client_auth_san_ip VARCHAR,
|
|
||||||
tls_client_auth_san_email VARCHAR,
|
|
||||||
tls_client_certificate_bound_access_tokens BOOLEAN DEFAULT FALSE,
|
|
||||||
|
|
||||||
-- Logout URIs
|
|
||||||
post_logout_redirect_uris VARCHAR,
|
|
||||||
frontchannel_logout_uri VARCHAR,
|
|
||||||
frontchannel_logout_session_required BOOLEAN DEFAULT FALSE,
|
|
||||||
backchannel_logout_uri VARCHAR,
|
|
||||||
backchannel_logout_session_required BOOLEAN DEFAULT FALSE,
|
|
||||||
|
|
||||||
-- Response encryption
|
|
||||||
authorization_signed_response_alg VARCHAR,
|
|
||||||
authorization_encrypted_response_alg VARCHAR,
|
|
||||||
authorization_encrypted_response_enc VARCHAR,
|
|
||||||
|
|
||||||
contact_info VARCHAR,
|
|
||||||
software_id VARCHAR,
|
|
||||||
software_version VARCHAR
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### `oauth_grants` table (everything in one table!)
|
|
||||||
```sql
|
|
||||||
CREATE TABLE oauth_grants (
|
|
||||||
id INTEGER PRIMARY KEY,
|
|
||||||
account_id INTEGER FOREIGN KEY, -- nullable for client credentials
|
|
||||||
oauth_application_id INTEGER FOREIGN KEY,
|
|
||||||
sub_account_id INTEGER, -- for context-based ownership
|
|
||||||
|
|
||||||
type VARCHAR, -- 'authorization_code', 'refresh_token', etc.
|
|
||||||
|
|
||||||
-- Authorization code flow
|
|
||||||
code VARCHAR UNIQUE (per app),
|
|
||||||
redirect_uri VARCHAR,
|
|
||||||
|
|
||||||
-- Tokens (stored hashed or plain)
|
|
||||||
token VARCHAR UNIQUE,
|
|
||||||
token_hash VARCHAR UNIQUE,
|
|
||||||
refresh_token VARCHAR UNIQUE,
|
|
||||||
refresh_token_hash VARCHAR UNIQUE,
|
|
||||||
|
|
||||||
-- Expiry
|
|
||||||
expires_in TIMESTAMP NOT NULL,
|
|
||||||
revoked_at TIMESTAMP,
|
|
||||||
|
|
||||||
-- Scopes
|
|
||||||
scopes VARCHAR NOT NULL,
|
|
||||||
access_type VARCHAR DEFAULT 'offline', -- 'offline' or 'online'
|
|
||||||
|
|
||||||
-- PKCE
|
|
||||||
code_challenge VARCHAR,
|
|
||||||
code_challenge_method VARCHAR, -- 'plain' or 'S256'
|
|
||||||
|
|
||||||
-- Device Code Grant
|
|
||||||
user_code VARCHAR UNIQUE,
|
|
||||||
last_polled_at TIMESTAMP,
|
|
||||||
|
|
||||||
-- TLS Client Auth
|
|
||||||
certificate_thumbprint VARCHAR,
|
|
||||||
|
|
||||||
-- Resource Indicators
|
|
||||||
resource VARCHAR,
|
|
||||||
|
|
||||||
-- OpenID Connect
|
|
||||||
nonce VARCHAR,
|
|
||||||
acr VARCHAR, -- Authentication Context Class
|
|
||||||
claims_locales VARCHAR,
|
|
||||||
claims VARCHAR, -- custom OIDC claims
|
|
||||||
|
|
||||||
-- DPoP
|
|
||||||
dpop_jkt VARCHAR -- DPoP key thumbprint
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Optional Tables for Advanced Features
|
|
||||||
|
|
||||||
```sql
|
|
||||||
-- For Pushed Authorization Requests
|
|
||||||
CREATE TABLE oauth_pushed_requests (
|
|
||||||
request_uri VARCHAR UNIQUE PRIMARY KEY,
|
|
||||||
oauth_application_id INTEGER FOREIGN KEY,
|
|
||||||
params TEXT, -- JSON params
|
|
||||||
created_at TIMESTAMP
|
|
||||||
);
|
|
||||||
|
|
||||||
-- For SAML Assertion Grant
|
|
||||||
CREATE TABLE oauth_saml_settings (
|
|
||||||
id INTEGER PRIMARY KEY,
|
|
||||||
oauth_application_id INTEGER FOREIGN KEY,
|
|
||||||
idp_url VARCHAR,
|
|
||||||
certificate TEXT,
|
|
||||||
-- ...
|
|
||||||
);
|
|
||||||
|
|
||||||
-- For DPoP
|
|
||||||
CREATE TABLE oauth_dpop_proofs (
|
|
||||||
id INTEGER PRIMARY KEY,
|
|
||||||
oauth_grant_id INTEGER FOREIGN KEY,
|
|
||||||
jti VARCHAR UNIQUE,
|
|
||||||
created_at TIMESTAMP
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
### Key Differences from Your Implementation
|
|
||||||
|
|
||||||
| Aspect | Your Implementation | Rodauth-OAuth |
|
|
||||||
|--------|-------------------|----------------|
|
|
||||||
| Authorization Codes | Separate table | In oauth_grants |
|
|
||||||
| Access Tokens | Separate table | In oauth_grants |
|
|
||||||
| Refresh Tokens | Not implemented | In oauth_grants |
|
|
||||||
| Token Hashing | Not done | Bcrypt (default) |
|
|
||||||
| Applications | Basic (name, client_id, secret) | 75+ columns for full spec |
|
|
||||||
| PKCE | Simple columns | Built-in feature |
|
|
||||||
| Account Data | In users table | In accounts table |
|
|
||||||
| Session Management | Session model | Rodauth's account_active_session_keys |
|
|
||||||
| User Consent | OidcUserConsent table | In memory or via hooks |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6. Integration Points with Rails
|
|
||||||
|
|
||||||
### Via Rodauth-Rails Wrapper
|
|
||||||
|
|
||||||
Rodauth-OAuth can be used in Rails through the `rodauth-rails` gem:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Install generator
|
|
||||||
gem 'rodauth-rails'
|
|
||||||
bundle install
|
|
||||||
rails generate rodauth:install
|
|
||||||
rails generate rodauth:oauth:install # Generates OIDC tables/migrations
|
|
||||||
rails generate rodauth:oauth:views # Generates templates
|
|
||||||
```
|
|
||||||
|
|
||||||
### Generated Components
|
|
||||||
|
|
||||||
1. **Migration**: `db/migrate/*_create_rodauth_oauth.rb`
|
|
||||||
- Creates all OAuth tables
|
|
||||||
- Customizable column names via config
|
|
||||||
|
|
||||||
2. **Models**: `app/models/`
|
|
||||||
- `RodauthApp` (configuration)
|
|
||||||
- `OauthApplication` (client app)
|
|
||||||
- `OauthGrant` (grants/tokens)
|
|
||||||
- Customizable!
|
|
||||||
|
|
||||||
3. **Views**: `app/views/rodauth/`
|
|
||||||
- Authorization consent form
|
|
||||||
- Application management dashboard
|
|
||||||
- Grant management dashboard
|
|
||||||
|
|
||||||
4. **Lib**: `lib/rodauth_app.rb`
|
|
||||||
- Main rodauth configuration
|
|
||||||
|
|
||||||
### Rails Controller Integration
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
class BooksController < ApplicationController
|
|
||||||
before_action :require_oauth_authorization, only: %i[create update]
|
|
||||||
before_action :require_oauth_authorization_scopes, only: %i[create update]
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def require_oauth_authorization(scope = "books.read")
|
|
||||||
rodauth.require_oauth_authorization(scope)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
Or for route protection:
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
# config/routes.rb
|
|
||||||
namespace :api do
|
|
||||||
resources :books, only: [:index] # protected by rodauth
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 7. Architectural Comparison
|
|
||||||
|
|
||||||
### Your Custom Implementation
|
|
||||||
|
|
||||||
**Pros:**
|
|
||||||
- Simple, easy to understand
|
|
||||||
- Minimal dependencies (just JWT, OpenSSL)
|
|
||||||
- Lightweight database (small tables)
|
|
||||||
- Direct Rails integration
|
|
||||||
- Minimal features = less surface area
|
|
||||||
|
|
||||||
**Cons:**
|
|
||||||
- Only supports Authorization Code + PKCE
|
|
||||||
- No refresh tokens
|
|
||||||
- No token revocation/introspection
|
|
||||||
- No client credentials grant
|
|
||||||
- No JWT access tokens
|
|
||||||
- Manual consent management
|
|
||||||
- Not standards-compliant (missing many OIDC features)
|
|
||||||
- Will need continuous custom development
|
|
||||||
|
|
||||||
**Architecture:**
|
|
||||||
```
|
|
||||||
Rails Controller
|
|
||||||
↓
|
|
||||||
OidcController (450 lines)
|
|
||||||
↓
|
|
||||||
OidcAuthorizationCode Model
|
|
||||||
OidcAccessToken Model
|
|
||||||
OidcUserConsent Model
|
|
||||||
↓
|
|
||||||
Database
|
|
||||||
```
|
|
||||||
|
|
||||||
### Rodauth-OAuth Implementation
|
|
||||||
|
|
||||||
**Pros:**
|
|
||||||
- 34 built-in features
|
|
||||||
- OpenID-Certified
|
|
||||||
- Production-tested
|
|
||||||
- Highly configurable
|
|
||||||
- Comprehensive token management
|
|
||||||
- Standards-compliant (RFCs & OpenID specs)
|
|
||||||
- Strong test coverage (hundreds of tests)
|
|
||||||
- Active maintenance
|
|
||||||
|
|
||||||
**Cons:**
|
|
||||||
- More complex (needs Roda/Rodauth knowledge)
|
|
||||||
- Larger codebase to learn
|
|
||||||
- Rails integration via wrapper (extra layer)
|
|
||||||
- Different paradigm (Roda vs Rails)
|
|
||||||
- More database columns to manage
|
|
||||||
|
|
||||||
**Architecture:**
|
|
||||||
```
|
|
||||||
Roda App
|
|
||||||
↓
|
|
||||||
Rodauth Plugin (configurable)
|
|
||||||
├── oauth_base (foundation)
|
|
||||||
├── oauth_authorization_code_grant
|
|
||||||
├── oauth_pkce
|
|
||||||
├── oauth_jwt
|
|
||||||
├── oidc (all OpenID features)
|
|
||||||
├── [other optional features]
|
|
||||||
↓
|
|
||||||
Sequel ORM
|
|
||||||
↓
|
|
||||||
Database (flexible schema)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 8. Feature Comparison Matrix
|
|
||||||
|
|
||||||
| Feature | Your Impl | Rodauth-OAuth | Notes |
|
|
||||||
|---------|-----------|---------------|-------|
|
|
||||||
| **Authorization Code** | ✓ | ✓ | Both support |
|
|
||||||
| **PKCE** | ✓ | ✓ | Both support |
|
|
||||||
| **Refresh Tokens** | ✗ | ✓ | You'd need to add |
|
|
||||||
| **Implicit Flow** | ✗ | ✓ Optional | Legacy, not recommended |
|
|
||||||
| **Client Credentials** | ✗ | ✓ Optional | Machine-to-machine |
|
|
||||||
| **Device Code** | ✗ | ✓ Optional | IoT devices |
|
|
||||||
| **JWT Bearer Grant** | ✗ | ✓ Optional | Service accounts |
|
|
||||||
| **SAML Bearer Grant** | ✗ | ✓ Optional | Enterprise SAML |
|
|
||||||
| **JWT Access Tokens** | ✗ | ✓ Optional | Stateless tokens |
|
|
||||||
| **Token Revocation** | ✗ | ✓ | RFC 7009 |
|
|
||||||
| **Token Introspection** | ✗ | ✓ | RFC 7662 |
|
|
||||||
| **Pushed Auth Requests** | ✗ | ✓ Optional | RFC 9126 |
|
|
||||||
| **DPoP** | ✗ | ✓ Optional | RFC 9449 |
|
|
||||||
| **TLS Client Auth** | ✗ | ✓ Optional | RFC 8705 |
|
|
||||||
| **OpenID Connect** | ✓ Basic | ✓ Full | Yours is minimal |
|
|
||||||
| **ID Tokens** | ✓ | ✓ | Both support |
|
|
||||||
| **UserInfo Endpoint** | ✓ | ✓ | Both support |
|
|
||||||
| **Discovery** | ✓ | ✓ | Both support |
|
|
||||||
| **Session Management** | ✗ | ✓ Optional | Check session iframe |
|
|
||||||
| **RP-Init Logout** | ✓ | ✓ | Both support |
|
|
||||||
| **Front-Channel Logout** | ✗ | ✓ | Iframe-based |
|
|
||||||
| **Back-Channel Logout** | ✗ | ✓ | Server-to-server |
|
|
||||||
| **Dynamic Client Reg** | ✗ | ✓ Optional | RFC 7591/7592 |
|
|
||||||
| **Token Hashing** | ✗ | ✓ | Security best practice |
|
|
||||||
| **Scopes** | ✓ | ✓ | Both support |
|
|
||||||
| **Custom Claims** | ✓ Manual | ✓ Built-in | Yours via JWT service |
|
|
||||||
| **Consent UI** | ✓ | ✓ | Both support |
|
|
||||||
| **Client App Dashboard** | ✗ | ✓ Optional | Built-in |
|
|
||||||
| **Grant Management Dashboard** | ✗ | ✓ Optional | Built-in |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 9. Integration Complexity Analysis
|
|
||||||
|
|
||||||
### Switching to Rodauth-OAuth
|
|
||||||
|
|
||||||
#### Medium Complexity (Not Trivial, but Doable)
|
|
||||||
|
|
||||||
**What you'd need to do:**
|
|
||||||
|
|
||||||
1. **Learn Roda + Rodauth**
|
|
||||||
- Move from pure Rails to Roda-based architecture
|
|
||||||
- Understand rodauth feature system
|
|
||||||
- Time: 1-2 weeks for Rails developers
|
|
||||||
|
|
||||||
2. **Migrate Database Schema**
|
|
||||||
- Consolidate tables: authorization codes + access tokens → oauth_grants
|
|
||||||
- Rename columns to match rodauth conventions
|
|
||||||
- Add many new columns for feature support
|
|
||||||
- Migration script needed: ~100-300 lines
|
|
||||||
- Time: 1 week development + testing
|
|
||||||
|
|
||||||
3. **Replace Your OIDC Code**
|
|
||||||
- Replace your 450-line OidcController
|
|
||||||
- Remove your 3 model files
|
|
||||||
- Keep your OidcJwtService (mostly compatible)
|
|
||||||
- Add rodauth configuration
|
|
||||||
- Time: 1-2 weeks
|
|
||||||
|
|
||||||
4. **Update Application/Client Model**
|
|
||||||
- Expand `Application` model properties
|
|
||||||
- Support all OAuth scopes, grant types, response types
|
|
||||||
- Time: 3-5 days
|
|
||||||
|
|
||||||
5. **Create Migrations from Template**
|
|
||||||
- Use rodauth-oauth migration templates
|
|
||||||
- Customize for your database
|
|
||||||
- Time: 2-3 days
|
|
||||||
|
|
||||||
6. **Testing**
|
|
||||||
- Write integration tests
|
|
||||||
- Verify all OAuth flows still work
|
|
||||||
- Check token validation logic
|
|
||||||
- Time: 2-3 weeks
|
|
||||||
|
|
||||||
**Total Effort:** 4-8 weeks for experienced team
|
|
||||||
|
|
||||||
### Keeping Your Implementation (Custom Path)
|
|
||||||
|
|
||||||
#### What You'd Need to Add
|
|
||||||
|
|
||||||
To reach feature parity with rodauth-oauth (for common use cases):
|
|
||||||
|
|
||||||
1. **Refresh Token Support** (1-2 weeks)
|
|
||||||
- Database schema
|
|
||||||
- Token refresh endpoint
|
|
||||||
- Token validation logic
|
|
||||||
|
|
||||||
2. **Token Revocation** (1 week)
|
|
||||||
- Revocation endpoint
|
|
||||||
- Token blacklist/invalidation
|
|
||||||
|
|
||||||
3. **Token Introspection** (1 week)
|
|
||||||
- Introspection endpoint
|
|
||||||
- Token validation without DB lookup
|
|
||||||
|
|
||||||
4. **Client Credentials Grant** (2 weeks)
|
|
||||||
- Endpoint logic
|
|
||||||
- Client authentication
|
|
||||||
- Token generation for apps
|
|
||||||
|
|
||||||
5. **Improved Security** (ongoing)
|
|
||||||
- Token hashing (bcrypt)
|
|
||||||
- Rate limiting
|
|
||||||
- Additional validation
|
|
||||||
|
|
||||||
6. **Advanced OIDC Features**
|
|
||||||
- Session Management
|
|
||||||
- Logout endpoints (front/back-channel)
|
|
||||||
- Dynamic client registration
|
|
||||||
- Device code flow
|
|
||||||
|
|
||||||
**Total Effort:** 2-3 months ongoing
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 10. Key Findings & Recommendations
|
|
||||||
|
|
||||||
### What Rodauth-OAuth Does Better
|
|
||||||
|
|
||||||
1. **Standards Compliance**
|
|
||||||
- Certified for 11 OpenID Connect profiles
|
|
||||||
- Implements 20+ RFCs and specs
|
|
||||||
- Regular spec updates
|
|
||||||
|
|
||||||
2. **Security**
|
|
||||||
- Token hashing by default
|
|
||||||
- DPoP support (token binding)
|
|
||||||
- TLS client auth
|
|
||||||
- Proper scope enforcement
|
|
||||||
|
|
||||||
3. **Features**
|
|
||||||
- 34 optional features (you get what you need)
|
|
||||||
- No bloat - only enable what you use
|
|
||||||
- Mature refresh token handling
|
|
||||||
|
|
||||||
4. **Production Readiness**
|
|
||||||
- Thousands of test cases
|
|
||||||
- Open source (auditable)
|
|
||||||
- Active maintenance
|
|
||||||
- Real-world deployments
|
|
||||||
|
|
||||||
5. **Flexibility**
|
|
||||||
- Works with any SQL database
|
|
||||||
- Highly configurable column names
|
|
||||||
- Custom behavior via overrides
|
|
||||||
- Multiple app types support
|
|
||||||
|
|
||||||
### What Your Implementation Does Better
|
|
||||||
|
|
||||||
1. **Simplicity**
|
|
||||||
- Fewer dependencies
|
|
||||||
- Smaller codebase
|
|
||||||
- Easier to reason about
|
|
||||||
|
|
||||||
2. **Rails Integration**
|
|
||||||
- Direct Rails ActiveRecord
|
|
||||||
- No Roda learning curve
|
|
||||||
- Familiar patterns
|
|
||||||
|
|
||||||
3. **Control**
|
|
||||||
- Full control of every line
|
|
||||||
- No surprises
|
|
||||||
- Easy to debug
|
|
||||||
|
|
||||||
### Recommendation
|
|
||||||
|
|
||||||
**Use Rodauth-OAuth IF:**
|
|
||||||
- You need a production OIDC/OAuth provider
|
|
||||||
- You want standards compliance
|
|
||||||
- You plan to support multiple grant types
|
|
||||||
- You need token revocation/introspection
|
|
||||||
- You want a maintained codebase
|
|
||||||
|
|
||||||
**Keep Your Custom Implementation IF:**
|
|
||||||
- Authorization Code + PKCE only is sufficient
|
|
||||||
- You're avoiding Roda/Rodauth learning curve
|
|
||||||
- Your org standardizes on Rails patterns
|
|
||||||
- You have time to add features incrementally
|
|
||||||
- You need maximum control and simplicity
|
|
||||||
|
|
||||||
**Hybrid Approach:**
|
|
||||||
- Use rodauth-oauth for OIDC/OAuth server components
|
|
||||||
- Keep your Rails app for other features
|
|
||||||
- They can coexist (separate services)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 11. Migration Path (If You Decide to Switch)
|
|
||||||
|
|
||||||
### Phase 1: Preparation (Week 1-2)
|
|
||||||
- Set up separate Roda app with rodauth-oauth
|
|
||||||
- Run alongside your existing service
|
|
||||||
- Parallel user testing
|
|
||||||
|
|
||||||
### Phase 2: Data Migration (Week 2-3)
|
|
||||||
- Create migration script for oauth_grants table
|
|
||||||
- Backfill existing auth codes and tokens
|
|
||||||
- Verify data integrity
|
|
||||||
|
|
||||||
### Phase 3: Gradual Cutover (Week 4-6)
|
|
||||||
- Direct some OAuth clients to new server
|
|
||||||
- Monitor for issues
|
|
||||||
- Swap over when confident
|
|
||||||
|
|
||||||
### Phase 4: Cleanup (Week 6+)
|
|
||||||
- Remove custom OIDC code
|
|
||||||
- Decommission old tables
|
|
||||||
- Document new architecture
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 12. Code Examples
|
|
||||||
|
|
||||||
### Rodauth-OAuth: Minimal Setup
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
# Gemfile
|
|
||||||
gem 'roda'
|
|
||||||
gem 'rodauth-oauth'
|
|
||||||
gem 'sequel'
|
|
||||||
|
|
||||||
# lib/auth_server.rb
|
|
||||||
class AuthServer < Roda
|
|
||||||
plugin :render, views: 'views'
|
|
||||||
plugin :sessions, secret: 'SECRET'
|
|
||||||
|
|
||||||
plugin :rodauth do
|
|
||||||
db DB
|
|
||||||
enable :login, :logout, :create_account, :oidc, :oauth_pkce,
|
|
||||||
:oauth_authorization_code_grant, :oauth_token_introspection
|
|
||||||
|
|
||||||
oauth_application_scopes %w[openid email profile]
|
|
||||||
oauth_require_pkce true
|
|
||||||
hmac_secret 'HMAC_SECRET'
|
|
||||||
|
|
||||||
oauth_jwt_keys('RS256' => [private_key])
|
|
||||||
end
|
|
||||||
|
|
||||||
route do |r|
|
|
||||||
r.rodauth # All OAuth routes automatically mounted
|
|
||||||
|
|
||||||
# Your custom routes
|
|
||||||
r.get 'api' do
|
|
||||||
rodauth.require_oauth_authorization('api.read')
|
|
||||||
# return data
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
### Your Current Approach: Manual
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
# app/controllers/oidc_controller.rb
|
|
||||||
def authorize
|
|
||||||
validate_params
|
|
||||||
find_application
|
|
||||||
check_authentication
|
|
||||||
handle_consent
|
|
||||||
generate_code
|
|
||||||
redirect_with_code
|
|
||||||
end
|
|
||||||
|
|
||||||
def token
|
|
||||||
extract_client_credentials
|
|
||||||
find_application
|
|
||||||
validate_code
|
|
||||||
check_pkce
|
|
||||||
generate_tokens
|
|
||||||
return_json
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Summary Table
|
|
||||||
|
|
||||||
| Aspect | Your Implementation | Rodauth-OAuth |
|
|
||||||
|--------|-------------------|----------------|
|
|
||||||
| **Framework** | Rails | Roda |
|
|
||||||
| **Database ORM** | ActiveRecord | Sequel |
|
|
||||||
| **Grant Types** | 1 (Auth Code) | 7+ options |
|
|
||||||
| **Token Types** | Opaque | Opaque or JWT |
|
|
||||||
| **Security Features** | Basic | Advanced (DPoP, MTLS, etc.) |
|
|
||||||
| **OIDC Compliance** | Partial | Full (Certified) |
|
|
||||||
| **Lines of Code** | ~1000 | ~10,000+ |
|
|
||||||
| **Features** | 2-3 | 34 optional |
|
|
||||||
| **Maintenance Burden** | High | Low (OSS) |
|
|
||||||
| **Learning Curve** | Low | Medium (Roda) |
|
|
||||||
| **Production Ready** | Yes | Yes |
|
|
||||||
| **Community** | Just you | Active |
|
|
||||||
|
|
||||||
@@ -1,418 +0,0 @@
|
|||||||
# Rodauth-OAuth: Quick Reference Guide
|
|
||||||
|
|
||||||
## What Is It?
|
|
||||||
A production-ready Ruby gem implementing OAuth 2.0 and OpenID Connect. Think of it as a complete, standards-certified OAuth/OIDC server library for Ruby apps.
|
|
||||||
|
|
||||||
## Key Stats
|
|
||||||
- **Framework**: Roda (not Rails, but works with Rails via wrapper)
|
|
||||||
- **Features**: 34 modular features you can enable/disable
|
|
||||||
- **Certification**: Officially certified for 11 OpenID Connect profiles
|
|
||||||
- **Test Coverage**: Hundreds of tests
|
|
||||||
- **Status**: Production-ready, actively maintained
|
|
||||||
|
|
||||||
## Why Consider It?
|
|
||||||
|
|
||||||
### Advantages Over Your Implementation
|
|
||||||
1. **Complete OAuth/OIDC Implementation**
|
|
||||||
- All major grant types supported
|
|
||||||
- Certified compliance with standards
|
|
||||||
- 20+ RFC implementations
|
|
||||||
|
|
||||||
2. **Security Features**
|
|
||||||
- Token hashing (bcrypt) by default
|
|
||||||
- DPoP support (token binding)
|
|
||||||
- TLS mutual authentication
|
|
||||||
- Proper scope enforcement
|
|
||||||
|
|
||||||
3. **Advanced Token Management**
|
|
||||||
- Refresh tokens (you don't have)
|
|
||||||
- Token revocation
|
|
||||||
- Token introspection
|
|
||||||
- Token rotation policies
|
|
||||||
|
|
||||||
4. **Low Maintenance**
|
|
||||||
- Well-tested codebase
|
|
||||||
- Active community
|
|
||||||
- Regular spec updates
|
|
||||||
- Battle-tested in production
|
|
||||||
|
|
||||||
5. **Extensible**
|
|
||||||
- Highly configurable
|
|
||||||
- Override any behavior you need
|
|
||||||
- Database-agnostic
|
|
||||||
- Works with any SQL DB
|
|
||||||
|
|
||||||
### What Your Implementation Does Better
|
|
||||||
1. **Simplicity** - Fewer lines of code, easier to understand
|
|
||||||
2. **Rails Native** - No need to learn Roda
|
|
||||||
3. **Control** - Full ownership of the codebase
|
|
||||||
4. **Minimal Dependencies** - Just JWT and OpenSSL
|
|
||||||
|
|
||||||
## Architecture Overview
|
|
||||||
|
|
||||||
### Your Current Setup
|
|
||||||
```
|
|
||||||
Rails App
|
|
||||||
└─ OidcController (450 lines)
|
|
||||||
├─ /oauth/authorize
|
|
||||||
├─ /oauth/token
|
|
||||||
├─ /oauth/userinfo
|
|
||||||
└─ /logout
|
|
||||||
|
|
||||||
Models:
|
|
||||||
├─ OidcAuthorizationCode
|
|
||||||
├─ OidcAccessToken
|
|
||||||
└─ OidcUserConsent
|
|
||||||
|
|
||||||
Features Supported:
|
|
||||||
├─ Authorization Code Flow ✓
|
|
||||||
├─ PKCE ✓
|
|
||||||
└─ Basic OIDC ✓
|
|
||||||
|
|
||||||
NOT Supported:
|
|
||||||
├─ Refresh Tokens
|
|
||||||
├─ Token Revocation
|
|
||||||
├─ Token Introspection
|
|
||||||
├─ Client Credentials Grant
|
|
||||||
├─ Device Code Flow
|
|
||||||
├─ Session Management
|
|
||||||
├─ Front/Back-Channel Logout
|
|
||||||
└─ Dynamic Client Registration
|
|
||||||
```
|
|
||||||
|
|
||||||
### Rodauth-OAuth Setup
|
|
||||||
```
|
|
||||||
Roda App (web framework)
|
|
||||||
└─ Rodauth Plugin (authentication/authorization)
|
|
||||||
├─ oauth_base (foundation)
|
|
||||||
├─ oauth_authorization_code_grant
|
|
||||||
├─ oauth_pkce
|
|
||||||
├─ oauth_jwt (optional)
|
|
||||||
├─ oidc (OpenID core)
|
|
||||||
├─ oidc_session_management (optional)
|
|
||||||
├─ oidc_rp_initiated_logout (optional)
|
|
||||||
├─ oidc_frontchannel_logout (optional)
|
|
||||||
├─ oidc_backchannel_logout (optional)
|
|
||||||
├─ oauth_token_revocation (optional)
|
|
||||||
├─ oauth_token_introspection (optional)
|
|
||||||
├─ oauth_client_credentials_grant (optional)
|
|
||||||
└─ ... (28+ more optional features)
|
|
||||||
|
|
||||||
Routes Generated Automatically:
|
|
||||||
├─ /.well-known/openid-configuration ✓
|
|
||||||
├─ /.well-known/jwks.json ✓
|
|
||||||
├─ /oauth/authorize ✓
|
|
||||||
├─ /oauth/token ✓
|
|
||||||
├─ /oauth/userinfo ✓
|
|
||||||
├─ /oauth/introspect (optional)
|
|
||||||
├─ /oauth/revoke (optional)
|
|
||||||
└─ /logout ✓
|
|
||||||
```
|
|
||||||
|
|
||||||
## Database Schema Comparison
|
|
||||||
|
|
||||||
### Your Current Tables
|
|
||||||
```
|
|
||||||
oidc_authorization_codes
|
|
||||||
├─ id
|
|
||||||
├─ user_id
|
|
||||||
├─ application_id
|
|
||||||
├─ code (unique)
|
|
||||||
├─ redirect_uri
|
|
||||||
├─ scope
|
|
||||||
├─ nonce
|
|
||||||
├─ code_challenge
|
|
||||||
├─ code_challenge_method
|
|
||||||
├─ used (boolean)
|
|
||||||
├─ expires_at
|
|
||||||
└─ created_at
|
|
||||||
|
|
||||||
oidc_access_tokens
|
|
||||||
├─ id
|
|
||||||
├─ user_id
|
|
||||||
├─ application_id
|
|
||||||
├─ token (unique)
|
|
||||||
├─ scope
|
|
||||||
├─ expires_at
|
|
||||||
└─ created_at
|
|
||||||
|
|
||||||
oidc_user_consents
|
|
||||||
├─ user_id
|
|
||||||
├─ application_id
|
|
||||||
├─ scopes_granted
|
|
||||||
└─ granted_at
|
|
||||||
|
|
||||||
applications
|
|
||||||
├─ id
|
|
||||||
├─ name
|
|
||||||
├─ client_id (unique)
|
|
||||||
├─ client_secret
|
|
||||||
├─ redirect_uris (JSON)
|
|
||||||
├─ app_type
|
|
||||||
└─ ... (few more fields)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Rodauth-OAuth Tables
|
|
||||||
```
|
|
||||||
accounts (from rodauth)
|
|
||||||
├─ id
|
|
||||||
├─ status_id
|
|
||||||
├─ email
|
|
||||||
└─ password_hash
|
|
||||||
|
|
||||||
oauth_applications (75+ columns!)
|
|
||||||
├─ Basic: id, account_id, name, description
|
|
||||||
├─ OAuth: client_id, client_secret, redirect_uri, scopes
|
|
||||||
├─ Config: token_endpoint_auth_method, grant_types, response_types
|
|
||||||
├─ JWT/JWKS: jwks_uri, jwks, jwt_public_key
|
|
||||||
├─ OIDC: subject_type, id_token_signed_response_alg, etc.
|
|
||||||
├─ PAR: require_pushed_authorization_requests
|
|
||||||
├─ DPoP: dpop_bound_access_tokens
|
|
||||||
├─ TLS: tls_client_auth_* fields
|
|
||||||
└─ Logout: post_logout_redirect_uris, frontchannel_logout_uri, etc.
|
|
||||||
|
|
||||||
oauth_grants (consolidated - replaces your two tables!)
|
|
||||||
├─ id, account_id, oauth_application_id
|
|
||||||
├─ type (authorization_code, refresh_token, etc.)
|
|
||||||
├─ code, token, refresh_token (with hashed versions)
|
|
||||||
├─ expires_in, revoked_at
|
|
||||||
├─ scopes, access_type
|
|
||||||
├─ code_challenge, code_challenge_method (PKCE)
|
|
||||||
├─ user_code, last_polled_at (Device code grant)
|
|
||||||
├─ nonce, acr, claims (OIDC)
|
|
||||||
├─ dpop_jkt (DPoP)
|
|
||||||
└─ certificate_thumbprint, resource (advanced)
|
|
||||||
|
|
||||||
[Optional tables for features you enable]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Feature Comparison Matrix
|
|
||||||
|
|
||||||
| Feature | Your Code | Rodauth-OAuth | Effort to Add* |
|
|
||||||
|---------|-----------|---------------|--------|
|
|
||||||
| Authorization Code Flow | ✓ | ✓ | N/A |
|
|
||||||
| PKCE | ✓ | ✓ | N/A |
|
|
||||||
| Refresh Tokens | ✗ | ✓ | 1-2 weeks |
|
|
||||||
| Token Revocation | ✗ | ✓ | 1 week |
|
|
||||||
| Token Introspection | ✗ | ✓ | 1 week |
|
|
||||||
| Client Credentials Grant | ✗ | ✓ | 2 weeks |
|
|
||||||
| Device Code Flow | ✗ | ✓ | 3 weeks |
|
|
||||||
| JWT Access Tokens | ✗ | ✓ | 1 week |
|
|
||||||
| Session Management | ✗ | ✓ | 2-3 weeks |
|
|
||||||
| Front-Channel Logout | ✗ | ✓ | 1-2 weeks |
|
|
||||||
| Back-Channel Logout | ✗ | ✓ | 2 weeks |
|
|
||||||
| Dynamic Client Reg | ✗ | ✓ | 3-4 weeks |
|
|
||||||
| Token Hashing | ✗ | ✓ | 1 week |
|
|
||||||
|
|
||||||
*Time estimates for adding to your implementation
|
|
||||||
|
|
||||||
## Code Examples
|
|
||||||
|
|
||||||
### Rodauth-OAuth: Minimal OAuth Server
|
|
||||||
```ruby
|
|
||||||
# Gemfile
|
|
||||||
gem 'roda'
|
|
||||||
gem 'rodauth-oauth'
|
|
||||||
gem 'sequel'
|
|
||||||
|
|
||||||
# lib/auth_server.rb
|
|
||||||
class AuthServer < Roda
|
|
||||||
plugin :sessions, secret: ENV['SESSION_SECRET']
|
|
||||||
plugin :rodauth do
|
|
||||||
db DB
|
|
||||||
enable :login, :logout, :create_account,
|
|
||||||
:oidc, :oauth_pkce, :oauth_authorization_code_grant,
|
|
||||||
:oauth_token_revocation
|
|
||||||
|
|
||||||
oauth_application_scopes %w[openid email profile]
|
|
||||||
oauth_require_pkce true
|
|
||||||
end
|
|
||||||
|
|
||||||
route do |r|
|
|
||||||
r.rodauth # All OAuth endpoints auto-mounted!
|
|
||||||
|
|
||||||
# Your app logic here
|
|
||||||
end
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
That's it! All these endpoints are automatically available:
|
|
||||||
- GET /.well-known/openid-configuration
|
|
||||||
- GET /.well-known/jwks.json
|
|
||||||
- GET /oauth/authorize
|
|
||||||
- POST /oauth/token
|
|
||||||
- POST /oauth/revoke
|
|
||||||
- GET /oauth/userinfo
|
|
||||||
- GET /logout
|
|
||||||
|
|
||||||
### Your Current Approach
|
|
||||||
```ruby
|
|
||||||
# app/controllers/oidc_controller.rb
|
|
||||||
class OidcController < ApplicationController
|
|
||||||
def authorize
|
|
||||||
# 150 lines of validation logic
|
|
||||||
end
|
|
||||||
|
|
||||||
def token
|
|
||||||
# 100 lines of token generation logic
|
|
||||||
end
|
|
||||||
|
|
||||||
def userinfo
|
|
||||||
# 50 lines of claims logic
|
|
||||||
end
|
|
||||||
|
|
||||||
def logout
|
|
||||||
# 50 lines of logout logic
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def validate_pkce(auth_code, code_verifier)
|
|
||||||
# 50 lines of PKCE validation
|
|
||||||
end
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
## Integration Paths
|
|
||||||
|
|
||||||
### Option 1: Stick with Your Implementation
|
|
||||||
- Keep building features incrementally
|
|
||||||
- Effort: 2-3 months to reach feature parity
|
|
||||||
- Pro: Rails native, full control
|
|
||||||
- Con: Continuous maintenance burden
|
|
||||||
|
|
||||||
### Option 2: Switch to Rodauth-OAuth
|
|
||||||
- Learn Roda/Rodauth (1-2 weeks)
|
|
||||||
- Migrate database (1 week)
|
|
||||||
- Replace 450 lines of code with config (1 week)
|
|
||||||
- Testing & validation (2-3 weeks)
|
|
||||||
- Effort: 4-8 weeks total
|
|
||||||
- Pro: Production-ready, certified, maintained
|
|
||||||
- Con: Different framework (Roda)
|
|
||||||
|
|
||||||
### Option 3: Hybrid Approach
|
|
||||||
- Keep your Rails app for business logic
|
|
||||||
- Use rodauth-oauth as separate OAuth/OIDC service
|
|
||||||
- Services communicate via HTTP/APIs
|
|
||||||
- Effort: 2-3 weeks (independent services)
|
|
||||||
- Pro: Best of both worlds
|
|
||||||
- Con: Operational complexity
|
|
||||||
|
|
||||||
## Decision Matrix
|
|
||||||
|
|
||||||
### Use Rodauth-OAuth If You Need...
|
|
||||||
- [x] Standards compliance (OpenID certified)
|
|
||||||
- [x] Multiple grant types (Client Credentials, Device Code, etc.)
|
|
||||||
- [x] Token revocation/introspection
|
|
||||||
- [x] Refresh tokens
|
|
||||||
- [x] Advanced logout (front/back-channel)
|
|
||||||
- [x] Session management
|
|
||||||
- [x] Token hashing/security best practices
|
|
||||||
- [x] Hands-off maintenance
|
|
||||||
- [x] Production-battle-tested code
|
|
||||||
|
|
||||||
### Keep Your Implementation If You...
|
|
||||||
- [x] Only need Authorization Code + PKCE
|
|
||||||
- [x] Want zero Roda/external framework learning
|
|
||||||
- [x] Value Rails patterns over standards
|
|
||||||
- [x] Like to understand every line of code
|
|
||||||
- [x] Can allocate time for ongoing maintenance
|
|
||||||
- [x] Prefer minimal dependencies
|
|
||||||
|
|
||||||
## Key Differences You'll Notice
|
|
||||||
|
|
||||||
### 1. Framework Paradigm
|
|
||||||
- **Your impl**: Rails (MVC, familiar)
|
|
||||||
- **Rodauth**: Roda (routing-focused, lightweight)
|
|
||||||
|
|
||||||
### 2. Database ORM
|
|
||||||
- **Your impl**: ActiveRecord (Rails native)
|
|
||||||
- **Rodauth**: Sequel (lighter, more control)
|
|
||||||
|
|
||||||
### 3. Configuration Style
|
|
||||||
- **Your impl**: Rails initializers, environment variables
|
|
||||||
- **Rodauth**: Plugin block with DSL
|
|
||||||
|
|
||||||
### 4. Model Management
|
|
||||||
- **Your impl**: Rails models with validations, associations
|
|
||||||
- **Rodauth**: Minimal models, logic in database
|
|
||||||
|
|
||||||
### 5. Testing Approach
|
|
||||||
- **Your impl**: RSpec, model/controller tests
|
|
||||||
- **Rodauth**: Request-based integration tests
|
|
||||||
|
|
||||||
## File Locations (If You Switch)
|
|
||||||
|
|
||||||
```
|
|
||||||
Current Structure
|
|
||||||
├── app/controllers/oidc_controller.rb
|
|
||||||
├── app/models/
|
|
||||||
│ ├── oidc_authorization_code.rb
|
|
||||||
│ ├── oidc_access_token.rb
|
|
||||||
│ └── oidc_user_consent.rb
|
|
||||||
├── app/services/oidc_jwt_service.rb
|
|
||||||
├── db/migrate/*oidc*.rb
|
|
||||||
|
|
||||||
Rodauth-OAuth Equivalent
|
|
||||||
├── lib/rodauth_app.rb # Configuration (replaces most controllers)
|
|
||||||
├── app/views/rodauth/ # Templates (consent form, etc.)
|
|
||||||
├── config/routes.rb # Simple: routes mount rodauth
|
|
||||||
└── db/migrate/*rodauth_oauth*.rb
|
|
||||||
```
|
|
||||||
|
|
||||||
## Performance Considerations
|
|
||||||
|
|
||||||
### Your Implementation
|
|
||||||
- Small tables → fast queries
|
|
||||||
- Fewer columns → less overhead
|
|
||||||
- Simple token validation
|
|
||||||
- Estimated: 5-10ms per token validation
|
|
||||||
|
|
||||||
### Rodauth-OAuth
|
|
||||||
- More columns, but same queries
|
|
||||||
- Optional token hashing (slight overhead)
|
|
||||||
- More features = more options checked
|
|
||||||
- Estimated: 10-20ms per token validation
|
|
||||||
- Can be optimized: disable unused features
|
|
||||||
|
|
||||||
## Getting Started (If You Want to Explore)
|
|
||||||
|
|
||||||
1. **Review the code**
|
|
||||||
```bash
|
|
||||||
cd /Users/dkam/Development/clinch/tmp/rodauth-oauth
|
|
||||||
ls -la lib/rodauth/features/ # See all features
|
|
||||||
cat examples/oidc/authentication_server.rb # Full working example
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Run the example**
|
|
||||||
```bash
|
|
||||||
cd /Users/dkam/Development/clinch/tmp/rodauth-oauth/examples
|
|
||||||
ruby oidc/authentication_server.rb # Starts server on http://localhost:9292
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Read the key files**
|
|
||||||
- README.md: Overview
|
|
||||||
- MIGRATION-GUIDE-v1.md: Version migration (shows architecture)
|
|
||||||
- test/migrate/*.rb: Database schema
|
|
||||||
- examples/oidc/*.rb: Complete working implementation
|
|
||||||
|
|
||||||
## Next Steps
|
|
||||||
|
|
||||||
1. **If keeping your implementation:**
|
|
||||||
- Prioritize refresh token support
|
|
||||||
- Add token revocation endpoint
|
|
||||||
- Consider token hashing
|
|
||||||
|
|
||||||
2. **If exploring rodauth-oauth:**
|
|
||||||
- Run the example server
|
|
||||||
- Review the feature files
|
|
||||||
- Check if hybrid approach works for your org
|
|
||||||
|
|
||||||
3. **For either path:**
|
|
||||||
- Document your decision
|
|
||||||
- Plan feature roadmap
|
|
||||||
- Set up appropriate monitoring
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Bottom Line**: Rodauth-OAuth is the "production-grade" option if you need comprehensive OAuth/OIDC. Your implementation is fine if you keep features minimal and have maintenance bandwidth.
|
|
||||||
Reference in New Issue
Block a user