From 0bb0927c835a1c9c0c066aeb0de25e48b8a50eb5 Mon Sep 17 00:00:00 2001
From: Melissa Henderson <57110301+melissahenderson@users.noreply.github.com>
Date: Mon, 18 Nov 2024 12:11:01 -0500
Subject: [PATCH 1/5] docs: accts, idp, and disclosure component
Updated the accounting concepts page. Formatted the examples to be a bit easier to scan through. I'm working on revised examples outside of this PR. Also made some updates to the IDP doc and removed the use of the Disclosure component from the Webhook Events page and README. We are no longer using the component.
---
packages/documentation/README.md | 5 +-
.../docs/integration/requirements/idp.mdx | 158 +++-----
.../requirements/webhook-events.mdx | 124 +++---
.../docs/overview/concepts/accounting.mdx | 364 ++++++++++++------
4 files changed, 357 insertions(+), 294 deletions(-)
diff --git a/packages/documentation/README.md b/packages/documentation/README.md
index 824def64ee..2601440e1c 100644
--- a/packages/documentation/README.md
+++ b/packages/documentation/README.md
@@ -61,7 +61,6 @@ Refer to the Starlight documentation on [authoring content](https://starlight.as
We have extracted some commonly repeated patterns within the documentation pages into custom docs components that can be reused. There are components which are shared across all our Starlight documentation sites and those which are specific to this project only. This will determine what the import path is.
- CodeBlock (Shared)
-- Disclosure (Shared)
- Hidden (Shared)
- LargeImg (Shared)
- LinkOut (Shared)
@@ -69,10 +68,10 @@ We have extracted some commonly repeated patterns within the documentation pages
- StylishHeader (Shared)
- Tooltip (Shared)
-For the shared components, if you are using both `CodeBlock` and `Disclosure` on the same page, you can import them both like so:
+For the shared components, if you are using both `CodeBlock` and `LinkOut` on the same page, you can import them both like so:
```jsx
-import { CodeBlock, Disclosure } from '@interledger/docs-design-system'
+import { CodeBlock, LinkOut } from '@interledger/docs-design-system'
```
For more information about importing things in Javascript, please refer to [import on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import).
diff --git a/packages/documentation/src/content/docs/integration/requirements/idp.mdx b/packages/documentation/src/content/docs/integration/requirements/idp.mdx
index 4c839264d7..8939d05ba1 100644
--- a/packages/documentation/src/content/docs/integration/requirements/idp.mdx
+++ b/packages/documentation/src/content/docs/integration/requirements/idp.mdx
@@ -12,98 +12,80 @@ import {
An identity provider (IdP) is a system or service that stores and manages user identity information, authentication, and consent. Examples of IdPs include OpenID Connect and Okta.
-Integration with an IdP is required if you plan to support outgoing payments via Open Payments. The Open Payments standard requires interactive outgoing payment _grant_ requests, which precede outgoing payment requests. In an interactive grant request, explicit interaction by an individual (e.g., the client's end-user) is required to approve the grant. An example of an interaction is an end-user tapping _Approve_ in an app to authorize a payment.
+Open Payments requires any authorization server that issues interactive grants be integrated with an IdP. Interactive grants are used to gather consent, and are required for Open Payments outgoing payments. Interactive grants are optional for incoming payments and quotes.
-Your IdP will:
-
-- Authenticate requests from clients, such as mobile apps, to create quotes and payments on Rafiki's backend
-- Facilitate interactions with the client's end-user to gather consent
+Responsibilities of your IdP include:
+- Providing an interface to gather consent
+- Sending the interaction choice (approve or deny) to your authorization server
+- Sending a request to your authorization server to finish the interaction
+- Redirecting the user after the interaction is complete
+- Authenticating requests from clients to create payments on Rafiki's backend
:::note
-We provide Ory Kratos, a cloud-based user management system, for the identity and user management of your [Rafiki Admin](/admin/admin-user-guide) users. Kratos is for internal use only and **cannot** be used as your client-facing IdP.
+We provide Ory Kratos, a cloud-based user management system, for the identity and user management of your Rafiki Admin users. Kratos is for internal use only and **cannot** be used as your IdP for Open Payments.
:::
-### Interactions and consent
-
-Before an outgoing payment is created via Open Payments, an outgoing payment _grant_ must be issued.
-
-Outgoing payment grant requests must be interactive. This means the request requires explicit interaction, often from the a client's end-user, to gather consent (permission) before creating the outgoing payment. The interaction is facilitated by your IdP.
-
-Your IdP:
+## Interactive grants
-
+In Open Payments, grants are used to indicate a resource owner, such as an account holder, has given a piece of software, such as a mobile app, permission (consent) to act on their behalf.
-1. Provides an interface to gather consent (for example, a consent screen)
-2. Sends the interaction choice (accept/deny) to your authorization server
-3. Sends a request to your authorization server to finish the interaction
-4. Redirects the user after the interaction is complete
+Open Payments requires that consent be collected via an interactive grant before an outgoing payment request is issued. A grant is interactive when explicit interaction by an entity (e.g., the software's end user) is required to approve or deny the grant. Tapping an *Approve* button to authorize a payment is an example of an explicit interaction.
-
+See the Open Payments documentation for more information on grant negotiation and authorization.
-### Authorization server
+## Authorization servers
-The purpose of an Open Payments authorization server is to grant permission to clients to access the Open Payments APIs. These APIs are used to create incoming payments, quotes, and outgoing payments against an account holder's account.
+Authorization servers grant permission to clients to access the Open Payments APIs. This enables clients to create incoming payments, quotes, and outgoing payments against an account holder's account.
-Rafiki's [auth service](/integration/services/auth-service) provides you with a reference implementation of an Open Payments authorization server. You can use the service as an alternative to developing your own in-house service.
+Rafiki's [auth service](/integration/services/auth-service) provides you with a reference implementation of an Open Payments authorization server. You can use the service as an alternative to developing your own in-house solution. Additionally, the server extends an [API](#interaction-endpoints) that provides interaction endpoints for your IdP.
-The authorization server extends an HTTP API for your IdP to use to start and finish interactions, collect authorization, get information about a grant, and communicate whether an end-user has authorized a grant. The API's [endpoints](#interaction-endpoints) are described below.
-
-## Environment variables
+### Environment variables
The following `backend` variables must be configured on your authorization server.
-| Variable | Helm value name | Default | Description | Required |
-| ------------------------------ | ---------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
-| `IDENTITY_SERVER_URL` | `auth.identityServer.domain` | N/A | Your IdP server's URL where your authorization server will direct clients to so end-users can complete the interaction and authorize a grant. | Y |
-| `IDENTITY_SERVER_SECRET` | `auth.identityServer.secret` | N/A | A shared secret between your authorization and IdP servers that your authorization server will use to secure its IdP-related endpoints.
When your IdP sends requests to your authorization server, your IdP must provide the secret via an [`x-idp-secret`](#x-idp-secret-header) header. | Y |
-| `INCOMING_PAYMENT_INTERACTION` | `auth.interaction.incomingPayment` | `false` | Indicates whether incoming payments grant requests are interactive. | Y |
-| `INTERACTION_EXPIRY_SECONDS` | `auth.interactionExpirySeconds` | `600` | The time in seconds for which a user can interact with a grant request | Y |
-| `INTERACTION_PORT` | `auth.port.interaction` | `3009` | The port number for the [interaction endpoints](#interaction-endpoints) | Y |
-| `INTROSPECTION_PORT` | `auth.port.introspection` | `3007` | The port number of your Open Payments authorization token introspection server | Y |
-| `LIST_ALL_ACCESS_INTERACTION` | N/A | `true` | Specifies whether grant requests including a `list-all` action should require interaction. In these requests, the client asks to list resources that they themselves did not create. | Y |
+| Variable | Helm value name | Default | Description |
+| -------- | --------------- | ------- | ----------- |
+| `IDENTITY_SERVER_URL` | `auth.identityServer.domain` | N/A | Your IdP server's URL where your authorization server will direct clients to so end-users can complete the interaction and authorize a grant. | Y |
+| `IDENTITY_SERVER_SECRET` | `auth.identityServer.secret` | N/A | A shared secret between your authorization and IdP servers that your authorization server will use to secure its IdP-related endpoints.
When your IdP sends requests to your authorization server, your IdP must provide the secret via an [`x-idp-secret`](#x-idp-secret-header) header. | Y |
+| `INCOMING_PAYMENT_INTERACTION` | `auth.interaction.incomingPayment` | `false` | Indicates whether incoming payments grant requests are interactive. | Y |
+| `INTERACTION_EXPIRY_SECONDS` | `auth.interactionExpirySeconds` | `600` | The time in seconds for which a user can interact with a grant request | Y |
+| `INTERACTION_PORT` | `auth.port.interaction` | `3009` | The port number for the [interaction endpoints](#interaction-endpoints) | Y |
+| `INTROSPECTION_PORT` | `auth.port.introspection` | `3007` | The port number of your Open Payments authorization token introspection server | Y |
+| `LIST_ALL_ACCESS_INTERACTION` | N/A | `true` | Specifies whether grant requests including a `list-all` action should require interaction. In these requests, the client asks to list resources that they themselves did not create. | Y |
-## Manage grants
-
-After a pending grant request is created, your IdP server can use the interaction endpoints listed below to:
-
-- Start and finish interactions
-- Collect authorization
-- Get information about a grant
-- Communicate whether an end-user has authorized a grant
+## Interaction endpoints
-Each interaction is identified by an `id` and a `nonce`. Both are provided as query parameters when your authorization server redirects to your IdP server.
+The authorization server provided by Rafiki's `auth` service extends an API for your IdP server to use after a pending grant request is created.
-The endpoints are appended to the `IDENTITY_SERVER_URL` you defined when configuring your [environment variables](#environment-variables).
+Each interaction with an endpoint is identified by an `id` and a `nonce`. Both are provided as query parameters when your authorization server redirects to your IdP's server.
-
-| Method | Endpoint | Purpose |
-| ---------------------------------------------------- | ------------------------------- | ----------------------------------------------------------------- |
-| | `/interact/{id}/{nonce}` | [Start user interaction session](#start-user-interaction-session) |
-| | `/grant/{id}/{nonce}` | [Look up grant information](#look-up-grant-information) |
-| | `/grant/{id}/{nonce}/{choice}` | [Accept or reject grant](#accept-or-reject-grant) |
-| | `/interact/{id}/{nonce}/finish` | [Finish user interaction](#finish-interaction)
|
-| | `/interact/{id}/{nonce}` | [Continue grant](#continue-grant) |
+| Method | Endpoint | Purpose |
+| ------ | -------- | ------- |
+| | `/interact/{id}/{nonce}` | [Start user interaction session](#start-user-interaction-session) |
+| | `/grant/{id}/{nonce}` | [Look up grant information](#look-up-grant-information) |
+| | `/grant/{id}/{nonce}/{choice}` | [Accept or reject grant](#accept-or-reject-grant) |
+| | `/interact/{id}/{nonce}/finish` | [Finish user interaction](#finish-interaction) |
+| | `/interact/{id}/{nonce}` | [Continue grant](#continue-grant) |
-We also provide an
-| Variable | Type | Description |
-| ------------------- | --------- | --------------------------------------------------------------------------------------------------------------- |
-| `WEBHOOK_TIMEOUT` | `backend` | The amount of time, in milliseconds, after which a webhook request will time out |
+| Variable | Type | Description |
+| -------- | ---- | ----------- |
+| `WEBHOOK_TIMEOUT` | `backend` | The amount of time, in milliseconds, after which a webhook request will time out |
| `WEBHOOK_MAX_RETRY` | `backend` | The maximum number of retries for a webhook event when a non-200 status is returned or if the request timed out |
@@ -166,17 +166,18 @@ The first retry is after 10 seconds. Additional retries occur after 20 more seco
-| Event type | Description |
-| ----------------------------------------------------------- | --------------------------------------------------------------------------------- |
-| [`incoming_payment.created`](#incoming-payment-created) | An incoming payment has been created |
+| Event type | Description |
+| ---------- | ----------- |
+| [`incoming_payment.created`](#incoming-payment-created) | An incoming payment has been created |
| [`incoming_payment.completed`](#incoming-payment-completed) | An incoming payment is complete and will not accept any additional incoming funds |
-| [`incoming_payment.expired`](#incoming-payment-expired) | An incoming payment expired and will not accept any additional incoming funds |
+| [`incoming_payment.expired`](#incoming-payment-expired) | An incoming payment expired and will not accept any additional incoming funds |
#### Incoming payment created
-
-| Event type | Description |
-| ----------------------------------------------------------- | -------------------------------------------------- |
-| [`outgoing_payment.created`](#outgoing-payment-created) | An outgoing payment has been created |
-| [`outgoing_payment.completed`](#outgoing-payment-completed) | An outgoing payment has completed |
-| [`outgoing_payment.failed`](#outgoing-payment-failed) | An outgoing payment partially or completely failed |
+| Event type | Description |
+| ---------- | ----------- |
+| [`outgoing_payment.created`](#outgoing-payment-created) | An outgoing payment has been created |
+| [`outgoing_payment.completed`](#outgoing-payment-completed) | An outgoing payment has completed |
+| [`outgoing_payment.failed`](#outgoing-payment-failed) | An outgoing payment partially or completely failed |
#### Outgoing payment created
-
-| Event type | Description |
-| --------------------------------------------------------------------- | ------------------------------------------------------------------ |
-| [`wallet_address.not_found`](#wallet-address-not-found) | The requested wallet address was not found on this Rafiki instance |
-| [`wallet_address.web_monetization`](#wallet-address-web-monetization) | Web Monetization payments have been received via STREAM |
+| Event type | Description |
+| ---------- | ----------- |
+| [`wallet_address.not_found`](#wallet-address-not-found) | The requested wallet address was not found on this Rafiki instance |
+| [`wallet_address.web_monetization`](#wallet-address-web-monetization) | Web Monetization payments have been received via STREAM |
#### Wallet address not found
-
-| Environment variable | Type | Description |
+| Environment variable | Type | Description |
| ---------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------- |
| `WALLET_ADDRESS_LOOKUP_TIMEOUT_MS` | `backend` | The time in milliseconds that you have to create a missing wallet address before the initial request times out |
@@ -415,8 +410,8 @@ When you receive this event, look up the associated account in your system and c
#### Wallet address Web Monetization
-
-
+
+Expand for event sequence
A wallet address received a Web Monetization payment of \$0.33
-
-
+
The `wallet_address.web_monetization` event indicates that a wallet address received Web Monetization payments via the ILP STREAM protocol. Withdraw the liquidity from the wallet address in Rafiki and credit the recipient's account on your ledger.
@@ -439,16 +433,16 @@ The `wallet_address.web_monetization` event indicates that a wallet address rece
-| Event type | Description |
-| --------------------------------------------- | ------------------------------------------------------------- |
+| Event type | Description |
+| ---------- | ----------- |
| [`asset.liquidity_low`](#asset-liquidity-low) | Your asset liquidity has dropped below your defined threshold |
#### Asset liquidity low
-
-
+
+Expand for event sequence
Your asset liquidity for USD (asset scale: 2) drops below \$100.00.
-
-
+
The `asset.liquidity_low` event indicates that an asset's liquidity has dropped below your predefined liquidity threshold. Check if you already have, or can acquire, additional liquidity for that specific asset. If so, deposit it in Rafiki. Cross-currency transfers will fail if you don't increase the asset's liquidity.
@@ -470,16 +463,16 @@ The `asset.liquidity_low` event indicates that an asset's liquidity has dropped
-| Event type | Description |
-| ------------------------------------------- | ------------------------------------------------------------ |
+| Event type | Description |
+| ---------- | ----------- |
| [`peer.liquidity_low`](#peer-liquidity-low) | Your peer liquidity has dropped below your defined threshold |
#### Peer liquidity low
-
-
+
+Expand for event sequence
The liquidity for your peer, Happy Life Bank, drops below \$100.00 USD.
+
-
-
-The `peer.liquidity_low` event indicates that a peer's liquidity has dropped below your predefined liquidity threshold. Decide whether you want to extend the peer's credit line or if your peer must settle before you will extend a new line of credit. If you cannot or do not increase the peer liquidity in Rafiki, transfers to that peer will fail.
+The `peer.liquidity_low` event indicates that a peer's liquidity has dropped below your predefined liquidity threshold. Decide whether you want to extend the peer's credit line or if your peer must settle before you will extend a new line of credit. If you cannot or do not increase the peer liquidity in Rafiki, transfers to that peer will fail.
\ No newline at end of file
diff --git a/packages/documentation/src/content/docs/overview/concepts/accounting.mdx b/packages/documentation/src/content/docs/overview/concepts/accounting.mdx
index 9ea2b75982..2cf093c5f9 100644
--- a/packages/documentation/src/content/docs/overview/concepts/accounting.mdx
+++ b/packages/documentation/src/content/docs/overview/concepts/accounting.mdx
@@ -1,139 +1,261 @@
---
-title: Accounting concepts
+title: Accounting in Rafiki
+tableOfContents:
+ maxHeadingLevel: 4
---
-import { LinkOut } from '@interledger/docs-design-system'
+import { LinkOut, CodeBlock, Mermaid, StylishHeader } from '@interledger/docs-design-system'
+import { Steps } from '@astrojs/starlight/components';
-import { CodeBlock } from '@interledger/docs-design-system'
+Rafiki uses
double-entry accounting to record financial transactions. In this method of bookkeeping, a transaction recorded to one account results in an equal and opposite entry to another account. For example, a \$50 credit to one account will result in a \$50 debit from another account.
-## Accounts and assets
+Transactions in Rafiki represent Interledger packet interactions, denominated in a given [asset](#assets). Packet interactions can be successful, fail, or be rejected. Rafiki's accounting layer processes the interactions and converts the activities into financial records, which are then written to your [accounting database](#accounting-databases).
-Rafiki uses a combination of liquidity (credit) and settlement (debit) accounts to perform
double-entry accounting.
+Accounts within Rafiki are your internal [liquidity](#liquidity-accounts) and [settlement](#settlement-accounts) accounts used to fund payments, not the accounts that you service for your customers. This distinction is crucial for understanding how Rafiki handles transactions and settlements. Some accounts are created on-the-fly during payment processing, while others must be created when integrating with Rafiki or setting up a peer.
-In this context, accounts in Rafiki are specifically the accounts that peers hold with one another. These are not customer accounts. This distinction is crucial for understanding how Rafiki handles transactions and settlements.
+## Assets
+
+An asset represents a transferrable item of value. Although the Interledger Protocol (ILP) supports the transfer of any asset deemed to have value, assets are generally denominated in a currency. For example fiat currencies, central bank digital currencies, and branded currencies (such as merchant reward points).
+
+Part of Rafiki's [integration requirements](/integration/requirements/assets) include adding one or more assets that you support.
+
+An asset is made up of the following properties.
+
+
+
+| Property | Type | Description | Example |
+| -------- | ---- | ----------- | ------- |
+| `value` | BigInt | A numerical amount | `10000` |
+| `assetCode` | String | A code representing the asset. An ISO 4217 currency code should be used whenever possible. | `"USD"` |
+| `assetScale` | Integer | Difference in order of magnitude between the standard unit and a fractional unit | `2` |
+
+
+
+To convert an asset’s value into an amount that’s easier to interpret, apply the following formula.
+
+$\frac{value}{10^{assetScale}}$ = *currencyAmount*
+
+Using the example data from the table above, the formula looks like this:
+
+$\frac{10000}{10^2} =\$100.00 USD
+
+## Accounts
+
+Rafiki uses a combination of liquidity and settlement accounts to track the amounts available to fund transactions. Rafiki does not physically hold funds in each account. Instead, it uses
double-entry accounting to record the transactions. The actual settlement of amounts owed, in which funds are physically exchanged, occurs outside of both Rafiki and the Interledger Protocol.
### Liquidity accounts
-A liquidity account holds a non-negative balance, with Rafiki ensuring that total debits do not exceed total credits.
+Liquidity accounts are used to track deposits, withdrawals, and transfers that occur during the course of a transaction. Liquidity accounts are provided for assets, peers, and payments.
-There is one liquidity account for each of the following resources:
+Liquidity accounts hold either a zero or a positive balance. Rafiki ensures that the total debits to a liquidity account will not exceed the account's total credits.
-- Asset
-- Peer
-- Wallet address
-- Incoming payment
-- Outgoing payment
+
-### Settlement accounts
+| Account type | What the account represents | Number of accounts |
+| ------------------------- | --------------------------- | ------------------ |
+| [Asset liquidity](#asset-liquidity-accounts) | The value, denominated in a given asset, that Rafiki has at its disposal for sending or forwarding ILP packets | One per asset |
+| [Peer liquidity](#peer-liquidity-accounts) | The credit line, denominated in the asset of your peering relationship, that you extend to a peer | One per peer |
+| [Incoming payment liquidity](#incoming-payment-liquidity-accounts) | The value received from a completed incoming payment | One per incoming payment |
+| [Outgoing payment liquidity](#outgoing-payment-liquidity-accounts) | The value that Rafiki will attempt to send in an outgoing payment | One per outgoing payment |
+| [Wallet address liquidity](#wallet-address-liquidity-accounts) | The value of an incoming payment received to a wallet address via either SPSP or Web Monetization | One per wallet address |
+
+
+
+#### Asset liquidity accounts
+
+Asset liquidity ensures there is enough value available to handle a foreign exchange transaction between you and a peer. You have one asset liquidity account for each asset you transact in.
+
+An asset liquidity account represents the value that Rafiki has at its disposal for sending or forwarding ILP packets. The amount in an asset liquidity account increases when packets are received and decreases when packets are sent/forwarded. Any transaction that would result in a negative balance will fail.
+
+:::note
+If you and your peer transact in the same asset (there's no currency conversion) and you both provide your customers only with wallet addresses denominated in that asset, then there will be no movement info/from the corresponding asset liquidity account. In this scenario, the transaction occurs over Interledger's Simple Payment Setup Protocol (SPSP).
+
+For example, you and your peer transact in USD and only provide your customers with USD wallet addresses.
+:::
+
+You should define and adjust asset liquidity based on your liquidity risk profile. You can deposit or withdraw asset liquidity as needed through [Rafiki Admin](/admin/admin-user-guide#edit-asset) or by using the [Backend Admin API](/admin/manage-liquidity#asset-liquidity).
+
+
+Asset liquidity example - cross-currency transactions
+Your Rafiki instance is configured for two assets: EUR and USD.
-A settlement account holds a non-positive balance, with Rafiki ensuring that total credits do not exceed total debits. A settlement account represents the total funds you as the ASE have deposited into Rafiki.
+* Rafiki holds an asset liquidity account for both EUR and USD.
+* You’ve set the asset scale of both currencies to 0.
+* Your starting EUR liquidity is 10 and your USD liquidity is 50.
-Before you can peer with another ASE, you must both agree on the asset you will use for settlement. The Interledger packets exchanged between you and your peer will be denominated in the agreed-upon asset.
+**Cross-currency transaction #1:**
-There is one settlement account for each asset.
+
+1. Rafiki receives packets worth 10 EUR. Your EUR liquidity increases to 20 (10 + 10).
+2. The current EUR-to-USD exchange rate is applied, with 10 EUR equating to 12 USD.
+3. Rafiki sends packets worth 12 USD. Your USD liquidity decreases to 38 (50 - 12).
+
-### Assets
+**Cross-currency transaction #2:**
-An asset represents an item of value that can be transferred via the Interledger Protocol. Since the Interledger Protocol aims to create an internet of value, it allows for the transfer of any asset, not just currency. In practice, however, assets are usually denominated in a currency (fiat or branded currencies).
+
+1. Rafiki receives packets worth 50 EUR. Your EUR liquidity increases to 70 (20 + 50).
+2. The current EUR-to-USD exchange rate is applied, with 50 EUR equating to 55 USD.
+3. The transaction fails. Since your USD liquidity is 38, you do not have enough liquidity to cover the transaction.
+4. Your EUR liquidity reduces back to 20.
+
+
-In Rafiki, the `asset` type is comprised of the following properties.
+#### Peer liquidity accounts
-
+Peer liquidity is the credit line you've extended to a peer. A peer liquidity account represents the amount of the line of credit that the peer still has available to them. You have one liquidity account for each peer and the account is denominated in the asset you both agreed to transact in.
-| Property | Type | Description | Example |
-| ------------ | ------- | ---------------------------------------------------------------------------------------------------------------------- | ------- |
-| `value ` | BigInt | A numerical amount | `10000` |
-| `assetCode` | String | Should be an
ISO 4217 currency code whenever possible | `"USD"` |
-| `assetScale` | Integer | Difference in order of magnitude between the standard unit and a fractional unit | `2` |
+The amount of credit that you extend to a peer, the asset that you transact in, and the mechanism you use to settle are just a few items that should be defined in your respective peering agreements.
+
+:::note
+A peering agreement is a legal contract between the parties involved in a peering relationship. It defines terms such as the assets involved, auth tokens, connection endpoints, and other operational details. It is not configured or managed within Rafiki but is necessary for establishing the terms under which assets are exchanged.
+:::
+
+If a peer’s liquidity is insufficient (e.g., they’ve used up their allotted credit line), payments will not be processed. Your peer should settle with you so that you can reset their liquidity.
+
+You should define and adjust each peer's liquidity based on your liquidity risk profile. You can deposit or withdraw peer liquidity as needed through [Rafiki Admin](/admin/admin-user-guide#edit-peer) or by using the [Backend Admin API](/admin/manage-liquidity#peer-liquidity).
+
+
+Peer liquidity example
+You and Cloud Nine Wallet are peers. You’ve agreed to extend Cloud Nine Wallet a line of credit worth 100.00 USD. This means Cloud Nine Wallet has 100.00 in their peer liquidity account on your Rafiki instance.
+
+Your Rafiki instance can send packets that total up to 100.00 to wallet addresses issued by Cloud Nine Wallet. When the 100.00 is used up, Cloud Nine Wallet settles with you by sending 100.00 via the shared settlement mechanism outlined in your peering agreement. When you receive the funds, you reset their liquidity in Rafiki.
+
+
+#### Payment liquidity accounts
+
+Payment liquidity is the amount that's available because of an incoming or outgoing payment. Rafiki has three types of payment liquidity accounts.
+
+
+
+| Payment type | Purpose |
+| ------------ | ------- |
+| [Incoming](#incoming-payment-liquidity-accounts) | For incoming payments created via the Open Payments APIs |
+| [Outgoing](#outgoing-payment-liquidity-accounts) | For outgoing payments created via the Open Payments APIs |
+| [Wallet address](#wallet-address-liquidity-accounts) | For incoming payments created via SPSP or Web Monetization |
-To convert an asset amount into a currency amount that's easier to read, apply the following formula:
+##### Incoming payment liquidity accounts
-$currencyAmount = \frac{value}{10^{assetScale}}$
+An incoming payment liquidity account represents the value received from a completed incoming payment. When an incoming payment is created via the
Open Payments APIs, a corresponding liquidity account is automatically created. You will have one liquidity account per incoming payment.
-Using the example from the table above, our formula looks like this:
+You are notified of created, completed, and expired incoming payments by listening for the appropriate [webhook events](/integration/requirements/webhook-events/#incoming-payments). Since Rafiki doesn't hold funds, anything you receive must be withdrawn and then credited to the recipient's account on your ledger.
-$\frac{10000}{10^2} =100.00$ USD
+The liquidity account isn’t used again after the payment completes, but its record remains in your accounting database. When a new incoming payment occurs, a new liquidity account is created.
-### TigerBeetle
+##### Outgoing payment liquidity accounts
-TigerBeetle is a high-performance distributed financial accounting database used by Rafiki’s `backend` service to store account balance data at the ILP layer. Both liquidity and settlement accounts in Rafiki correspond to TigerBeetle credit and debit accounts, respectively. TigerBeetle only holds balance data without any additional ILP packet metadata. For detailed information on TigerBeetle, including its consensus mechanism and its limitations, visit the official TigerBeetle
documentation and
blog.
+An outgoing payment liquidity account represents the value available to send in an outgoing payment. When an outgoing payment is created via the
Open Payments APIs, a corresponding liquidity account is automatically created. You will have one liquidity account per outgoing payment.
-You have the flexibility to choose whether to use TigerBeetle or opt for a separate Postgres database. However, TigerBeetle is recommended due to its speed, efficiency, and dedicated design for handling double ledger accounting. For more information about Tigerbeetle in a production environment, see [Running Rafiki in production](/integration/prod/helm-k8s/#tigerbeetle).
+You are notified of created, completed, and failed outgoing payments by listening for the appropriate [webhook events](/integration/requirements/webhook-events/#outgoing-payments). Liquidity must be deposited into the outgoing payment account before the payment can be processed.
-## Liquidity
+Since Rafiki doesn’t hold funds, any excess liquidity that remains after the outgoing payment completes must be withdrawn. While we recommend refunding the excess to the sender, the choice is ultimately up to you.
-Rafiki tracks liquidity using the Interledger Protocol, which is a clearing protocol, without physically holding funds.
+The account isn’t used again after the payment completes, but its record remains in your accounting database. When a new outgoing payment is created, a new liquidity account is created.
-### Asset liquidity
+##### Wallet address liquidity accounts
-Asset liquidity represents the value, denominated in a given asset, that Rafiki has at its disposal in which to send or forward ILP packets. Asset liquidity increases when packets are received and decreases when packets are sent. Asset liquidity is always positive and cannot fall below zero.
+A wallet address liquidity account contains the value received to a wallet address via either SPSP or Web Monetization. When an incoming payment is created by one of these two methods, a corresponding liquidity account is automatically created. You will have one account per wallet address.
-Additionally, you must provide asset liquidity if you are exchanging one currency for another. Asset liquidity ensures there is enough value available to handle transactions in the specified assets.
+Since Rafiki doesn’t hold funds, you must withdraw the liquidity when the payment completes and credit the funds to the recipient’s account on your ledger. You are notified to withdraw liquidity by listening for the appropriate [webhook event](/integration/requirements/webhook-events#wallet-addresses).
-You should define and adjust asset liquidity based on your liquidity risk profile.
+Unlike the incoming and outgoing payment liquidity accounts, the same wallet address liquidity account is used for future incoming SPSP or Web Monetization payments.
-#### Asset liquidity examples
+### Settlement accounts
-Your Rafiki instance is configured with two assets: EUR and USD. You've set both to have an asset scale of 0. Your EUR liquidity is 10, and your USD liquidity is 50.
+A settlement account represents the total funds, denominated in a specified asset, that you have deposited into Rafiki. You have one settlement account for each asset you transact in.
-In a cross currency transaction:
+Settlement accounts hold either a zero or a negative balance. A negative balance on a settlement account means you've deposited more funds into Rafiki than you've taken out.
-- Rafiki receives packets worth 10 EUR and sends packets worth 11 USD. Your EUR liquidity increases to 20 (10 + 10) and your USD liquidity decreases to 39 (50 - 11).
-- Rafiki receives packets worth 50 EUR which equates to 55 USD. This transaction fails because Rafiki does not have enough USD liquidity.
+Rafiki ensures that the total credits to a settlement account will not exceed its total debits.
-### Peer liquidity
+
+Settlement account example
+You deposit \$10,000 into a peer's liquidity account, meaning you've extended a credit line of \$10,000 to your peer.
-Peer liquidity is the credit line, denominated in the asset of the peering relationship, you extend to a peer. Peer liquidity should be defined in the peering agreement and depends on the trust between you and your peer. If peer liquidity is insufficient, payments will not be processed. When peer liquidity is used up, you and your peer should settle then reset your liquidity.
+Your peer liquidity account balance is \$10,000 and your USD settlement account balance is now -\$10,000.
-:::note
-A peering agreement is a legal contract between the parties involved in a peering relationship. It defines terms such as the assets involved, auth tokens, connection endpoints, and other operational details. It is not configured or managed within Rafiki but is necessary for establishing the terms under which assets are exchanged between peers.
-:::
+An incoming payment from your peer for \$100 is created, meaning your peer is using \$100 of their line of credit. Since Rafiki doesn't hold funds, you must withdraw the liquidity and credit the amount to the recipient's account on your ledger.
-#### Peer liquidity example
+Now, your peer liquidity account's balance is \$9,900 and your USD settlement account's balance is -\$9,900.
-Your peer, Cloud Nine Wallet, has a peer liquidity of 100 USD. Rafiki can send packets that total up to 100 USD to wallet addresses issued by Cloud Nine Wallet.
+
-After the 100 USD liquidity is used up, you settle with Cloud Nine Wallet and reset the peer liquidity in Rafiki to 100 USD.
+A negative balance on a settlement account means you've deposited more funds into Rafiki than you've withdrawn. The closer a settlement account's balance is to 0, the more likely it is you need to settle with your peer for the amount owed and then deposit the amount back into Rafiki.
+
+## Accounting databases
+
+### TigerBeetle
-### Payment liquidity
+TigerBeetle is a high-performance distributed financial accounting database used by Rafiki’s backend service to store account balance data at the ILP layer. Both liquidity and settlement accounts in Rafiki correspond to TigerBeetle credit and debit accounts, respectively.
-Payment liquidity is managed for incoming and outgoing payments created via Open Payments through liquidity accounts in your accounting database. When incoming or outgoing payments are created via the Open Payments APIs, a corresponding liquidity account is automatically created. Liquidity must be deposited to an outgoing payment account before the payment can be processed. You are notified to deposit or withdraw liquidity via [webhook events](/integration/requirements/webhook-events).
+TigerBeetle only holds balance data without any additional ILP packet metadata. For detailed information on TigerBeetle, including its consensus mechanism and its limitations, visit the official TigerBeetle
documentation and
blog. For more information about TigerBeetle in a production Rafiki environment, see [Running Rafiki in production](/integration/prod/helm-k8s/#running-rafiki-in-production).
+
+### Postgres
+
+You can choose to use a separate Postgres database for accounting instead of using TigerBeetle. However, TigerBeetle is recommended due to its speed, efficiency, and dedicated design for handling double-entry/double-ledger accounting.
## Transfers
-Transfers in Rafiki are based on double-entry accounting, increasing both the total debits (withdrawals )of one account and the total credits (deposits) of another by the same amount.
+As with the accounts described above, Rafiki performs
double-entry accounting for transfers, where increasing the total debits of one account increases the total credits of another account by the same amount, and vice versa.
+
+Transfers can be completed in either a single phase or in two phases.
### Single-phase transfer
A single-phase transfer posts funds to accounts immediately when the transfer is created.
+**Example of successful single-phase incoming payment**
+
+
>ASE: Fires webhook event when incoming payment completes
+ ASE->>R: Withdraws payment amount from incoming payment liquidity account
+ ASE->>ASE: Credits the recipient's account by the payment amount
+ `}
+/>
+
### Two-phase transfer
-A two-phase transfer moves funds in stages.
+A two-phase transfer moves funds in two stages.
1. Reserve funds (`pending`)
2. Resolve funds (`post`, `void`, or `expire`)
-The name _two-phase transfer_ is a reference to the two-phase commit protocol for distributed transactions.
+**Example of successful two-phase incoming payment**
+
+>ASE: Fires webhook event when incoming payment completes
+ ASE->>Rafiki: Withdraws payment amount from incoming payment liquidity account (reserve funds pending)
+ ASE->>ASE: Credits the recipient's account by the payment amount
+ ASE->>Rafiki: Resolve funds (post)
+ Rafiki->>Rafiki: Two-phase transfer complete
+ `}
+/>
+
+The name two-phase transfer is a reference to the two-phase commit protocol for distributed transactions.
-### Intra-Rafiki transfer examples
+### Transfer examples
+
+#### Intra-Rafiki transfer examples
Remember that a settlement account will always have a zero or negative balance and a liquidity account will always have a zero or positive balance.
-#### Deposits
+Deposits
A deposit is the act of debiting the settlement account and crediting the liquidity account.
-**Depositing asset liquidity**
+**Example:** Depositing `100 USD` asset liquidity
| Debit Account | Credit Account |
| ------------- | --------------- |
| Settlement | Asset liquidity |
-**Example:** Depositing `100 USD`
-
-**Depositing peer liquidity**
+
+
+**Example:** Depositing `100 USD` peer liquidity
| Debit Account | Credit Account |
| ------------- | -------------- |
| Settlement | Peer liquidity |
-**Example:** Peering relationship in USD, depositing `100 USD`
-
-**Depositing outgoing payment liquidity**
+
+
+**Example:** Depositing `35 USD` outgoing payment liquidity
| Debit Account | Credit Account |
| ------------- | ---------------- |
| Settlement | Outgoing payment |
-**Example:** Depositing `35 USD`
-
-#### Withdrawals
+
+
+Withdrawals
A withdrawal is the act of debiting the liquidity account and crediting the settlement account.
-**Withdrawing asset liquidity**
+**Example:** Withdrawing `50 USD` in asset liquidity
| Debit Account | Credit Account |
| --------------- | -------------- |
| Asset liquidity | Settlement |
-**Example:** Withdrawing `50 USD`
-
-**Withdrawing peer liquidity**
+
+
+**Example:** Withdrawing `50 USD` in peer liquidity
| Debit Account | Credit Account |
| -------------- | -------------- |
| Peer liquidity | Settlement |
-**Example:** Peering relationship in USD, withdrawing `50 USD`
-
-**Withdrawing wallet address liquidity**
+
+
+**Example:** Withdrawing `2 USD` in wallet address liquidity
| Debit Account | Credit Account |
| -------------- | -------------- |
| Wallet address | Settlement |
-**Example:** Withdrawing `2 USD`
-
-**Withdrawing incoming payment liquidity**
+
+
+**Example:** Withdrawing `2 USD` in incoming payment liquidity
| Debit Account | Credit Account |
| ---------------- | -------------- |
| Incoming payment | Settlement |
-**Example:** Withdrawing `25 USD`
-
-**Withdrawing outgoing payment liquidity**
+
+
+**Example:** Withdrawing `1 USD` in outgoing payment liquidity
| Debit Account | Credit Account |
| ---------------- | -------------- |
| Outgoing payment | Settlement |
-**Example:** Withdrawing `1 USD`
-
-#### Payments in the same asset
+
+
+Payments in the same asset
-**Send amount < receive amount**
+**Example:** Sender consented to a payment of `14 USD` but the quote promised to deliver `15 USD`. The send amount is less than the receive amount.
| Debit Account | Credit Account |
| ---------------- | ---------------- |
| Outgoing payment | Incoming payment |
| Asset liquidity | Incoming payment |
-**Example:** Sender consented to a payment of `14 USD` but the quote promised to deliver `15 USD`.
-
-**Send amount > receive amount**
+
+
+**Example:** Sender consented to a payment of `15 USD` but the quote promised to deliver `14 USD`. The send amount is more than the receive amount.
| Debit Account | Credit Account |
| ---------------- | ---------------- |
| Outgoing payment | Incoming payment |
| Outgoing payment | Asset liquidity |
-**Example:** Sender consented to a payment of `15 USD` but the quote promised to deliver `14 USD`.
-
-#### Cross currency payments
+
+
+Cross currency payments
-**Exchanging currencies**
+**Example:** Outgoing payment is for `10 USD`, incoming payment receives `9 EUR` after a currency exchange
| Debit Account | Credit Account | Asset |
| ---------------- | ---------------- | ----- |
| Outgoing payment | Asset liquidity | `USD` |
| Asset liquidity | Incoming payment | `EUR` |
-**Example:** Outgoing payment for `10 USD`, incoming payment receives `9 EUR`.
-
-### Interledger transfer examples
+
+
+#### Interledger transfer examples
In these examples, the sender and receiver do not have wallet addresses at the same Rafiki instance.
Remember that a settlement account will always have a zero or negative balance and a liquidity account will always have a zero or positive balance.
-#### Sending connector
+Sending connector - same asset
-**Same asset**
+**Example:** Sender creates an outgoing payment for `100 USD` to an incoming payment in the same asset at a peer's Rafiki instance
| Debit Account | Credit Account |
| ---------------- | -------------- |
| Outgoing payment | Peer liquidity |
-**Example:** Sender creates an outgoing payment for 100 USD to an incoming payment at a peer's Rafiki instance. The peering relationship is in USD.
-
-**Cross currency**
+
+
+Sending connector - cross currency
+
+**Example:** Sender creates an outgoing payment for `100 USD` to an incoming payment at a peer's Rafiki instance. The peering relationship is in EUR, so the payment is converted on the sending side.
| Debit Account | Credit Account | Asset |
| ---------------- | --------------- | ----- |
| Outgoing payment | Asset liquidity | `USD` |
| Asset Liquidity | Peer Liquidity | `EUR` |
-**Example:** Sender creates an outgoing payment for 100 USD to an incoming payment at a peer's Rafiki instance. The peering relationship is in EUR, so payment is converted on the sending side.
-
-#### Receiving connector
+
-**Same asset**
+Receiving connector - same asset
+
+**Example:** An incoming payment receives `100 USD` from an outgoing payment in the same asset at a peer's Rafiki instance.
| Debit Account | Credit Account |
| -------------- | ---------------- |
| Peer liquidity | Incoming payment |
-**Example:** An incoming payment receives `100 USD` from an outgoing payment at a peer's Rafiki instance.
-
-**Cross currency**
+
+
+Receiving connector - cross currency
+
+**Example:** A Rafiki instance receives `10 USD` from a peer (peering relationship in USD) to be deposited in an incoming payment liquidity account denominated in EUR. The payment is converted to EUR and deposited.
| Debit Account | Credit Account | Asset |
| --------------- | ---------------- | ----- |
| Peer liquidity | Asset liquidity | `USD` |
| Asset liquidity | Incoming payment | `EUR` |
-**Example:** A Rafiki instance receives `10 USD` from a peer (peering relationship in USD) to be deposited in an incoming payment liquidity account denominated in EUR. The payment is converted to EUR and deposited.
-
-#### Connector
+
+
+Connector - same asset
-**Same asset**
+**Example:** Rafiki forwards `10 USD` from peer A to peer B.
| Debit Account | Credit Account |
| -------------- | -------------- |
| Peer liquidity | Peer liquidity |
-**Example:** Rafiki forwards `10 USD` from peer A to peer B.
-
-**Cross currency**
+
+
+Connector - cross currency
+
+**Example:** Rafiki receives `100 USD` from peer A and forwards `90 EUR` to peer B.
| Debit Account | Credit Account | Asset |
| --------------- | --------------- | ----- |
| Peer liquidity | Asset liquidity | `USD` |
| Asset liquidity | Peer liquidity | `EUR` |
-**Example:** Rafiki receives `100 USD` from peer A and forwards `90 EUR` to peer B.
-
-
+
\ No newline at end of file
From 45b216db70aaa7e28efb37968549394fd649f621 Mon Sep 17 00:00:00 2001
From: Melissa Henderson <57110301+melissahenderson@users.noreply.github.com>
Date: Fri, 22 Nov 2024 12:46:42 -0500
Subject: [PATCH 2/5] docs: IDP updates based on Max's feedback
---
.../docs/integration/requirements/idp.mdx | 55 +++++++++++--------
.../src/partials/auth-variables.mdx | 2 +-
2 files changed, 32 insertions(+), 25 deletions(-)
diff --git a/packages/documentation/src/content/docs/integration/requirements/idp.mdx b/packages/documentation/src/content/docs/integration/requirements/idp.mdx
index 8939d05ba1..fd8e8d5c23 100644
--- a/packages/documentation/src/content/docs/integration/requirements/idp.mdx
+++ b/packages/documentation/src/content/docs/integration/requirements/idp.mdx
@@ -12,14 +12,13 @@ import {
An identity provider (IdP) is a system or service that stores and manages user identity information, authentication, and consent. Examples of IdPs include OpenID Connect and Okta.
-Open Payments requires any authorization server that issues interactive grants be integrated with an IdP. Interactive grants are used to gather consent, and are required for Open Payments outgoing payments. Interactive grants are optional for incoming payments and quotes.
+Open Payments requires any authorization server that issues interactive grants be integrated with an IdP. Interactive grants are used to gather consent. More information about interactive grants are available [below](#interactive-grants).
Responsibilities of your IdP include:
-- Providing an interface to gather consent
+- Providing an interface to gather end-user consent for a particular action
- Sending the interaction choice (approve or deny) to your authorization server
- Sending a request to your authorization server to finish the interaction
- Redirecting the user after the interaction is complete
-- Authenticating requests from clients to create payments on Rafiki's backend
:::note
We provide Ory Kratos, a cloud-based user management system, for the identity and user management of your Rafiki Admin users. Kratos is for internal use only and **cannot** be used as your IdP for Open Payments.
@@ -29,31 +28,35 @@ We provide Ory Kratos, a cloud-based user management system, for the identity an
In Open Payments, grants are used to indicate a resource owner, such as an account holder, has given a piece of software, such as a mobile app, permission (consent) to act on their behalf.
-Open Payments requires that consent be collected via an interactive grant before an outgoing payment request is issued. A grant is interactive when explicit interaction by an entity (e.g., the software's end user) is required to approve or deny the grant. Tapping an *Approve* button to authorize a payment is an example of an explicit interaction.
+Open Payments requires that consent is collected via an interactive grant before an outgoing payments request is issued. A grant is interactive when explicit interaction by an entity (e.g., the software's end user) is required to approve or deny the grant. Tapping an *Approve* button to authorize a payment is an example of an explicit interaction.
+
+Interactive grants can be optional for incoming payments and quotes; however, they're enabled by default in Rafiki (the `LIST_ALL_ACCESS_INTERACTION` environment variable is `true`). When a grant request includes a `list-all` action for incoming payments and quotes, the request requires interaction. The `list-all` action is used when the client asks to list resources that it did not create.
+
+If `LIST_ALL_ACCESS_INTERACTION` is `false`, you can still force interactive grants for quotes by setting `QUOTE_INTERACTION` to `true`.
See the Open Payments documentation for more information on grant negotiation and authorization.
## Authorization servers
-Authorization servers grant permission to clients to access the Open Payments APIs. This enables clients to create incoming payments, quotes, and outgoing payments against an account holder's account.
+Authorization servers grant permission to clients to access the Open Payments Resource APIs. This enables clients to create incoming payments, quotes, and outgoing payments against an account holder's account.
Rafiki's [auth service](/integration/services/auth-service) provides you with a reference implementation of an Open Payments authorization server. You can use the service as an alternative to developing your own in-house solution. Additionally, the server extends an [API](#interaction-endpoints) that provides interaction endpoints for your IdP.
### Environment variables
-The following `backend` variables must be configured on your authorization server.
+The following variables must be configured for the `auth` service.
| Variable | Helm value name | Default | Description |
| -------- | --------------- | ------- | ----------- |
-| `IDENTITY_SERVER_URL` | `auth.identityServer.domain` | N/A | Your IdP server's URL where your authorization server will direct clients to so end-users can complete the interaction and authorize a grant. | Y |
+| `IDENTITY_SERVER_URL` | `auth.identityServer.domain` | N/A | The URL of your IdP's server, used by your authorization server to inform an Open Payments client of where to redirect the end-user to complete the interaction and authorize a grant. | Y |
| `IDENTITY_SERVER_SECRET` | `auth.identityServer.secret` | N/A | A shared secret between your authorization and IdP servers that your authorization server will use to secure its IdP-related endpoints.
When your IdP sends requests to your authorization server, your IdP must provide the secret via an [`x-idp-secret`](#x-idp-secret-header) header. | Y |
| `INCOMING_PAYMENT_INTERACTION` | `auth.interaction.incomingPayment` | `false` | Indicates whether incoming payments grant requests are interactive. | Y |
| `INTERACTION_EXPIRY_SECONDS` | `auth.interactionExpirySeconds` | `600` | The time in seconds for which a user can interact with a grant request | Y |
| `INTERACTION_PORT` | `auth.port.interaction` | `3009` | The port number for the [interaction endpoints](#interaction-endpoints) | Y |
-| `INTROSPECTION_PORT` | `auth.port.introspection` | `3007` | The port number of your Open Payments authorization token introspection server | Y |
| `LIST_ALL_ACCESS_INTERACTION` | N/A | `true` | Specifies whether grant requests including a `list-all` action should require interaction. In these requests, the client asks to list resources that they themselves did not create. | Y |
+| `QUOTE_INTERACTION` | `auth.interaction.quote` | `false` | When `true`, quote grants are interactive. |
@@ -63,10 +66,10 @@ The authorization server provided by Rafiki's `auth` service extends an API for
Each interaction with an endpoint is identified by an `id` and a `nonce`. Both are provided as query parameters when your authorization server redirects to your IdP's server.
-The endpoints are tied to the `IDENTITY_SERVER_URL` you defined when configuring your environment variables. For example, if your identity server URL is `https://idp.wallet.example.com`, then calling the `/interact/{id}/{nonce}` endpoint to start a user interaction session would look as follows:
+The endpoints are tied to the auth server URL. For example, if your auth server URL is `https://auth.wallet.example.com`, then calling the `/interact/{id}/{nonce}` endpoint to start a user interaction session would look as follows:
```
-https://idp.wallet.example.com/interact/{id}/{nonce}
+https://auth.wallet.example.com/interact/{id}/{nonce}
```
### Interaction endpoints
@@ -75,13 +78,13 @@ The endpoints are called in the sequence listed below.
-| Method | Endpoint | Purpose |
-| ------ | -------- | ------- |
-| | `/interact/{id}/{nonce}` | [Start user interaction session](#start-user-interaction-session) |
-| | `/grant/{id}/{nonce}` | [Look up grant information](#look-up-grant-information) |
-| | `/grant/{id}/{nonce}/{choice}` | [Accept or reject grant](#accept-or-reject-grant) |
-| | `/interact/{id}/{nonce}/finish` | [Finish user interaction](#finish-interaction) |
-| | `/interact/{id}/{nonce}` | [Continue grant](#continue-grant) |
+| Method | Endpoint | Purpose | Called by | Publicly exposed |
+| ------ | -------- | ------- | --------- | ------------------- |
+| | `/interact/{id}/{nonce}` | [Start user interaction session](#start-user-interaction-session) | Open Payments client | Yes |
+| | `/grant/{id}/{nonce}` | [Look up grant information](#look-up-grant-information) | Identity provider | No |
+| | `/grant/{id}/{nonce}/{choice}` | [Accept or reject grant](#accept-or-reject-grant) | Identity provider | No |
+| | `/interact/{id}/{nonce}/finish` | [Finish user interaction](#finish-interaction) | Identity provider | Yes |
+| | `/interact/{id}/{nonce}` | [Continue grant](#continue-grant) | Open Payments client | Yes |
@@ -97,15 +100,13 @@ Called by your IdP server to retrieve a list of access rights, requested by the
#### Accept or reject grant
-Your IdP server communicates the choice made by the end-user on the consent screen (accept/reject) to your authorization server. The request is secured with an [`x-idp-secret`](#x-idp-secret-header) header. Then, your IdP server redirects to the `finish` endpoint. The response is served on your configured `INTERACTION_PORT`.
+Your IdP server communicates the choice made by the end-user on the consent screen (accept/reject) to your authorization server. The request is secured with an [`x-idp-secret`](#x-idp-secret-header) header. Then, your IdP server calls the `finish` endpoint on Rafiki's `auth` service, which handles the interaction requests on your defined `INTERACTION PORT`.
#### Finish interaction
Called by your IdP server to end the interaction and redirect the end-user's browser session to the URI of the grant initialization request.
-The `result` query parameter indicates the success or failure of the grant authorization. When successful, the SHA-256 hash of the interaction is sent in the response along with an `interact_ref` that identifies the interaction on the authorization server and the URI of the grant initialization request.
-
-The following are examples of the possible response types.
+The `result` query parameter indicates the success or failure of the grant authorization. The following are examples of the possible response types.
@@ -117,18 +118,24 @@ The following are examples of the possible response types.
+When successful, the SHA-256 hash of the interaction is sent in the response to the client, along with an `interact_ref` that identifies the interaction on the authorization server and the URI of the grant initialization request. The client must verify the hash before it will request to continue the grant
+
#### Continue grant
The client requests a grant from your authorization server for an accepted interaction. Your authorization server responds with an access token.
## x-idp-secret header
-The `x-idp-secret` header is used for requests to the following endpoints:
+The `x-idp-secret` header is specific to Rafiki's authorization server and is used for requests to the following endpoints:
- `GET /grant/:id/:nonce`
- `POST /grant/:id/:nonce/accept`
- `POST /grant/:id/:nonce/reject`
-The header's purpose is to secure communications between your IdP and authorization server and its value should be a shared secret known to both entities. When your IdP server sends requests to your authorization server, your IdP must provide the secret via this header.
+The header's purpose is to secure communications between your IdP and Rafiki's authorization server. Its value should be a shared secret known to both entities. When your IdP server sends requests to Rafiki's authorization server, your IdP must provide the secret via this header.
+
+:::note
+If you're running your own authorization server rather than using the server provided by Rafiki, you can add security in any way you see fit. You aren't required to use the `x-idp-secret` header.
+:::
-To set up the header, set the `IDENTITY_SERVER_SECRET` on your authorization server environment to a value that is also used to configure your IdP server's requests to your authorization server.
\ No newline at end of file
+To set up the header, set the `IDENTITY_SERVER_SECRET` variable to a value that is also used to configure your IdP server's requests to the authorization server.
\ No newline at end of file
diff --git a/packages/documentation/src/partials/auth-variables.mdx b/packages/documentation/src/partials/auth-variables.mdx
index 663ee7a31d..f2cb02005e 100644
--- a/packages/documentation/src/partials/auth-variables.mdx
+++ b/packages/documentation/src/partials/auth-variables.mdx
@@ -9,7 +9,7 @@ import { LinkOut } from '@interledger/docs-design-system'
| `AUTH_DATABASE_URL` | `auth.postgresql.host`,
`auth.postgresql.port`,
`auth.postgresql.username`,
`auth.postgresql.database`,
`auth.postgresql.password` | `postgresql://postgres:password@localhost:5432/auth_development` | The URL of the Postgres database storing your Open Payments grant data. For Helm, these components are provided individually. |
| `AUTH_SERVER_URL` | `auth.server.domain` | _undefined_ | The public endpoint for your Rafiki instance’s public Open Payments routes. |
| `COOKIE_KEY` | `auth.cookieKey` | _undefined_ | The koa KeyGrip key that is used to sign cookies for an interaction session. |
-| `IDENTITY_SERVER_URL` | `auth.identityServer.domain` | _undefined_ | The specific URL of your identity provider's user-facing consent screen. |
+| `IDENTITY_SERVER_URL` | `auth.identityServer.domain` | _undefined_ | The URL of your IdP's server, used by your authorization server to inform an Open Payments client of where to redirect the end-user to complete the interaction and authorize a grant. |
| `IDENTITY_SERVER_SECRET` | `auth.identityServer.secret` | _undefined_ | The API key for fetching your identity (IdP) server endpoint. |
| `REDIS_URL` | `auth.redis.host`,
`auth.redis.port` | `redis://127.0.0.1:6379` | The connection URL for Redis. For Helm, these components are provided individually. |
From 3a5b8c3671b7d6972bd605b0e49ca8cc12d9e715 Mon Sep 17 00:00:00 2001
From: Melissa Henderson <57110301+melissahenderson@users.noreply.github.com>
Date: Mon, 25 Nov 2024 11:49:28 -0500
Subject: [PATCH 3/5] docs: idp and auth var updates
---
.../docs/integration/requirements/idp.mdx | 20 +++----
.../src/partials/auth-variables.mdx | 54 +++++++++----------
2 files changed, 38 insertions(+), 36 deletions(-)
diff --git a/packages/documentation/src/content/docs/integration/requirements/idp.mdx b/packages/documentation/src/content/docs/integration/requirements/idp.mdx
index fd8e8d5c23..a5a97d51f1 100644
--- a/packages/documentation/src/content/docs/integration/requirements/idp.mdx
+++ b/packages/documentation/src/content/docs/integration/requirements/idp.mdx
@@ -12,7 +12,7 @@ import {
An identity provider (IdP) is a system or service that stores and manages user identity information, authentication, and consent. Examples of IdPs include OpenID Connect and Okta.
-Open Payments requires any authorization server that issues interactive grants be integrated with an IdP. Interactive grants are used to gather consent. More information about interactive grants are available [below](#interactive-grants).
+Open Payments requires any authorization server that issues interactive grants be integrated with an IdP. Interactive grants are used to gather consent. More information about interactive grants is available [below](#interactive-grants).
Responsibilities of your IdP include:
- Providing an interface to gather end-user consent for a particular action
@@ -28,7 +28,7 @@ We provide Ory Kratos, a cloud-based user management system, for the identity an
In Open Payments, grants are used to indicate a resource owner, such as an account holder, has given a piece of software, such as a mobile app, permission (consent) to act on their behalf.
-Open Payments requires that consent is collected via an interactive grant before an outgoing payments request is issued. A grant is interactive when explicit interaction by an entity (e.g., the software's end user) is required to approve or deny the grant. Tapping an *Approve* button to authorize a payment is an example of an explicit interaction.
+Rafiki's implementation of an Open Payments authorization server requires that consent is collected via an interactive grant before an outgoing payments request is issued. A grant is interactive when explicit interaction by a resource owner (e.g., the software's end user) is required to approve or deny the grant. Tapping an *Approve* button to authorize a payment is an example of an explicit interaction.
Interactive grants can be optional for incoming payments and quotes; however, they're enabled by default in Rafiki (the `LIST_ALL_ACCESS_INTERACTION` environment variable is `true`). When a grant request includes a `list-all` action for incoming payments and quotes, the request requires interaction. The `list-all` action is used when the client asks to list resources that it did not create.
@@ -40,7 +40,9 @@ See the Open Payme
Authorization servers grant permission to clients to access the Open Payments Resource APIs. This enables clients to create incoming payments, quotes, and outgoing payments against an account holder's account.
-Rafiki's [auth service](/integration/services/auth-service) provides you with a reference implementation of an Open Payments authorization server. You can use the service as an alternative to developing your own in-house solution. Additionally, the server extends an [API](#interaction-endpoints) that provides interaction endpoints for your IdP.
+Rafiki's [auth service](/integration/services/auth-service) provides you with a reference implementation of an Open Payments authorization server. We recommend you use the `auth` service rather than developing your own in-house solution.
+
+The authorization server also extends an [API](#interaction-endpoints) that provides interaction endpoints for your IdP.
### Environment variables
@@ -50,7 +52,7 @@ The following variables must be configured for the `auth` service.
| Variable | Helm value name | Default | Description |
| -------- | --------------- | ------- | ----------- |
-| `IDENTITY_SERVER_URL` | `auth.identityServer.domain` | N/A | The URL of your IdP's server, used by your authorization server to inform an Open Payments client of where to redirect the end-user to complete the interaction and authorize a grant. | Y |
+| `IDENTITY_SERVER_URL` | `auth.identityServer.domain` | N/A | The URL of your IdP's server, used by the authorization server to inform an Open Payments client of where to redirect the end-user to start interactions. | Y |
| `IDENTITY_SERVER_SECRET` | `auth.identityServer.secret` | N/A | A shared secret between your authorization and IdP servers that your authorization server will use to secure its IdP-related endpoints.
When your IdP sends requests to your authorization server, your IdP must provide the secret via an [`x-idp-secret`](#x-idp-secret-header) header. | Y |
| `INCOMING_PAYMENT_INTERACTION` | `auth.interaction.incomingPayment` | `false` | Indicates whether incoming payments grant requests are interactive. | Y |
| `INTERACTION_EXPIRY_SECONDS` | `auth.interactionExpirySeconds` | `600` | The time in seconds for which a user can interact with a grant request | Y |
@@ -92,7 +94,7 @@ We also provide an grant initialization request.
+Called by your IdP server to end the interaction. Your authorization server automatically redirects the end-user's browser session to the `finish` endpoint on Rafiki's `auth` service, which handles the interaction requests on your defined `INTERACTION PORT`.
-The `result` query parameter indicates the success or failure of the grant authorization. The following are examples of the possible response types.
+The `result` query parameter in the response indicates the success or failure of the grant authorization. The following are examples of the possible response types.
@@ -118,7 +120,7 @@ The `result` query parameter indicates the success or failure of the grant autho
-When successful, the SHA-256 hash of the interaction is sent in the response to the client, along with an `interact_ref` that identifies the interaction on the authorization server and the URI of the grant initialization request. The client must verify the hash before it will request to continue the grant
+When successful, the SHA-256 hash of the interaction is sent in the response to the client, along with an `interact_ref` that identifies the interaction on the authorization server and the URI of the grant initialization request. The client must verify the hash before it will request to continue the grant.
#### Continue grant
diff --git a/packages/documentation/src/partials/auth-variables.mdx b/packages/documentation/src/partials/auth-variables.mdx
index f2cb02005e..5d3b4dd0a7 100644
--- a/packages/documentation/src/partials/auth-variables.mdx
+++ b/packages/documentation/src/partials/auth-variables.mdx
@@ -6,12 +6,12 @@ import { LinkOut } from '@interledger/docs-design-system'
| Variable | Helm value name | Default | Description |
| -------- | --------------- | ------- | ----------- |
-| `AUTH_DATABASE_URL` | `auth.postgresql.host`,
`auth.postgresql.port`,
`auth.postgresql.username`,
`auth.postgresql.database`,
`auth.postgresql.password` | `postgresql://postgres:password@localhost:5432/auth_development` | The URL of the Postgres database storing your Open Payments grant data. For Helm, these components are provided individually. |
-| `AUTH_SERVER_URL` | `auth.server.domain` | _undefined_ | The public endpoint for your Rafiki instance’s public Open Payments routes. |
-| `COOKIE_KEY` | `auth.cookieKey` | _undefined_ | The koa KeyGrip key that is used to sign cookies for an interaction session. |
-| `IDENTITY_SERVER_URL` | `auth.identityServer.domain` | _undefined_ | The URL of your IdP's server, used by your authorization server to inform an Open Payments client of where to redirect the end-user to complete the interaction and authorize a grant. |
-| `IDENTITY_SERVER_SECRET` | `auth.identityServer.secret` | _undefined_ | The API key for fetching your identity (IdP) server endpoint. |
-| `REDIS_URL` | `auth.redis.host`,
`auth.redis.port` | `redis://127.0.0.1:6379` | The connection URL for Redis. For Helm, these components are provided individually. |
+| `AUTH_DATABASE_URL` | `auth.postgresql.host`,
`auth.postgresql.port`,
`auth.postgresql.username`,
`auth.postgresql.database`,
`auth.postgresql.password` | `postgresql://postgres:password@localhost:5432/auth_development` | The URL of the Postgres database storing your Open Payments grant data. For Helm, these components are provided individually. |
+| `AUTH_SERVER_URL` | `auth.server.domain` | _undefined_ | The public endpoint for your Rafiki instance’s public Open Payments routes. |
+| `COOKIE_KEY` | `auth.cookieKey` | _undefined_ | The koa KeyGrip key that is used to sign cookies for an interaction session. |
+| `IDENTITY_SERVER_URL` | `auth.identityServer.domain` | _undefined_ | The URL of your IdP's server, used by the authorization server to inform an Open Payments client of where to redirect the end-user to start interactions. |
+| `IDENTITY_SERVER_SECRET` | `auth.identityServer.secret` | _undefined_ | The API key for fetching your identity (IdP) server endpoint. |
+| `REDIS_URL` | `auth.redis.host`,
`auth.redis.port` | `redis://127.0.0.1:6379` | The connection URL for Redis. For Helm, these components are provided individually. |
@@ -21,26 +21,26 @@ import { LinkOut } from '@interledger/docs-design-system'
| Variable | Helm value name | Default | Description |
| -------- | --------------- | ------- | ----------- |
-| `ACCESS_TOKEN_DELETION_DAYS` | `auth.accessToken.deletionDays` | `30` | The days until expired and/or revoked access tokens are deleted. |
-| `ACCESS_TOKEN_EXPIRY_SECONDS` | `auth.accessToken.expirySeconds` | `600` (10 minutes) | The expiry time, in seconds, for access tokens. |
-| `ADMIN_API_SIGNATURE_VERSION` | `auth.adminApi.signatureVersion` | `1` | The version of the request signing algorithm used to generate signatures. |
-| `ADMIN_API_SIGNATURE_TTL_SECONDS` | `auth.adminAPI.signatureTtlSeconds` | `30` | The TTL, in seconds, for which a request’s signature will be valid. |
-| `ADMIN_PORT` | `auth.port.admin` | `3003` | The port of your Rafiki Auth Admin API server. |
-| `AUTH_PORT` | `auth.port.auth` | `3006` | The port of your Open Payments authorization server. |
-| `DATABASE_CLEANUP_WORKERS` | `auth.workers.cleanup` | `1` | The number of workers processing expired or revoked access tokens. |
-| `ENABLE_MANUAL_MIGRATIONS` | `auth.enableManualMigrations` | `false` | When `true`, you must run the auth Postgres database manually with the command `npm run knex – migrate:latest –envproduction` |
-| `INCOMING_PAYMENT_INTERACTION` | `auth.interaction.incomingPayment` | `false` | When `true`, incoming Open Payments grant requests are interactive |
-| `INTERACTION_EXPIRY_SECONDS` | `auth.interactionExpirySeconds` | `600` (10 minutes) | The time, in seconds, for which a user can interact with a grant request before the request expires. |
-| `INTERACTION_PORT` | `auth.port.interaction` | `3009` | The port number of your Open Payments interaction-related APIs. |
-| `INTROSPECTION_PORT` | `auth.port.introspection` | `3007` | The port of your Open Payments access token introspection server. |
-| `LIST_ALL_ACCESS_INTERACTION` | `auth.interaction.listAll` | `true` | When `true`, grant requests that include a `list-all` action will require interaction. In these requests, the client asks to list resources that it did not create. |
-| `LOG_LEVEL` | `auth.logLevel` | `info` |
Pino log level |
-| `NODE_ENV` | `auth.nodeEnv` | `development` | The type of node environment: `development`, `test`, or `production`. |
-| `QUOTE_INTERACTION` | `auth.interaction.quote` | `false` | When `true`, quote grants are interactive. |
-| `REDIS_TLS_CA_FILE_PATH` | `auth.redis.tlsCaFile` | `''` |
Redis TLS config |
-| `REDIS_TLS_CERT_FILE_PATH` | `auth.redis.tlsCertFile` | `''` |
Redis TLS config |
-| `REDIS_TLS_KEY_FILE_PATH` | `auth.redis.tlsKeyFile` | `''` |
Redis TLS config |
-| `TRUST_PROXY` | `auth.trustProxy` | `false` | When `true`, the `X-Forwarded-Proto` header is used to determine if connections are secure. |
-| `WAIT_SECONDS` | `auth.grant.waitSeconds` | `5` | The wait time, in seconds, included in a grant request response (`grant.continue`). |
+| `ACCESS_TOKEN_DELETION_DAYS` | `auth.accessToken.deletionDays` | `30` | The days until expired and/or revoked access tokens are deleted. |
+| `ACCESS_TOKEN_EXPIRY_SECONDS` | `auth.accessToken.expirySeconds` | `600` (10 minutes) | The expiry time, in seconds, for access tokens. |
+| `ADMIN_API_SIGNATURE_VERSION` | `auth.adminApi.signatureVersion` | `1` | The version of the request signing algorithm used to generate signatures. |
+| `ADMIN_API_SIGNATURE_TTL_SECONDS` | `auth.adminAPI.signatureTtlSeconds` | `30` | The TTL, in seconds, for which a request’s signature will be valid. |
+| `ADMIN_PORT` | `auth.port.admin` | `3003` | The port of your Rafiki Auth Admin API server. |
+| `AUTH_PORT` | `auth.port.auth` | `3006` | The port of your Open Payments authorization server. |
+| `DATABASE_CLEANUP_WORKERS` | `auth.workers.cleanup` | `1` | The number of workers processing expired or revoked access tokens. |
+| `ENABLE_MANUAL_MIGRATIONS` | `auth.enableManualMigrations` | `false` | When `true`, you must run the auth Postgres database manually with the command `npm run knex – migrate:latest –envproduction` |
+| `INCOMING_PAYMENT_INTERACTION` | `auth.interaction.incomingPayment` | `false` | When `true`, incoming Open Payments grant requests are interactive |
+| `INTERACTION_EXPIRY_SECONDS` | `auth.interactionExpirySeconds` | `600` (10 minutes) | The time, in seconds, for which a user can interact with a grant request before the request expires. |
+| `INTERACTION_PORT` | `auth.port.interaction` | `3009` | The port number of your Open Payments interaction-related APIs. |
+| `INTROSPECTION_PORT` | `auth.port.introspection` | `3007` | The port of your Open Payments access token introspection server. |
+| `LIST_ALL_ACCESS_INTERACTION` | `auth.interaction.listAll` | `true` | When `true`, grant requests that include a `list-all` action will require interaction. In these requests, the client asks to list resources that it did not create. |
+| `LOG_LEVEL` | `auth.logLevel` | `info` |
Pino log level |
+| `NODE_ENV` | `auth.nodeEnv` | `development` | The type of node environment: `development`, `test`, or `production`. |
+| `QUOTE_INTERACTION` | `auth.interaction.quote` | `false` | When `true`, quote grants are interactive. |
+| `REDIS_TLS_CA_FILE_PATH` | `auth.redis.tlsCaFile` | `''` |
Redis TLS config |
+| `REDIS_TLS_CERT_FILE_PATH` | `auth.redis.tlsCertFile` | `''` |
Redis TLS config |
+| `REDIS_TLS_KEY_FILE_PATH` | `auth.redis.tlsKeyFile` | `''` |
Redis TLS config |
+| `TRUST_PROXY` | `auth.trustProxy` | `false` | When `true`, the `X-Forwarded-Proto` header is used to determine if connections are secure. |
+| `WAIT_SECONDS` | `auth.grant.waitSeconds` | `5` | The wait time, in seconds, included in a grant request response (`grant.continue`). |
From 922d997c5082ef5b23989909524de27b39fb7780 Mon Sep 17 00:00:00 2001
From: Melissa Henderson <57110301+melissahenderson@users.noreply.github.com>
Date: Tue, 3 Dec 2024 11:26:31 -0500
Subject: [PATCH 4/5] docs: minor idp-related updates
---
.../docs/integration/requirements/idp.mdx | 30 ++++++++++---------
.../src/partials/auth-variables.mdx | 2 +-
2 files changed, 17 insertions(+), 15 deletions(-)
diff --git a/packages/documentation/src/content/docs/integration/requirements/idp.mdx b/packages/documentation/src/content/docs/integration/requirements/idp.mdx
index a5a97d51f1..34f78020a5 100644
--- a/packages/documentation/src/content/docs/integration/requirements/idp.mdx
+++ b/packages/documentation/src/content/docs/integration/requirements/idp.mdx
@@ -16,8 +16,8 @@ Open Payments requires any authorization server that issues interactive grants b
Responsibilities of your IdP include:
- Providing an interface to gather end-user consent for a particular action
-- Sending the interaction choice (approve or deny) to your authorization server
-- Sending a request to your authorization server to finish the interaction
+- Sending the interaction choice (approve or deny) to the authorization server
+- Sending a request to the authorization server to finish the interaction
- Redirecting the user after the interaction is complete
:::note
@@ -32,7 +32,9 @@ Rafiki's implementation of an Open Payments authorization server requires that c
Interactive grants can be optional for incoming payments and quotes; however, they're enabled by default in Rafiki (the `LIST_ALL_ACCESS_INTERACTION` environment variable is `true`). When a grant request includes a `list-all` action for incoming payments and quotes, the request requires interaction. The `list-all` action is used when the client asks to list resources that it did not create.
-If `LIST_ALL_ACCESS_INTERACTION` is `false`, you can still force interactive grants for quotes by setting `QUOTE_INTERACTION` to `true`.
+If `LIST_ALL_ACCESS_INTERACTION` is `false`, you can still force interactive grants for quotes and/or incoming payments by setting the respective variable(s) to `true`.
+* `QUOTE_INTERACTION`
+* `INCOMING_PAYMENT_INTERACTION`
See the