Client App Quick Start Guide
This guide will walk you through setting up a mobile or web client application to connect to a user's UMA wallet and send a payment.
We provide SDKs for Android, iOS, and web platforms to simplify this process.
Using the UMA Auth Client SDKs, you can:
- Establish a Nostr Wallet Connect (NWC) connection to the user's UMA wallet using OAuth 2.0
- Make various payment-related requests using the established connection
The UMA Connect button is the UI entry point to the UMA Auth flow. You can import and embed this button into your application and
optionally customize its appearance.
The SDK also requires several configuration parameters specific to your client app. These are:
- App identity public key - For information on how to generate your application's identity public key, see the The App Identity Nostr Keys guide.
- Nostr relay URL - The URL of the relay where your app registration event was published.
- Redirect URI - The callback URL where the authorization server sends the user after a successful OAuth authentication.
- Required commands - A list of essential NWC methods that your app must have permission for to support basic interaction.
- Optional commands - A list of additional NWC methods that enhance functionality but are not necessary for basic operations.
- Requested spending limit, currency and time period - The maximum speding amount (in specific currency for duration) that your app would like to request for the connection.
In React, you can use the
UmaConnectButton
element:<UmaConnectButton
app-identity-pubkey="npub1hf4dj426lt26x5z7d3rc9c95yu7qggr3nv30xkqctv4vru7wnrsq6vw3gz"
nostr-relay="wss://nos.lol"
redirect-uri="http://localhost:3001"
required-commands={[
"pay_invoice",
"get_balance",
"get_budget",
"get_info",
"make_invoice",
]}
optional-commands={[
"list_transactions",
]}
budget-amount="500"
budget-currency="SAT"
budget-period="monthly"
style={{
"--uma-connect-background": "#7366C5",
"--uma-connect-radius": "8px",
"--uma-connect-padding-x": "32px",
"--uma-connect-padding-y": "16px",
"--uma-connect-text-color": "#F9F9F9",
"--uma-connect-font-family": "Arial",
"--uma-connect-font-size": "16px",
"--uma-connect-font-weight": "600",
}}
/>
Alternatively, in raw HTML or a non-react context, you can build the UMA Auth client SDK and import it with a script tag to use the web component implementation:
<script src="../../packages/uma-auth-client/dist/uma-auth-client-web-components.umd.cjs"></script>
<uma-connect-button
app-identity-pubkey="npub1scmpzl2ehnrtnhu289d9rfrwprau9z6ka0pmuhz6czj2ae5rpuhs2l4j9d"
nostr-relay="wss://nos.lol"
redirect-uri="http://localhost:3001"
required-commands="pay_invoice,get_balance"
optional-commands="list_transactions"
budget-amount="500"
budget-currency="USD"
budget-period="monthly"
/>
Users can click their button to move through the flow to connect their wallet. Note that like a normal OAuth flow,
the user will be redirected to their wallet app to sign in, so make sure that you persist important state if needed for
when you're redirected back to the
redirect-uri
.Upon successful connection, connect button element will automatically exchange the authorization code for an access token.
Once the authentication flow is complete, your application will have access to an NWC connection, a list of granted
permissions associated with it, spending limits and other associated authentication data.
To effectively use the NWC connection, check the granted permissions and based on these permissions, determine which
NWC methods you can invoke in your client app. To make an NWC request, you can use the react hook
useNwcRequester
to
send requests to the user's wallet:const { nwcRequester } = useNwcRequester();
const [balance, setBalance] = useState<
Nip47.GetBalanceResponse | undefined
>();
useEffect(() => {
async function fetchBalance(nwcRequester: NwcRequester) {
const res = await nwcRequester.getBalance();
setBalance(res);
}
if (nwcRequester) {
fetchBalance(nwcRequester);
}
}, [nwcRequester]);
In non-react contexts, you can use the
NwcRequester
class directly. For example, to fetch balance, you can call getBalance
.let requester: NwcRequester | null = null;
useOAuth.subscribe((oAuth) => {
if (oAuth.isConnectionValid() && oAuth.nwcConnectionUri && !requester) {
requester = new NwcRequester(oAuth.nwcConnectionUri, oAuth.clearUserAuth, oAuth.oAuthTokenExchange);
requester.getBalance().then((res) => {
console.log("Balance:", res);
});
}
});
For a complete list of NWC methods that the UMA Auth SDK supports, see below. Note that support for these commands will also vary depending
on what the user's wallet supports. See the protocol spec
for descriptions of each NWC method.
getInfo
getBalance
getBudget
payInvoice
payKeysend
makeInvoice
lookupInvoice
listTransactions
lookupUser
fetchQuote
executeQuote
payToAddress
If you prefer not to use the SDK, you can implement the UMA auth protocol manually. This approach gives you more control and flexibility
but requires a deeper understanding of the protocol. See the Manual Implementation of the UMA Auth Protocol guide
for specifications.
The client app SDK provides support for connecting to an NWC relay, making requests and handling expired tokens or connections,
but there may be situations where you would like to initiate NWC payments fron your client app backend, for example, charging a
user for a recurring subscription. The SDK does support this, but it is very important to note that there are a few caveats here.
You would still require your users to go through the connection establishment flow as described in the
Establish an NWC connection section, but instead of using the
NwcRequester
in your client app, you would instead, send the connection details to your backend. The NWC connection string,
access token and refresh token are highly sensitive pieces of information. They provide direct access to a user's wallet and
spending limit. You should treat these with utmost security. To get a user's connection details using the SDK, you can do the following:const { token, nwcConnectionUri, nwcExpiresAt, address } = useOAuth();
if (token && nwcConnectionUri) {
const connectionData = {
accessToken: token.accessToken,
refreshToken: token.refreshToken,
// token expiration (usually short, on the order of a few hours)
expiresAt: token.expiresAt,
permissions: token.commands,
budget: token.budget,
nwcConnectionUri,
// connection expiration (configured by user)
nwcExpiresAt,
// UMA or lightning address
address,
};
// Send connection data to your backend using a secure method
// The refresh token and connection uri specifically provide the holder access
// to spending your user's spending limit if that permission is granted.
// For this reason, you should encrypt these on your backend and follow
// best practices for sensitive data.
} else {
// Handle the case where there user doesn't have an active connection
}
Once you have the NWC connection details on your backend, you can use it to make NWC requests from your backend!
To do so, you may use a Nostr library or implement the protocol yourself using WebSockets. If you would like to use
a library, refer to the "Making NWC Requests" section for recommendations.
Before you make an NWC request, you should ensure that your token is still valid, and if not, refresh your tokens.
You should also check that the connection is not expired. See the OAuth Details
page for more information on how to best handle these.
NOTE: Once you refresh the OAuth token associated with a connection on your backend, you are no longer able to use
the same auth state on your client application since it is rotated on every refresh. You will either need to make NWC
requests from your backend only or have an auth state syncing mechanism between your client application and backend.