|
| 1 | +--- |
| 2 | +title: Authorize Intent for HTTP Payment Authentication |
| 3 | +abbrev: Payment Intent Authorize |
| 4 | +docname: draft-payment-intent-authorize-00 |
| 5 | +version: 00 |
| 6 | +category: info |
| 7 | +ipr: trust200902 |
| 8 | +submissiontype: IETF |
| 9 | +consensus: true |
| 10 | + |
| 11 | +author: |
| 12 | + - name: Jake Moxey |
| 13 | + ins: J. Moxey |
| 14 | + email: jake@tempo.xyz |
| 15 | + org: Tempo Labs |
| 16 | + - name: Brendan Ryan |
| 17 | + ins: B. Ryan |
| 18 | + email: brendan@tempo.xyz |
| 19 | + org: Tempo Labs |
| 20 | + - name: Tom Meagher |
| 21 | + ins: T. Meagher |
| 22 | + email: thomas@tempo.xyz |
| 23 | + org: Tempo Labs |
| 24 | + |
| 25 | +normative: |
| 26 | + RFC2119: |
| 27 | + RFC8174: |
| 28 | + I-D.httpauth-payment: |
| 29 | + title: "The 'Payment' HTTP Authentication Scheme" |
| 30 | + target: https://datatracker.ietf.org/doc/draft-httpauth-payment/ |
| 31 | + author: |
| 32 | + - name: Jake Moxey |
| 33 | + date: 2026-01 |
| 34 | +--- |
| 35 | + |
| 36 | +--- abstract |
| 37 | + |
| 38 | +This document defines the "authorize" payment intent for use with the |
| 39 | +Payment HTTP Authentication Scheme {{I-D.httpauth-payment}}. The "authorize" |
| 40 | +intent represents a pre-authorization where the payer grants the server |
| 41 | +permission to charge up to a specified amount within a time window, |
| 42 | +without immediate payment. |
| 43 | + |
| 44 | +--- middle |
| 45 | + |
| 46 | +# Introduction |
| 47 | + |
| 48 | +The "authorize" intent enables pre-authorized payments where the payer |
| 49 | +grants the server permission to charge up to a specified amount at a |
| 50 | +later time. This is useful for: |
| 51 | + |
| 52 | +- **Metered billing**: Pay-per-use APIs where total cost is unknown upfront |
| 53 | +- **Delayed fulfillment**: Services where delivery occurs after authorization |
| 54 | +- **Spending caps**: User-controlled limits on automated spending |
| 55 | + |
| 56 | +Unlike the "charge" intent which requires immediate payment, "authorize" |
| 57 | +creates a payment capability that the server can exercise later. |
| 58 | + |
| 59 | +## Relationship to Payment Methods |
| 60 | + |
| 61 | +Payment methods implement "authorize" using their native authorization |
| 62 | +mechanisms: |
| 63 | + |
| 64 | +| Method | Implementation | |
| 65 | +|--------|----------------| |
| 66 | +| Tempo | Access Keys with spending limits | |
| 67 | +| Stripe | SetupIntent + saved PaymentMethod | |
| 68 | +| EVM | ERC-20 `approve()` or EIP-3009 authorization | |
| 69 | + |
| 70 | +# Requirements Language |
| 71 | + |
| 72 | +{::boilerplate bcp14-tagged} |
| 73 | + |
| 74 | +# Terminology |
| 75 | + |
| 76 | +Authorization |
| 77 | +: A grant of permission for a server to initiate payments up to a |
| 78 | + specified limit within a specified time window, without requiring |
| 79 | + immediate payment. |
| 80 | + |
| 81 | +Spending Limit |
| 82 | +: The maximum amount that can be charged against an authorization |
| 83 | + before it is exhausted. |
| 84 | + |
| 85 | +Revocation |
| 86 | +: The act of canceling an authorization before its natural expiry, |
| 87 | + preventing further charges. |
| 88 | + |
| 89 | +# Intent Semantics |
| 90 | + |
| 91 | +## Definition |
| 92 | + |
| 93 | +The "authorize" intent represents a request for the payer to grant |
| 94 | +permission for the server to initiate payments up to a specified limit, |
| 95 | +within a specified time window. |
| 96 | + |
| 97 | +## Properties |
| 98 | + |
| 99 | +| Property | Value | |
| 100 | +|----------|-------| |
| 101 | +| **Intent Identifier** | `authorize` | |
| 102 | +| **Payment Timing** | Deferred (server-initiated later) | |
| 103 | +| **Idempotency** | Reusable within limits | |
| 104 | +| **Reversibility** | Revocable before use | |
| 105 | + |
| 106 | +## Flow |
| 107 | + |
| 108 | +~~~ |
| 109 | + Client Server Payment Network |
| 110 | + │ │ │ |
| 111 | + │ (1) GET /resource │ │ |
| 112 | + ├───────────────────────────────>│ │ |
| 113 | + │ │ │ |
| 114 | + │ (2) 402 Payment Required │ │ |
| 115 | + │ intent="authorize" │ │ |
| 116 | + │<───────────────────────────────┤ │ |
| 117 | + │ │ │ |
| 118 | + │ (3) Sign authorization │ │ |
| 119 | + │ │ │ |
| 120 | + │ (4) Authorization: Payment │ │ |
| 121 | + ├───────────────────────────────>│ │ |
| 122 | + │ │ │ |
| 123 | + │ │ (5) Register authorization │ |
| 124 | + │ ├─────────────────────────────>│ |
| 125 | + │ │ │ |
| 126 | + │ (6) 200 OK (authorized) │ │ |
| 127 | + │<───────────────────────────────┤ │ |
| 128 | + │ │ │ |
| 129 | + │ ... later ... │ │ |
| 130 | + │ │ │ |
| 131 | + │ (7) GET /resource │ │ |
| 132 | + ├───────────────────────────────>│ │ |
| 133 | + │ │ (8) Charge via auth │ |
| 134 | + │ ├─────────────────────────────>│ |
| 135 | + │ │ │ |
| 136 | + │ (9) 200 OK + Receipt │ │ |
| 137 | + │<───────────────────────────────┤ │ |
| 138 | + │ │ │ |
| 139 | +~~~ |
| 140 | + |
| 141 | +## Non-Atomicity |
| 142 | + |
| 143 | +Unlike "charge", the "authorize" intent is non-atomic: |
| 144 | + |
| 145 | +- Authorization registration is separate from payment collection |
| 146 | +- Multiple charges may occur against a single authorization |
| 147 | +- Total charges MUST NOT exceed the authorized limit |
| 148 | + |
| 149 | +# Request Schema |
| 150 | + |
| 151 | +The `request` parameter for an "authorize" intent is a JSON object with |
| 152 | +shared fields defined by this specification and optional method-specific |
| 153 | +extensions in the `methodDetails` field. |
| 154 | + |
| 155 | +## Shared Fields |
| 156 | + |
| 157 | +All payment methods implementing the "authorize" intent MUST support these |
| 158 | +shared fields, enabling clients to parse and display authorization requests |
| 159 | +consistently across methods. |
| 160 | + |
| 161 | +### Required Fields |
| 162 | + |
| 163 | +| Field | Type | Description | |
| 164 | +|-------|------|-------------| |
| 165 | +| `amount` | string | Maximum authorization amount in base units | |
| 166 | +| `currency` | string | Currency or asset identifier (see {{currency-formats}}) | |
| 167 | +| `expires` | string | Authorization expiry timestamp in ISO 8601 format | |
| 168 | + |
| 169 | +### Optional Fields |
| 170 | + |
| 171 | +| Field | Type | Description | |
| 172 | +|-------|------|-------------| |
| 173 | +| `recipient` | string | Payment recipient in method-native format | |
| 174 | +| `description` | string | Human-readable authorization description | |
| 175 | +| `externalId` | string | Merchant's reference (order ID, etc.) | |
| 176 | +| `methodDetails` | object | Method-specific extension data | |
| 177 | + |
| 178 | +## Currency Formats {#currency-formats} |
| 179 | + |
| 180 | +The `currency` field supports multiple formats to accommodate different |
| 181 | +payment networks: |
| 182 | + |
| 183 | +| Format | Example | Description | |
| 184 | +|--------|---------|-------------| |
| 185 | +| ISO 4217 | `"usd"`, `"eur"` | Fiat currencies (lowercase) | |
| 186 | +| Token address | `"0x20c0..."` | ERC-20, TIP-20, or similar token contracts | |
| 187 | +| Well-known symbol | `"sat"`, `"btc"`, `"eth"` | Native blockchain assets | |
| 188 | + |
| 189 | +Clients can detect the format: |
| 190 | + |
| 191 | +- Starts with `0x`: Token contract address |
| 192 | +- Three lowercase letters: ISO 4217 currency code |
| 193 | +- Otherwise: Well-known symbol or method-specific identifier |
| 194 | + |
| 195 | +## Method Extensions |
| 196 | + |
| 197 | +Payment methods MAY define additional fields in the `methodDetails` object. |
| 198 | +These fields are method-specific and MUST be documented in the payment |
| 199 | +method specification. |
| 200 | + |
| 201 | +## Examples |
| 202 | + |
| 203 | +### Traditional Payment Processor (Stripe) |
| 204 | + |
| 205 | +~~~ json |
| 206 | +{ |
| 207 | + "amount": "100000", |
| 208 | + "currency": "usd", |
| 209 | + "expires": "2025-01-22T12:00:00Z", |
| 210 | + "description": "Pre-authorization for metered API usage", |
| 211 | + "methodDetails": { |
| 212 | + "captureMethod": "manual" |
| 213 | + } |
| 214 | +} |
| 215 | +~~~ |
| 216 | + |
| 217 | +### Blockchain Payment (Tempo) |
| 218 | + |
| 219 | +~~~ json |
| 220 | +{ |
| 221 | + "amount": "50000000", |
| 222 | + "currency": "0x20c0000000000000000000000000000000000001", |
| 223 | + "expires": "2025-02-05T12:00:00Z", |
| 224 | + "methodDetails": { |
| 225 | + "chainId": 42431 |
| 226 | + } |
| 227 | +} |
| 228 | +~~~ |
| 229 | + |
| 230 | +# Credential Requirements |
| 231 | + |
| 232 | +## Payload |
| 233 | + |
| 234 | +The credential `payload` for an "authorize" intent contains the |
| 235 | +authorization grant. The format is method-specific: |
| 236 | + |
| 237 | +| Authorization Type | Description | Example Methods | |
| 238 | +|-------------------|-------------|-----------------| |
| 239 | +| Signed Key Auth | Delegated signing key | Tempo Access Keys | |
| 240 | +| Token Approval | On-chain approval | EVM ERC-20 approve | |
| 241 | +| Saved Payment Method | Stored card/account | Stripe SetupIntent | |
| 242 | + |
| 243 | +## Reusability |
| 244 | + |
| 245 | +Unlike "charge" credentials, "authorize" credentials may enable multiple |
| 246 | +subsequent charges. The authorization persists until: |
| 247 | + |
| 248 | +- The expiry timestamp is reached |
| 249 | +- The spending limit is exhausted |
| 250 | +- The payer explicitly revokes it |
| 251 | + |
| 252 | +# Authorization Lifecycle |
| 253 | + |
| 254 | +## Registration |
| 255 | + |
| 256 | +When the server receives an "authorize" credential: |
| 257 | + |
| 258 | +1. Verify the authorization signature/proof |
| 259 | +2. Store the authorization for future use |
| 260 | +3. Return success (200) to indicate authorization accepted |
| 261 | +4. Optionally return `Payment-Authorization` for session reuse |
| 262 | + |
| 263 | +## Charging |
| 264 | + |
| 265 | +When charging against an authorization: |
| 266 | + |
| 267 | +1. Verify the authorization is still valid (not expired, not revoked) |
| 268 | +2. Verify sufficient limit remains |
| 269 | +3. Execute the charge via method-specific mechanism |
| 270 | +4. Decrement the remaining limit |
| 271 | +5. Return `Payment-Receipt` with charge details |
| 272 | + |
| 273 | +## Revocation |
| 274 | + |
| 275 | +Payers SHOULD be able to revoke authorizations before expiry. Revocation |
| 276 | +mechanisms are method-specific: |
| 277 | + |
| 278 | +| Method | Revocation Mechanism | |
| 279 | +|--------|---------------------| |
| 280 | +| Tempo | Remove Access Key from account | |
| 281 | +| EVM | Set approval to zero | |
| 282 | +| Stripe | Detach PaymentMethod from Customer | |
| 283 | + |
| 284 | +## Expiry |
| 285 | + |
| 286 | +Servers MUST NOT charge against expired authorizations. Servers SHOULD |
| 287 | +provide a mechanism for payers to query authorization status. |
| 288 | + |
| 289 | +# Security Considerations |
| 290 | + |
| 291 | +## Limit Verification |
| 292 | + |
| 293 | +Clients MUST verify the requested limit is acceptable before signing. |
| 294 | +Authorizations grant future spending capability without further user |
| 295 | +interaction. |
| 296 | + |
| 297 | +## Expiry Windows |
| 298 | + |
| 299 | +Clients SHOULD prefer short authorization windows. Long-lived |
| 300 | +authorizations increase risk if credentials are compromised. |
| 301 | + |
| 302 | +Recommended maximum windows: |
| 303 | + |
| 304 | +| Use Case | Recommended Max | |
| 305 | +|----------|-----------------| |
| 306 | +| Single session | 1 hour | |
| 307 | +| Daily usage | 24 hours | |
| 308 | +| Monthly billing | 30 days | |
| 309 | + |
| 310 | +## Revocation Capability |
| 311 | + |
| 312 | +Payment methods implementing "authorize" SHOULD provide revocation |
| 313 | +mechanisms. Payers MUST be able to revoke authorizations if they suspect |
| 314 | +compromise. |
| 315 | + |
| 316 | +## Authorization Scope |
| 317 | + |
| 318 | +Authorizations SHOULD be scoped as narrowly as possible: |
| 319 | + |
| 320 | +- Specific recipient address (not "any address") |
| 321 | +- Specific asset/currency |
| 322 | +- Reasonable limits and expiry |
| 323 | + |
| 324 | +## Server Accountability |
| 325 | + |
| 326 | +Servers holding authorizations are responsible for: |
| 327 | + |
| 328 | +- Secure storage of authorization data |
| 329 | +- Not exceeding authorized limits |
| 330 | +- Providing transaction records to payers |
| 331 | +- Honoring revocation requests |
| 332 | + |
| 333 | +# IANA Considerations |
| 334 | + |
| 335 | +## Payment Intent Registration |
| 336 | + |
| 337 | +This document registers the "authorize" intent in the "HTTP Payment |
| 338 | +Intents" registry established by {{I-D.httpauth-payment}}: |
| 339 | + |
| 340 | +| Intent | Description | Reference | |
| 341 | +|--------|-------------|-----------| |
| 342 | +| `authorize` | Pre-authorization for future charges | This document | |
0 commit comments