OAUTH PREVIEW — Create and manage OAuth clients in the Developer PortalStable portal →

Develop and test an OAuth application

Use this guide after you have registered a client and implemented the authorization flow. At this stage, your application should be able to send its owner to Lunch Money, receive an authorization code at its callback, exchange the code for tokens, and make an API request.

The goal now is to test that complete workflow—including its failure and recovery paths—before asking Lunch Money to approve the application for other users.

Development access is owner-only
While an OAuth client is in development, only the Lunch Money user who owns it can authorize the application. Your team should have the developer doing most of the initial Lunch Money work create and own the client so they can test the complete flow with their budget accounts. Other team members cannot authorize the application until the client has been reviewed and approved.

Set up a safe test environment

Use a separate Lunch Money test budget account when exercising create, update, or delete operations. The Getting Started guide walks through creating one and adding sample data.

Keep production client secrets, tokens, and user data out of test fixtures, logs, screenshots, and bug reports.

If you want a working reference flow for comparison, try OAuth with the confidential Node.js sample. Its me:read walkthrough helps validate client registration, exact local callback configuration, discovery, authorization, GET /v2/me, and revocation before you debug application-specific features. Add offline_access when registering the sample client only if you also want to exercise its optional refresh branch.

Local loopback callbacks

When you run a confidential web application on your own computer, its callback handler may not have a public HTTPS address yet. A loopback redirect lets the browser return the authorization result directly to the local process you are developing.

For a client in development, register an HTTP redirect using a supported loopback host and the port and path where your application listens:

You may choose any available port, but the complete redirect URI sent during authorization must match the registered value exactly. localhost and 127.0.0.1 are different hosts, so register the form your application sends. Non-loopback HTTP hosts, embedded credentials, and URI fragments are not supported.

The user's browser—not Lunch Money's server—connects to the loopback listener. Keep PKCE and state protections in place just as you would for a hosted callback. Before requesting review, also register the HTTPS callback used by the deployed application; the loopback URI can remain available for local testing. After approval, you can add or keep a loopback redirect as long as that production HTTPS callback remains. See after approval.

Test an approved client with your development team
After a client is approved, other team members can continue developing and testing the application's Lunch Money functionality. You can add or keep a loopback redirect on the approved client as long as the production HTTPS callback remains. If a loopback redirect is registered, each developer who can run the application locally may authorize access to their own Lunch Money budget account. The client ID is public, but developers working on a confidential web client also need access to its client secret through your team's secure credential-management process. Do not share access tokens or refresh tokens between developers.

Repeat or reset authorization

During development, the client owner can run authorization again whenever they want to repeat the sign-in, budget-account selection, consent, and callback flow. They do not need to revoke the current token first. The authorization server may reuse the current browser login or let the person continue with a different Lunch Money user. Treat the validated /v2/me user/account pair—not previous browser state—as the completed authorization's identity.

To test how the application responds after access is revoked, revoke the current token and make another API request with it. Lunch Money should reject the request, and the application should discard its saved credentials and begin authorization again. The token revocation guide includes copyable curl requests for development testing.

Test the complete client

Test with one Lunch Money user authorizing multiple budget accounts, then with a second Lunch Money user authorizing through the same browser or device. For a client registered with me:read, strictly validate the returned id and account_id after every exchange. Store credentials under the authenticated application user and that Lunch Money user/account pair. For a standalone app without its own accounts, use the Lunch Money user/account pair as the local connection identity.

  1. Complete authorization. For each attempt, your application should create a random state value, save it with the application user's session, and verify that Lunch Money returns the same value to the callback. Rejecting a missing, changed, or reused value prevents a callback started elsewhere from being attached to the wrong session.
  2. Keep the PKCE verifier with that same authorization attempt and use it when exchanging the returned code. Confirm that an exchange with a missing or changed verifier fails; this prevents someone who intercepts the code from using it.
  3. Read the token response's scope field and confirm that it contains the complete scope set registered for the client. Do not inspect or parse the access token itself.
  4. Call every scope-dependent feature, including negative permission cases.
  5. Test user denial, missing or changed state, callback errors, and interrupted authorization attempts. Confirm that denial or a failed /v2/me validation leaves all existing connections unchanged.
  6. Make GET /v2/me fail or return an invalid shape after a successful exchange. Confirm that the application saves no unidentified or partial connection.
  7. Reauthorize an already connected Lunch Money user/account pair. Confirm that the application atomically replaces that connection's credentials, makes it active, and does not create a duplicate.
  8. Authorize as a second Lunch Money user through the same browser or device. Confirm that the previously displayed profile, configuration, saved-budget choices, and cached financial data disappear, while any retained credentials remain hidden.
  9. Return to the first Lunch Money user. Confirm that only that user's retained connections become visible again and that the other user's connections cannot be selected.
  10. Have two different Lunch Money users independently authorize the same shared account_id. Confirm that the application stores separate credentials keyed by Lunch Money user id and account_id, without overwriting either connection.
  11. Give two visible budgets the same budget_name. Confirm that they remain separate by account_id and that the UI disambiguates them only where needed without using the name as a key.
  12. Attempt to select a connection belonging to an inactive Lunch Money user. Confirm that the request is rejected before credentials or cached data are loaded.
  13. Switch the active budget and exercise API calls, refresh, revocation, and local deletion. Confirm that each action and every cache entry affects only the active user/account connection.
  14. Remove the active Lunch Money user's final budget. Confirm that the application enters a disconnected state rather than exposing or selecting another user's hidden connection.
  15. Test remote disconnect and local-only credential deletion separately. Confirm local-only deletion, explain that the remote authorization remains active, and keep unrelated connections unchanged.

Test reauthorization before refresh

First make sure your application can recover without a refresh token. Record when the token response arrives and use expires_in to determine when the access token is expected to expire. After it expires, make a harmless API request and confirm that Lunch Money returns an authentication failure identifying the token as invalid.

Your application should discard the unusable token for that connection and start authorization again. Confirm that the same application user can complete the flow, select the intended budget account, and continue using that connection with the replacement token. This recovery path is required when a client does not have offline_access, and it remains the fallback when a refresh token expires, is revoked, or otherwise stops working. Keep other connections usable while this one recovers.

After reauthorization works, clients registered with offline_access can add and test refresh-token handling. Verify replacement-token storage, concurrent-refresh protection, revocation, and terminal refresh recovery before relying on unattended operation. See token lifecycle and recovery.

Finally, add a production HTTPS redirect and complete the review checklist.

Next: Operate securely.