Dosu LogoDosu Logo
Ask
Join our Discord
SurePublic
we-promise
DocumentsSure
API Authentication and Authorization
API Authentication and Authorization
Type
Topic
Status
Published
Created
Jul 19, 2026
Updated
Jul 19, 2026

API Authentication and Authorization#

Sure's programmatic API (/api/v1) supports two authentication methods: OAuth 2.0 Bearer tokens and API keys. Both are handled by Api::V1::BaseController, which skips session-based auth and CSRF, then runs authenticate_request!, check_api_key_rate_limit, and log_api_access as before_actions on every request.


Authentication Flow#

authenticate_request! tries each method in order; the first success sets @current_user and @authentication_method, then calls setup_current_context_for_api to attach a fresh, unsaved Session to Current.session — ensuring API requests never inherit web session state or impersonation context .

Request
  └─ authenticate_oauth (Authorization: Bearer <token>)
       └─ on failure → authenticate_api_key (X-Api-Key: <key>)
                         └─ on failure → 401 Unauthorized

OAuth 2.0 (Doorkeeper)#

  • Header: Authorization: Bearer <token>
  • authenticate_oauth looks up the token via Doorkeeper::AccessToken.by_token, then verifies accessible? and that the token carries at least read or read_write scope.
  • Doorkeeper is configured with 1-year token expiration , PKCE enforcement for non-confidential clients , refresh tokens , and SHA256 secret hashing in production .
  • OAuth discovery endpoints are exposed at /.well-known/oauth-protected-resource and /.well-known/oauth-authorization-server; dynamic client registration is available at POST /register.

API Keys#

  • Header: X-Api-Key: <key>
  • authenticate_api_key calls ApiKey.find_by_value, which looks up the key using deterministic AES encryption — enabling indexed lookups without storing plaintext.
  • Keys track last_used_at (updated on each request via update_last_used!) and support optional expiration (expires_at) and revocation (revoke!) .
  • Rate limiting is initialized here: @rate_limiter = ApiRateLimiter.limit(@api_key) .

Scope Model#

Both authentication methods use the same two-scope model, enforced by authorize_scope!:

ScopeAccess
readRead-only endpoints
read_writeRead + write; implicitly includes read access

read is the Doorkeeper default scope . Write endpoints call authorize_scope!(:write), which requires read_write; attempting a write with only read returns 403 Forbidden with "insufficient_scope".

current_scopes abstracts over both auth methods — returning doorkeeper_token.scopes for OAuth or @api_key.scopes for API keys — so authorize_scope! is auth-method-agnostic.


Rate Limiting (API Keys Only)#

Rate limiting applies only to API key authentication; OAuth tokens are not rate-limited .

check_api_key_rate_limit runs after authentication. It uses a Redis-backed sliding hourly window :

TierRequests / Hour
standard (default)100
premium1,000
enterprise10,000

Rate limit status is surfaced in response headers on every API key request :

  • X-RateLimit-Limit — the tier ceiling
  • X-RateLimit-Remaining — requests left in the current window
  • X-RateLimit-Reset — seconds until the window resets
  • Retry-After — also set on 429 Too Many Requests responses

Self-hosted deployments use NoopApiRateLimiter, which always returns false for rate_limit_exceeded? and Float::INFINITY for the limit , effectively disabling rate limiting.


Key Files#

FileRole
app/controllers/api/v1/base_controller.rbAuth dispatch, scope enforcement, rate limit hooks, error handlers
app/models/api_key.rbKey encryption, scopes, expiry, revocation
app/services/api_rate_limiter.rbRedis-backed rate limiting with tier support
config/initializers/doorkeeper.rbOAuth server config: PKCE, token TTL, SHA256 hashing, scopes
Documents
Account Authorization and Permissions
Account Balance Calculation
Account Creation
Account Lifecycle Management
Account Provider Architecture
Account Reporting Controls
Account Statement Management
Account Statement Reconciliation
Account Type Architecture
AI Bank Statement Extraction
AI Chat Interface
API Authentication and Authorization
Authentication and Session Management
Balance History System
Banking Data Encryption
Banking Provider Integration
Broker Activity Import
Budget Management
Category Management
Cryptocurrency Account Management
CSV Import and Column Mapping
Currency Management
Dashboard Filtering and Drilldowns
Depository Yield Modeling
Dev Container Setup
Dividend and DRIP Modeling
Docker Self-Hosting
Enable Banking Consent Management
Enable Banking Error Handling
Enable Banking OAuth and PSD2 Authentication
Family Data Export
Family Settings Management
Financial Insights and Metrics
Financial Reporting
FIRE Planning and Retirement Calculations
Goals and Savings Tracking
Internationalization and Localization
Investment Account Data Pipeline
Investment Account Flow Semantics
Investment Account Reconciliation
Investment Activity Labels
Investment Holdings Management
Investment Tax Treatment Classification
Investment Trade Conversion
Investment Trade Entry
Invitation Lifecycle and State Management
Ledger Entry Accounting Model
LLM Provider Configuration
LLM Request Timeout and Watchdog System
LLM Tool Calling
Manual Account Entry and Import
Manual Valuation
MCP Tool Access
Multi-Currency Exchange Rates
NDJSON Import System
Net Worth Balance Sheet
OIDC Provider Configuration
Pending Transaction Reconciliation
Plaid Integration
Provider Import Adapter
Rails Development Environment Configuration
Rails PWA Integration
Recurring Transactions and Cash Flow Projection
REST API Architecture
Securities Lookup
Security Exchange Identification
Security Price Import Pipeline
SimpleFIN Holdings Import
SimpleFIN Integration
SimpleFIN Liability Balance Normalization
SnapTrade Integration
Split Transactions
SSO Audit Logging
SSO Authentication Flow
SSO Provider Management
Timezone-Aware Financial Data Handling
Transaction Categorization
Transaction Deduplication
Transaction Exclusion
Transaction Filtering and Search
Transaction Management
Transaction Rule Engine
Transaction Sync Windows and Lookback
Transfer Management
Transfer Matching and Pairing
Turbo Frame Navigation
Yahoo Finance Integration
How split transaction child exclusion was implemented
Is it possible to edit the date of a synced transaction (e.g., one synced by LunchFlow)?
Provider Architecture