Create an interactive grant
This guide describes how to create an interactive grant. An interactive grant requires interaction from a user, typically your client’s end-user, before the grant can be issued.
For outgoing payment grants, the resource owner (e.g., your client’s end-user) must explicitly consent to the creation of an outgoing payment resource. As such, Open Payments requires outgoing payment grants be interactive.
Grants for creating incoming payment and quote resources are non-interactive by default; however, you can choose to make one or both interactive to fit your implementation needs.
Dependencies
Endpoints
Create an interactive grant
- Node 18
- A package manager such as NPM or PNPM
-
Open Payments SDK
- TSX
Additional configuration
Add "type": "module"
to package.json
Add the following to tsconfig.json
Steps
1. Import dependencies
Import createAuthenticatedClient
from the Open Payments SDK package.
Import dependencies
import {
createAuthenticatedClient,
isPendingGrant,
} from "@interledger/open-payments";
2. Create and initialize an authenticated Open Payments client
Create an OP authenticated client by providing the following properties:
walletAddressURL
: your OP-enabled wallet address that your client will use to authenticate itself to one or more authorization servers.privateKey
: the EdDSA-Ed25519 key or preferably the absolute or relative file path to the key that is bound to your wallet address. A public key signed with this private key must be made available as a public JWK document at{walletAddressUrl}/jwks.json
url.keyId
: the identifier of the private key and the corresponding public key.
Initialize Open Payments client
const client = await createAuthenticatedClient({
walletAddressUrl: WALLET_ADDRESS,
privateKey: PRIVATE_KEY_PATH,
keyId: KEY_ID,
});
3. Get payee’s wallet address information
Get wallet address information
const walletAddress = await client.walletAddress.get({
url: WALLET_ADDRESS,
});
4. Request an interactive grant
Indicate your client is capable of directing the end-user to a URI to start an interaction. We’ll use an outgoing payment grant as an example.
- Add the
interact
object to your grant request. - Specify
redirect
as thestart
mode. Open Payments only supportsredirect
at this time. The redirect URI will be provided by the authorization server in its response.
Now, indicate your client can receive a signal from the authorization server when the interaction has finished.
- Add the
finish
object within theinteract
object. - Specify
redirect
as themethod
. Open Payments only supportsredirect
at this time. - Specify the
uri
that the authorization server will send the end-user back to when the interaction has finished. - Create a
nonce
for your client to use to verify the authorization server is the same entity throughout the entire process. The nonce can be any random, hard-to-guess string.
Request outgoing payment grant
const grant = await client.grant.request(
{
url: walletAddress.authServer,
},
{
access_token: {
access: [
{
identifier: walletAddress.id,
type: "outgoing-payment",
actions: ["list", "list-all", "read", "read-all", "create"],
limits: {
debitAmount: DEBIT_AMOUNT,
receiveAmount: RECEIVE_AMOUNT,
},
},
],
},
interact: {
start: ["redirect"],
finish: {
method: "redirect",
uri: "http://localhost:3344",
nonce: NONCE,
},
},
},
);
Check grant state
if (!isPendingGrant(grant)) {
throw new Error("Expected interactive grant");
}
5. Start interaction with the end user
Once your client receives the authorization server’s response, it must send the end-user to the interact.redirect
URI contained in the response. This starts the interaction flow.
Example response
6. Finish interaction with the end user
The end-user interacts with the authorization server through the server’s interface and approves or denies the grant.
Provided the end-user approves the grant, the authorization server:
- Sends the end-user to your client’s previously defined
finish.uri
. The means by which the server sends the end-user to the URI is out of scope, but common options include redirecting the end-user from a web page and launching the system browser with the target URI. - Secures the redirect by adding a unique hash, allowing your client to validate the
finish
call, and an interaction reference as query parameters to the URI.
7. Request a grant continuation
Add the authorization server’s interaction reference, as the interact_ref
value, to the body of your continuation request.
Continue grant
const grant = await client.grant.continue(
{
accessToken: CONTINUE_ACCESS_TOKEN,
url: CONTINUE_URI,
},
{
interact_ref: interactRef,
},
);
Issue the request to the continue uri
supplied in the authorization server’s initial grant response. For example:
POST https://auth.rafiki.money/continue/4CF492MLVMSW9MKMXKHQ
A successful continuation response from the authorization server provides your client with an access token and other information necessary to continue the transaction.
Example response