@lunch-money/developer-docs 2.11.1-preview.9 → 2.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -13
- package/docs/branding-your-app.md +1 -1
- package/manifest.json +0 -101
- package/package.json +3 -3
- package/v2/docs/version-history.md +1 -3
- package/v2/spec/lunch-money-api-v2.yaml +1 -310
- package/docs/oauth/authorization-code.md +0 -80
- package/docs/oauth/concepts.md +0 -46
- package/docs/oauth/development.md +0 -57
- package/docs/oauth/index.md +0 -28
- package/docs/oauth/native-apps.md +0 -26
- package/docs/oauth/oauth-scope-catalog-design.md +0 -370
- package/docs/oauth/register-client.md +0 -51
- package/docs/oauth/review-and-approval.md +0 -57
- package/docs/oauth/scopes.md +0 -104
- package/docs/oauth/security.md +0 -44
- package/docs/oauth/tokens.md +0 -66
- package/docs/oauth/troubleshooting.md +0 -132
- package/v2/images/oauth-authorization-flow.svg +0 -32
- package/v2/images/oauth-token-lifecycle.svg +0 -14
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# Register an OAuth client
|
|
2
|
-
|
|
3
|
-
Before you add OAuth to your application code, register an OAuth client with Lunch Money. The client identifies your application during authorization and tells Lunch Money who is requesting access, where to return the user, and which permissions the application needs.
|
|
4
|
-
|
|
5
|
-
[Register a new OAuth client](/oauth/applications/new) in the Developer Portal when you are ready to begin.
|
|
6
|
-
|
|
7
|
-
> [!NOTE] Development access is owner-only
|
|
8
|
-
> A newly registered client starts in development. Only the Lunch Money user who owns it can authorize it until the client has been reviewed and approved.
|
|
9
|
-
|
|
10
|
-
## Plan the permissions
|
|
11
|
-
|
|
12
|
-
List the Lunch Money features your application will provide, then use the [scope catalog](/oauth/scopes) to choose the smallest complete set of permissions those features require. Select `offline_access` only if the application needs to continue making API requests after the initial access token expires and while the user is away.
|
|
13
|
-
|
|
14
|
-
Scopes cannot be changed after registration. While you are developing your application, creating a replacement client is inexpensive, so let the scope set evolve as you learn what the application needs. Aim to have the application's core functionality—and its required permissions—settled before you submit the client for review.
|
|
15
|
-
|
|
16
|
-
If functionality added after launch needs a scope that is not already registered, you must register a replacement client with the new complete scope set and have it reviewed before rollout. Existing authorizations do not transfer to the replacement client, so users must authorize it before they can use the new functionality. Treat that reauthorization as part of the feature launch: explain what the application can now do with their Lunch Money data and invite them to authorize the replacement client when they want to enable it.
|
|
17
|
-
|
|
18
|
-
## Choose the client type
|
|
19
|
-
|
|
20
|
-
Select the type based on whether your application code can keep a client secret secure:
|
|
21
|
-
|
|
22
|
-
- **Confidential web client:** Choose this when a trusted server can store a client secret, including for applications that are not traditional websites but use a centralized server.
|
|
23
|
-
- **Native or public client:** Choose this for standalone applications installed on a user-controlled device. These clients use PKCE without a client secret. Review the [native application guidance](/oauth/native-apps) before choosing redirects for this type.
|
|
24
|
-
|
|
25
|
-
The client type cannot be changed after registration. See [OAuth concepts](/oauth/concepts#client-types-and-credentials) for more detail about the two types.
|
|
26
|
-
|
|
27
|
-
## Register redirect URIs
|
|
28
|
-
|
|
29
|
-
A redirect URI tells Lunch Money where to return the user after authorization. Register every callback address your application will use. Confidential web clients must match every component of a registered URI, including its scheme, host, port, path, and query string. Native-client loopback redirects use the same exact matching except that the ephemeral port is ignored.
|
|
30
|
-
|
|
31
|
-
Web applications normally use an HTTPS callback. If you need a callback for local development, review the [loopback guidance](/oauth/development#local-loopback-callbacks) before registering one. Mobile and desktop applications may use an app-specific URL scheme or verified HTTPS link accepted by the Developer Portal.
|
|
32
|
-
|
|
33
|
-
## Register the OAuth client
|
|
34
|
-
|
|
35
|
-
Open the [new OAuth client form](/oauth/applications/new) in the Developer Portal. Then:
|
|
36
|
-
|
|
37
|
-
1. Describe the application so Lunch Money users can understand who built it and what it does.
|
|
38
|
-
2. Choose its client type.
|
|
39
|
-
3. Add at least one redirect URI.
|
|
40
|
-
4. Select the planned scopes.
|
|
41
|
-
5. Accept the current Lunch Money API Terms of Use and select **Register OAuth client**.
|
|
42
|
-
|
|
43
|
-
After registration, record the client ID in your application configuration. A client ID identifies the registration but is not a secret.
|
|
44
|
-
|
|
45
|
-
If you registered a **Confidential web client**, create a client secret from its details page. Lunch Money shows the secret value only once. Copy it immediately into a secret manager or protected server configuration; it cannot be retrieved later. Never commit it or expose it in browser or mobile code.
|
|
46
|
-
|
|
47
|
-
A confidential web client can have multiple active secrets. This allows you to introduce a replacement secret, update and verify the deployed application, and then revoke the old secret without interrupting authorization. See [OAuth security guidance](/oauth/security#operate-credentials-safely) when planning ongoing rotation.
|
|
48
|
-
|
|
49
|
-
You now have the client settings needed to connect your application to Lunch Money.
|
|
50
|
-
|
|
51
|
-
Next: [Implement authorization](/oauth/authorization-code).
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
# OAuth client review and approval
|
|
2
|
-
|
|
3
|
-
Every new OAuth client starts in development, where only its owner can authorize it. This gives you time to build and test the application without making an unfinished integration available to other Lunch Money users.
|
|
4
|
-
|
|
5
|
-
When the application is ready, submit its client for review in the Developer Portal. A Lunch Money employee reviews the application information, requested permissions, redirect configuration, and other readiness requirements. Approval moves the client to `active`, allowing other Lunch Money users to authorize the application.
|
|
6
|
-
|
|
7
|
-
## Lifecycle states
|
|
8
|
-
|
|
9
|
-
| State | What it means | Owner action |
|
|
10
|
-
| --- | --- | --- |
|
|
11
|
-
| `development` | The client has not been submitted for review; only its owner can authorize it | Configure and test, then request review. |
|
|
12
|
-
| `pending_review` | Review has been requested and is waiting for or receiving review; review-critical fields are frozen | Continue owner testing or cancel the request. |
|
|
13
|
-
| `active` | The review was approved; other Lunch Money users may authorize the application | Operate within the approved identity and scope set. |
|
|
14
|
-
| `rejected` | Changes were requested | Read feedback, revise editable configuration, and resubmit. |
|
|
15
|
-
| `disabled` | Lunch Money disabled the client; its owner is notified, authorization is unavailable, and existing grants no longer work | Review the reason provided and contact developer support when appropriate. |
|
|
16
|
-
|
|
17
|
-
Deleted clients disappear from the owner's Developer Portal.
|
|
18
|
-
|
|
19
|
-
## Prepare for review
|
|
20
|
-
|
|
21
|
-
Submitting a client for review is how you make your application authorizable by Lunch Money users other than yourself. You can create and test a client with only basic information, but review requires a complete, user-facing application profile and production-ready configuration.
|
|
22
|
-
|
|
23
|
-
Before requesting review, provide:
|
|
24
|
-
|
|
25
|
-
- an application description, developer name, and logo so users can identify the application and who created it;
|
|
26
|
-
- a monitored support email where users and Lunch Money can reach you;
|
|
27
|
-
- a publicly accessible homepage URL where users can learn about the application;
|
|
28
|
-
- a publicly accessible privacy policy URL explaining how the application handles user data;
|
|
29
|
-
- at least one eligible production HTTPS redirect URI;
|
|
30
|
-
- a recognized, supported scope set and an explanation of why the application needs each permission; and
|
|
31
|
-
- acceptance of the current Lunch Money API Terms of Use.
|
|
32
|
-
|
|
33
|
-
Fully test the client before submission. A confidential web client also needs at least one active, non-expired secret; a native or public client does not.
|
|
34
|
-
|
|
35
|
-
Explain which features use each requested permission, how that access benefits users, and why narrower scopes are insufficient. If the client includes `offline_access`, explain why the integration must operate while the user is absent. You may also provide documentation, source-code, and demonstration URLs or context about changes made after earlier feedback.
|
|
36
|
-
|
|
37
|
-
A client may retain owner-only loopback callbacks alongside its production HTTPS callback, but a loopback-only client is not ready for review.
|
|
38
|
-
|
|
39
|
-
## Submit, cancel, or revise
|
|
40
|
-
|
|
41
|
-
Submitting the request moves the client to `pending_review` and temporarily freezes review-critical fields. Reviews are usually completed within a couple of business days. You can continue developing and testing the application as the client owner while you wait. If you need to change a frozen field, cancel the request to return the client to `development`, make the change, and submit it again.
|
|
42
|
-
|
|
43
|
-
Lunch Money emails you when the review is complete. You can also check the current status and review history on the client's page in the Developer Portal.
|
|
44
|
-
|
|
45
|
-
## If review is denied
|
|
46
|
-
|
|
47
|
-
If the review is denied, the Developer Portal shows feedback explaining what needs to change. Update the client's editable configuration and submit a new review request. Editing the client alone does not resubmit it or clear the `rejected` status.
|
|
48
|
-
|
|
49
|
-
There is no review comment thread, so use the new request's additional context to explain how you addressed the feedback. The Portal keeps the earlier request in the client's review history.
|
|
50
|
-
|
|
51
|
-
## After approval
|
|
52
|
-
|
|
53
|
-
An `active` client can be authorized by other users. Reviewed identity fields, redirect configuration, and the registered scope set remain frozen after approval. Client-secret rotation and revocation remain available subject to lifecycle and security checks.
|
|
54
|
-
|
|
55
|
-
For an exceptional identity or configuration change, contact [developer support](mailto:developer-support@lunchmoney.app). A scope change always requires a replacement client and user reauthorization.
|
|
56
|
-
|
|
57
|
-
Next: [Review the security checklist](/oauth/security).
|
package/docs/oauth/scopes.md
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
# OAuth scopes
|
|
2
|
-
|
|
3
|
-
Choose the smallest complete set of permissions your application needs. This page is generated from the published `@lunch-money/v2-api-spec/oauth-scopes` catalog; do not edit it by hand.
|
|
4
|
-
|
|
5
|
-
> [!NOTE] Scopes are fixed when you create a client
|
|
6
|
-
> Authorization requests omit `scope`. To change permissions later, create and review a replacement client, update your integration, and ask every user to authorize it.
|
|
7
|
-
|
|
8
|
-
## Scope groups
|
|
9
|
-
|
|
10
|
-
Groups are selection shortcuts, not extra permissions. A group expands to the exact scopes listed below.
|
|
11
|
-
|
|
12
|
-
### Read only
|
|
13
|
-
|
|
14
|
-
View all supported Lunch Money data without changing it
|
|
15
|
-
|
|
16
|
-
[`me:read`](#scope-me-read), [`summary:read`](#scope-summary-read), [`categories:read`](#scope-categories-read), [`crypto_manual:read`](#scope-crypto-manual-read), [`crypto_synced:read`](#scope-crypto-synced-read), [`balance_history:read`](#scope-balance-history-read), [`manual_accounts:read`](#scope-manual-accounts-read), [`plaid_accounts:read`](#scope-plaid-accounts-read), [`transactions:read`](#scope-transactions-read), [`transaction_attachments:read`](#scope-transaction-attachments-read), [`tags:read`](#scope-tags-read), [`recurring_items:read`](#scope-recurring-items-read), [`budgets:read`](#scope-budgets-read)
|
|
17
|
-
|
|
18
|
-
### Transactions
|
|
19
|
-
|
|
20
|
-
Import, export, organize, and manage transactions and their attachments
|
|
21
|
-
|
|
22
|
-
[`transactions:read`](#scope-transactions-read), [`transactions:create`](#scope-transactions-create), [`transactions:update`](#scope-transactions-update), [`transactions:delete`](#scope-transactions-delete), [`transaction_attachments:read`](#scope-transaction-attachments-read), [`transaction_attachments:create`](#scope-transaction-attachments-create), [`transaction_attachments:delete`](#scope-transaction-attachments-delete), [`categories:read`](#scope-categories-read), [`tags:read`](#scope-tags-read), [`manual_accounts:read`](#scope-manual-accounts-read), [`plaid_accounts:read`](#scope-plaid-accounts-read), [`recurring_items:read`](#scope-recurring-items-read)
|
|
23
|
-
|
|
24
|
-
### Budgeting
|
|
25
|
-
|
|
26
|
-
Analyze and manage budgets, categories, and tags
|
|
27
|
-
|
|
28
|
-
[`summary:read`](#scope-summary-read), [`budgets:read`](#scope-budgets-read), [`budgets:update`](#scope-budgets-update), [`budgets:delete`](#scope-budgets-delete), [`categories:read`](#scope-categories-read), [`categories:create`](#scope-categories-create), [`categories:update`](#scope-categories-update), [`categories:delete`](#scope-categories-delete), [`tags:read`](#scope-tags-read), [`tags:create`](#scope-tags-create), [`tags:update`](#scope-tags-update), [`tags:delete`](#scope-tags-delete), [`recurring_items:read`](#scope-recurring-items-read)
|
|
29
|
-
|
|
30
|
-
### Accounts
|
|
31
|
-
|
|
32
|
-
Manage accounts, balances, and balance history
|
|
33
|
-
|
|
34
|
-
[`manual_accounts:read`](#scope-manual-accounts-read), [`manual_accounts:create`](#scope-manual-accounts-create), [`manual_accounts:update`](#scope-manual-accounts-update), [`manual_accounts:delete`](#scope-manual-accounts-delete), [`plaid_accounts:read`](#scope-plaid-accounts-read), [`plaid_accounts:update`](#scope-plaid-accounts-update), [`crypto_manual:read`](#scope-crypto-manual-read), [`crypto_manual:create`](#scope-crypto-manual-create), [`crypto_manual:update`](#scope-crypto-manual-update), [`crypto_manual:delete`](#scope-crypto-manual-delete), [`crypto_synced:read`](#scope-crypto-synced-read), [`crypto_synced:update`](#scope-crypto-synced-update), [`balance_history:read`](#scope-balance-history-read), [`balance_history:update`](#scope-balance-history-update), [`balance_history:delete`](#scope-balance-history-delete)
|
|
35
|
-
|
|
36
|
-
### Organize
|
|
37
|
-
|
|
38
|
-
Manage categories and tags used to organize transactions
|
|
39
|
-
|
|
40
|
-
[`categories:read`](#scope-categories-read), [`categories:create`](#scope-categories-create), [`categories:update`](#scope-categories-update), [`categories:delete`](#scope-categories-delete), [`tags:read`](#scope-tags-read), [`tags:create`](#scope-tags-create), [`tags:update`](#scope-tags-update), [`tags:delete`](#scope-tags-delete), [`recurring_items:read`](#scope-recurring-items-read)
|
|
41
|
-
|
|
42
|
-
### Full access
|
|
43
|
-
|
|
44
|
-
View and manage all supported Lunch Money data
|
|
45
|
-
|
|
46
|
-
[`me:read`](#scope-me-read), [`me:update`](#scope-me-update), [`summary:read`](#scope-summary-read), [`categories:read`](#scope-categories-read), [`categories:create`](#scope-categories-create), [`categories:update`](#scope-categories-update), [`categories:delete`](#scope-categories-delete), [`crypto_manual:read`](#scope-crypto-manual-read), [`crypto_manual:create`](#scope-crypto-manual-create), [`crypto_manual:update`](#scope-crypto-manual-update), [`crypto_manual:delete`](#scope-crypto-manual-delete), [`crypto_synced:read`](#scope-crypto-synced-read), [`crypto_synced:update`](#scope-crypto-synced-update), [`balance_history:read`](#scope-balance-history-read), [`balance_history:update`](#scope-balance-history-update), [`balance_history:delete`](#scope-balance-history-delete), [`manual_accounts:read`](#scope-manual-accounts-read), [`manual_accounts:create`](#scope-manual-accounts-create), [`manual_accounts:update`](#scope-manual-accounts-update), [`manual_accounts:delete`](#scope-manual-accounts-delete), [`plaid_accounts:read`](#scope-plaid-accounts-read), [`plaid_accounts:update`](#scope-plaid-accounts-update), [`transactions:read`](#scope-transactions-read), [`transactions:create`](#scope-transactions-create), [`transactions:update`](#scope-transactions-update), [`transactions:delete`](#scope-transactions-delete), [`transaction_attachments:read`](#scope-transaction-attachments-read), [`transaction_attachments:create`](#scope-transaction-attachments-create), [`transaction_attachments:delete`](#scope-transaction-attachments-delete), [`tags:read`](#scope-tags-read), [`tags:create`](#scope-tags-create), [`tags:update`](#scope-tags-update), [`tags:delete`](#scope-tags-delete), [`recurring_items:read`](#scope-recurring-items-read), [`budgets:read`](#scope-budgets-read), [`budgets:update`](#scope-budgets-update), [`budgets:delete`](#scope-budgets-delete)
|
|
47
|
-
|
|
48
|
-
## Resource scopes
|
|
49
|
-
|
|
50
|
-
| Scope | What it allows | V2 operations |
|
|
51
|
-
| --- | --- | --- |
|
|
52
|
-
| <a id="scope-me-read"></a>`me:read` | View your Lunch Money identity and account, user, and budget settings | `getMe`, `getAccountSettings`, `getUserSettings`, `getUserAccountSettings` |
|
|
53
|
-
| <a id="scope-me-update"></a>`me:update` | Update your Lunch Money account, user, and budget settings | `updateAccountSettings`, `updateUserSettings`, `updateUserAccountSettings` |
|
|
54
|
-
| <a id="scope-summary-read"></a>`summary:read` | View your budget summary | `getBudgetSummary` |
|
|
55
|
-
| <a id="scope-categories-read"></a>`categories:read` | View categories and category groups | `getAllCategories`, `getCategoryById` |
|
|
56
|
-
| <a id="scope-categories-create"></a>`categories:create` | Create categories and category groups | `createCategory` |
|
|
57
|
-
| <a id="scope-categories-update"></a>`categories:update` | Update categories and category groups | `updateCategory` |
|
|
58
|
-
| <a id="scope-categories-delete"></a>`categories:delete` | Delete categories and category groups | `deleteCategory` |
|
|
59
|
-
| <a id="scope-crypto-manual-read"></a>`crypto_manual:read` | View supported cryptocurrencies and manually managed cryptocurrency balances | `getAllCryptocurrencies`, `getAllCryptoManual`, `getCryptoManualById` |
|
|
60
|
-
| <a id="scope-crypto-manual-create"></a>`crypto_manual:create` | Add supported cryptocurrencies and create manually managed cryptocurrency balances | `createCryptocurrency`, `createCryptoManual` |
|
|
61
|
-
| <a id="scope-crypto-manual-update"></a>`crypto_manual:update` | Update manually managed cryptocurrency balances | `updateCryptoManual` |
|
|
62
|
-
| <a id="scope-crypto-manual-delete"></a>`crypto_manual:delete` | Delete manually managed cryptocurrency balances | `deleteCryptoManual` |
|
|
63
|
-
| <a id="scope-crypto-synced-read"></a>`crypto_synced:read` | View synced cryptocurrency accounts and balances | `getAllCryptoSynced`, `getCryptoSyncedById`, `getCryptoSyncedBalanceBySymbol` |
|
|
64
|
-
| <a id="scope-crypto-synced-update"></a>`crypto_synced:update` | Refresh balances for synced cryptocurrency accounts | `refreshCryptoSynced` |
|
|
65
|
-
| <a id="scope-balance-history-read"></a>`balance_history:read` | View balance history for accounts and synced cryptocurrency balances | `getBalanceHistory`, `getBalanceHistoryForAccount`, `getBalanceHistoryForCryptoSynced` |
|
|
66
|
-
| <a id="scope-balance-history-update"></a>`balance_history:update` | Create or update balance history and details for deleted accounts | `upsertBalanceHistoryForAccount`, `upsertBalanceHistoryForCryptoSynced`, `updateBalanceHistoryDetails` |
|
|
67
|
-
| <a id="scope-balance-history-delete"></a>`balance_history:delete` | Delete balance history for accounts and synced cryptocurrency balances | `deleteBalanceHistoryForAccount`, `deleteBalanceHistoryForCryptoSynced`, `deleteBalanceHistoryEntry` |
|
|
68
|
-
| <a id="scope-manual-accounts-read"></a>`manual_accounts:read` | View manually managed accounts | `getAllManualAccounts`, `getManualAccountById` |
|
|
69
|
-
| <a id="scope-manual-accounts-create"></a>`manual_accounts:create` | Create manually managed accounts | `createManualAccount` |
|
|
70
|
-
| <a id="scope-manual-accounts-update"></a>`manual_accounts:update` | Update manually managed accounts | `updateManualAccount` |
|
|
71
|
-
| <a id="scope-manual-accounts-delete"></a>`manual_accounts:delete` | Delete manually managed accounts | `deleteManualAccount` |
|
|
72
|
-
| <a id="scope-plaid-accounts-read"></a>`plaid_accounts:read` | View accounts connected through Plaid | `getAllPlaidAccounts`, `getPlaidAccountById` |
|
|
73
|
-
| <a id="scope-plaid-accounts-update"></a>`plaid_accounts:update` | Request a Plaid account refresh, which may import new transactions | `triggerPlaidAccountFetch` |
|
|
74
|
-
| <a id="scope-transactions-read"></a>`transactions:read` | View transactions, including split and group information and attachment metadata | `getAllTransactions`, `getTransactionById` |
|
|
75
|
-
| <a id="scope-transactions-create"></a>`transactions:create` | Create transactions | `createNewTransactions` |
|
|
76
|
-
| <a id="scope-transactions-update"></a>`transactions:update` | Update, split, unsplit, group, and ungroup transactions | `updateTransactions`, `updateTransaction`, `groupTransactions`, `ungroupTransactions`, `splitTransaction`, `unsplitTransaction` |
|
|
77
|
-
| <a id="scope-transactions-delete"></a>`transactions:delete` | Delete transactions | `deleteTransactions`, `deleteTransactionById` |
|
|
78
|
-
| <a id="scope-transaction-attachments-read"></a>`transaction_attachments:read` | Get download access to transaction attachments | `getTransactionAttachmentUrl` |
|
|
79
|
-
| <a id="scope-transaction-attachments-create"></a>`transaction_attachments:create` | Attach files to transactions | `attachFileToTransaction` |
|
|
80
|
-
| <a id="scope-transaction-attachments-delete"></a>`transaction_attachments:delete` | Delete transaction attachments | `deleteTransactionAttachment` |
|
|
81
|
-
| <a id="scope-tags-read"></a>`tags:read` | View tags | `getAllTags`, `getTagById` |
|
|
82
|
-
| <a id="scope-tags-create"></a>`tags:create` | Create tags | `createTag` |
|
|
83
|
-
| <a id="scope-tags-update"></a>`tags:update` | Update tags | `updateTag` |
|
|
84
|
-
| <a id="scope-tags-delete"></a>`tags:delete` | Delete tags | `deleteTag` |
|
|
85
|
-
| <a id="scope-recurring-items-read"></a>`recurring_items:read` | View recurring items | `getAllRecurring`, `getRecurringById` |
|
|
86
|
-
| <a id="scope-budgets-read"></a>`budgets:read` | View budget period settings | `getBudgetSettings` |
|
|
87
|
-
| <a id="scope-budgets-update"></a>`budgets:update` | Create or update budget amounts | `upsertBudget` |
|
|
88
|
-
| <a id="scope-budgets-delete"></a>`budgets:delete` | Delete budget amounts | `deleteBudget` |
|
|
89
|
-
|
|
90
|
-
## Continued access
|
|
91
|
-
|
|
92
|
-
<a id="scope-offline-access"></a>
|
|
93
|
-
|
|
94
|
-
### `offline_access`
|
|
95
|
-
|
|
96
|
-
Allow this app to maintain access without asking you to sign in and authorize it again
|
|
97
|
-
|
|
98
|
-
`offline_access` is not permission to a V2 resource. It allows an eligible token response to include a longer-lived, finite refresh token. Your application must still request every resource scope it needs when the client is created.
|
|
99
|
-
|
|
100
|
-
## Find the scope for an endpoint
|
|
101
|
-
|
|
102
|
-
The [V2 API reference](/v2/docs) displays the required OAuth scope for each operation. Scope requirements come from the same catalog and standard OpenAPI security metadata used to generate this page.
|
|
103
|
-
|
|
104
|
-
Next: [Implement the authorization-code flow](/oauth/authorization-code).
|
package/docs/oauth/security.md
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
# OAuth security guidance
|
|
2
|
-
|
|
3
|
-
OAuth gives your application permission to work with a user's Lunch Money data. A few deliberate choices about credential storage, callbacks, logging, and recovery help you protect that access and earn users' trust.
|
|
4
|
-
|
|
5
|
-
Before a client can be approved for use by other Lunch Money users, its application must have a publicly accessible privacy policy. The policy gives users a place to understand how the application handles their data before they authorize it. See [application review and approval](/oauth/review-and-approval) for the complete review requirements.
|
|
6
|
-
|
|
7
|
-
## Protect credentials
|
|
8
|
-
|
|
9
|
-
- Keep confidential-client secrets and refresh tokens on the server and in a secret manager or encrypted credential store.
|
|
10
|
-
- Never put a client secret in browser JavaScript, a mobile binary, a URL, source control, analytics, or a support ticket.
|
|
11
|
-
- Avoid logging authorization codes, access tokens, refresh tokens, session cookies, callback query strings, or secrets.
|
|
12
|
-
- Redact credentials from errors and tracing before data leaves the process.
|
|
13
|
-
- Use HTTPS outside the explicitly supported loopback-development case.
|
|
14
|
-
|
|
15
|
-
## Decide where your web application uses access tokens
|
|
16
|
-
|
|
17
|
-
A web application can keep access tokens on its server and have browser code call its own backend. Where direct browser access to the API is supported, it can instead make access tokens available to browser code and call the Lunch Money API from there. OAuth does not require one architecture for every application.
|
|
18
|
-
|
|
19
|
-
Keeping access tokens on the server reduces their exposure to browser code. Using them in the browser can simplify some applications and makes it easier for the signed-in user or support team to inspect Lunch Money API requests and responses in the browser's Network panel.
|
|
20
|
-
|
|
21
|
-
In the browser-based model, the short-lived access token is also visible to the signed-in user in the request's `Authorization` header. That visibility is expected and is not, by itself, a credential leak. The tradeoff is that a malicious script running on the page—or someone with access to that browser session—could copy the bearer token and use it until it expires or is revoked.
|
|
22
|
-
|
|
23
|
-
If your browser code uses access tokens, keep them available for no longer than necessary, avoid persistent browser storage when practical, and protect the application against cross-site scripting. Regardless of the architecture, keep the client secret and refresh tokens on the server, never put bearer tokens in URLs or logs, and associate each authorization with the correct application user and Lunch Money budgeting account.
|
|
24
|
-
|
|
25
|
-
## Secure authorization and callbacks
|
|
26
|
-
|
|
27
|
-
- Generate unpredictable, session-bound, single-use `state` and verify it before exchanging a code.
|
|
28
|
-
- Use PKCE with `S256` for every authorization.
|
|
29
|
-
- Require an exact registered redirect URI and prevent open redirects behind the callback.
|
|
30
|
-
- Exchange each authorization code once and remove callback parameters from the visible URL.
|
|
31
|
-
- Keep authorization results out of browser history where practical and return `Cache-Control: no-store` for sensitive responses.
|
|
32
|
-
- Launch native authorization in the platform browser, never an embedded WebView.
|
|
33
|
-
|
|
34
|
-
## Minimize authority
|
|
35
|
-
|
|
36
|
-
Choose only the resource scopes needed for expected features. Add `offline_access` only for genuine unattended operation. Remember that scope changes require a replacement client and reauthorization; they cannot be requested dynamically.
|
|
37
|
-
|
|
38
|
-
## Operate credentials safely
|
|
39
|
-
|
|
40
|
-
Rotate client secrets on a schedule appropriate for your application's risk and immediately when one may have been exposed. Use overlapping active secrets during a controlled rotation: create the replacement, deploy and verify it, and then revoke the old secret. Coordinate refreshes so two workers do not replay the same rotating token. Make logout revoke server-side credentials and clear local state.
|
|
41
|
-
|
|
42
|
-
If a credential may have been exposed, stop using it, revoke it, rotate the relevant client secret, review logs without copying secret values, and require reauthorization when the grant can no longer be trusted.
|
|
43
|
-
|
|
44
|
-
Next: [Review token recovery](/oauth/tokens) and [troubleshoot failures](/oauth/troubleshooting).
|
package/docs/oauth/tokens.md
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
# Token lifecycle and recovery
|
|
2
|
-
|
|
3
|
-
Treat expiration, refresh, revocation, and reauthorization as separate events. Your integration should expect every token to stop working eventually.
|
|
4
|
-
|
|
5
|
-

|
|
6
|
-
|
|
7
|
-
Teal boxes show the normal token lifecycle. The amber box marks a terminal failure that requires the user to authorize again.
|
|
8
|
-
|
|
9
|
-
## Determine expiration
|
|
10
|
-
|
|
11
|
-
Access tokens are deliberately short-lived. Record when the token response arrives and add its `expires_in` duration to determine the expected expiry. Refresh slightly before that point while accounting for clock skew. Do not parse the opaque access token or assume a fixed lifetime.
|
|
12
|
-
|
|
13
|
-
## Refresh access
|
|
14
|
-
|
|
15
|
-
A refresh token is issued after a successful authorization-code exchange only when the registered client includes `offline_access`. It lasts longer than an access token, but it is not permanent.
|
|
16
|
-
|
|
17
|
-
Send a form-encoded `grant_type=refresh_token` request to the discovered token endpoint. Confidential clients authenticate with `client_secret_basic`; public clients send their client ID without a secret. A refresh never expands or switches the grant's registered scopes.
|
|
18
|
-
|
|
19
|
-
Persist every replacement refresh token before discarding the previous value, and serialize refreshes for a grant. Lunch Money rotates refresh tokens; replay of a consumed token can invalidate the token family. If refresh fails terminally, delete unusable credentials and start a fresh authorization.
|
|
20
|
-
|
|
21
|
-
## Revoke access
|
|
22
|
-
|
|
23
|
-
Send the token to the discovered revocation endpoint using the authentication method appropriate to the client. Revocation returns success without revealing unnecessary token state. Locally discard the access token, refresh token, and related session state even if the network response is ambiguous.
|
|
24
|
-
|
|
25
|
-
> [!TIP] Revocation endpoint
|
|
26
|
-
> The currently resolved endpoint is `https://api.lunchmoney.dev/oauth/revoke`. Use authorization-server discovery to configure deployed applications so they receive the current endpoint automatically.
|
|
27
|
-
|
|
28
|
-
For a quick development test, the following requests revoke an access token. They assume the values have already been loaded into shell variables from your secure development configuration.
|
|
29
|
-
|
|
30
|
-
:::tabs
|
|
31
|
-
|
|
32
|
-
@tab Confidential web client
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
curl --request POST 'https://api.lunchmoney.dev/oauth/revoke' \
|
|
36
|
-
--user "$LUNCH_MONEY_CLIENT_ID:$LUNCH_MONEY_CLIENT_SECRET" \
|
|
37
|
-
--header 'Content-Type: application/x-www-form-urlencoded' \
|
|
38
|
-
--data-urlencode "token=$LUNCH_MONEY_ACCESS_TOKEN" \
|
|
39
|
-
--data 'token_type_hint=access_token'
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
@tab Native or public client
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
curl --request POST 'https://api.lunchmoney.dev/oauth/revoke' \
|
|
46
|
-
--header 'Content-Type: application/x-www-form-urlencoded' \
|
|
47
|
-
--data-urlencode "client_id=$LUNCH_MONEY_CLIENT_ID" \
|
|
48
|
-
--data-urlencode "token=$LUNCH_MONEY_ACCESS_TOKEN" \
|
|
49
|
-
--data 'token_type_hint=access_token'
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
:::
|
|
53
|
-
|
|
54
|
-
Do not paste a real client secret or token directly into a command where it may be saved in shell history. If the authorization also has a refresh token, revoke or otherwise invalidate it before testing a flow that should require the user to authorize again, then discard both tokens locally.
|
|
55
|
-
|
|
56
|
-
Revocation is different from expiration: expiration ends one credential naturally, while revocation deliberately removes access. Deleting or disabling an application and loss of user access can also make tokens unusable.
|
|
57
|
-
|
|
58
|
-
## Recovery rules
|
|
59
|
-
|
|
60
|
-
- A rejected API request may mean the access token expired, was revoked, lacks the required scope, targets the wrong resource, or no longer maps to an accessible account. The `401` response does not identify which cause applies. Follow the [API failure decision tree](/oauth/troubleshooting#api-failures).
|
|
61
|
-
- Retry once only after a coordinated successful refresh; do not loop on authentication errors.
|
|
62
|
-
- Treat a rejected refresh token as a signal to reauthorize, not as a reason to retry indefinitely.
|
|
63
|
-
- Preserve no fixed lifetime assumption in jobs, queues, or database schemas.
|
|
64
|
-
- Ask the user to authorize again after terminal grant or refresh failure.
|
|
65
|
-
|
|
66
|
-
See [troubleshooting](/oauth/troubleshooting) for error-specific guidance.
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
# Troubleshoot OAuth
|
|
2
|
-
|
|
3
|
-
OAuth problems are usually easiest to resolve once you identify where the flow stopped. An OAuth-related failure can occur in one of three places:
|
|
4
|
-
|
|
5
|
-
- **Authorization and callback:** your application sends the user to Lunch Money to authorize access, then Lunch Money returns the browser to your registered callback.
|
|
6
|
-
- **Token endpoint:** your application exchanges an authorization code for tokens or uses a refresh token to request replacements.
|
|
7
|
-
- **v2 API:** your application presents an access token while making a request for Lunch Money data.
|
|
8
|
-
|
|
9
|
-
When collecting diagnostic details, preserve nonsensitive information such as timestamps and error names, but leave credentials and full callback URLs out of logs and support messages.
|
|
10
|
-
|
|
11
|
-
> [!NOTE] Two error formats
|
|
12
|
-
> OAuth protocol endpoints under `/oauth/` use lower-case OAuth error names such as `invalid_grant`. The v2 API uses the Lunch Money response format, with a `message` and an `errors` array whose entries contain `errMsg`.
|
|
13
|
-
|
|
14
|
-
## Authorization endpoint failures
|
|
15
|
-
|
|
16
|
-
Authorization can fail before your application reaches the token endpoint. Lunch Money may return a lower-case OAuth error such as `invalid_request`, `invalid_scope`, or `access_denied`.
|
|
17
|
-
|
|
18
|
-
When Lunch Money can safely use the registered callback, it redirects the user's browser with an `error`, an optional `error_description`, and the original `state` as query parameters:
|
|
19
|
-
|
|
20
|
-
```text
|
|
21
|
-
https://example.com/oauth/callback?error=access_denied&state=RETURNED_STATE
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
Match on `error` when it is returned, verify `state`, and treat `error_description` as human-readable text that may change.
|
|
25
|
-
|
|
26
|
-
| OAuth error | Likely cause | What to do |
|
|
27
|
-
| --- | --- | --- |
|
|
28
|
-
| `invalid_request` | A required parameter is missing, duplicated, or malformed | Compare the request with discovery metadata; send `response_type=code`, exact redirect URI, `state`, and PKCE `S256` values. |
|
|
29
|
-
| `invalid_scope` | The client does not have a usable registered scope set | Open the client in the [Developer Portal](/oauth/applications) and review its assigned scopes. Registered clients always use that complete set. |
|
|
30
|
-
| `access_denied` | The user declined or the application is unavailable to that user | Treat denial normally. During development, only the owner may authorize; other users require an active approved application. |
|
|
31
|
-
|
|
32
|
-
### Redirect URI mismatch
|
|
33
|
-
|
|
34
|
-
If the redirect URI does not exactly match one registered for the client, Lunch Money cannot safely return the browser to it. Instead, Lunch Money shows an error page explaining that it could not return the user to the application. The page displays `REDIRECT_URI_MISMATCH`, a request or reference ID, a timestamp, and the application name and public client ID when they are available.
|
|
35
|
-
|
|
36
|
-
Ask the user to report those displayed details—not the complete attempted URL, credentials, authorization codes, tokens, cookies, or PKCE values. Open the client in the [Developer Portal](/oauth/applications), find its registered redirect URIs, and compare the complete URL with the value your application sent. The two values must be identical.
|
|
37
|
-
|
|
38
|
-
## Callback validation failures
|
|
39
|
-
|
|
40
|
-
After Lunch Money returns the browser to the registered callback, your application must verify that the returned `state` matches the authorization attempt. A missing, changed, or reused value is a state mismatch detected by your application, not an error reported by Lunch Money. Stop the flow, discard the authorization code, clear the one-time state, and begin again. Never exchange the code.
|
|
41
|
-
|
|
42
|
-
Your application should show the user a safe error message and enough internal reference information for your team to find the failed attempt without exposing the callback URL or its parameters.
|
|
43
|
-
|
|
44
|
-
## Token endpoint failures
|
|
45
|
-
|
|
46
|
-
The token endpoint (`POST /oauth/token`) returns OAuth 2.0 errors rather than the Lunch Money v2 API error format. The error name appears in an `error` field and is always lower case:
|
|
47
|
-
|
|
48
|
-
```json
|
|
49
|
-
{
|
|
50
|
-
"error": "invalid_grant",
|
|
51
|
-
"error_description": "grant request is invalid"
|
|
52
|
-
}
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
Match on `error`. Treat `error_description` as human-readable text that may change; it does not identify the specific cause.
|
|
56
|
-
|
|
57
|
-
| `error` value | Likely cause | What to do |
|
|
58
|
-
| --- | --- | --- |
|
|
59
|
-
| `invalid_client` | Client authentication is missing or wrong, or Lunch Money disabled the client | Confirm that a confidential client uses HTTP Basic with an active secret and that a public native client sends its client ID without a secret. If previously working credentials are still configured correctly, stop requests and contact [developer support](mailto:developer-support@lunchmoney.app). Reauthorizing users will not restore a disabled client. |
|
|
60
|
-
| `invalid_grant` during code exchange | The code expired, was already used, has the wrong PKCE verifier, or does not match the redirect/client | Start a new authorization. Do not retry the same code. |
|
|
61
|
-
| `invalid_grant` during refresh | The refresh token expired, was revoked, was replayed, or the grant is no longer usable | Stop retrying, discard the token set, and ask the user to authorize again. If the error recurs for the same user shortly after a successful refresh, investigate concurrent refreshes before reauthorizing. |
|
|
62
|
-
|
|
63
|
-
An `invalid_grant` response does not distinguish a replayed refresh token from one that expired or is otherwise unknown. Recurrence shortly after a successful refresh is the useful signal: Lunch Money rotates refresh tokens on every use, and replaying a consumed token revokes the entire grant. Serialize refreshes for each grant and persist every replacement before discarding the previous token, as described in [Refresh access](/oauth/tokens#refresh-access).
|
|
64
|
-
|
|
65
|
-
If a successful authorization-code exchange does not include a refresh token, confirm that the client was registered with `offline_access`. If it was not, create a replacement client that includes `offline_access`; test and review it, then reauthorize users. If it was, contact [developer support](mailto:developer-support@lunchmoney.app).
|
|
66
|
-
|
|
67
|
-
## API failures
|
|
68
|
-
|
|
69
|
-
Treat an OAuth `401` as an unknown access-token failure unless a refresh request establishes what happened. When an eligible refresh token is available, attempt one refresh and handle the token endpoint's result, which uses the OAuth format shown above rather than the v2 API format:
|
|
70
|
-
|
|
71
|
-
1. On success, save the replacement tokens and retry the API request once. The access token had merely expired.
|
|
72
|
-
2. On `invalid_grant`, treat the authorization as revoked: mark that user's Lunch Money connection as inactive and discard its tokens. Prompt the user to authorize again the next time they sign in rather than repeatedly interrupting them.
|
|
73
|
-
3. On `invalid_client`, stop requests for every user of the client and contact [developer support](mailto:developer-support@lunchmoney.app). Lunch Money may have disabled the client; retrying or asking users to authorize again will not help.
|
|
74
|
-
|
|
75
|
-
If no eligible refresh token is available, discard the rejected access token and ask the user to authorize again.
|
|
76
|
-
|
|
77
|
-
An OAuth access token can fail because it expired, access was revoked, the client was disabled, the user reauthorized the application, a token was revoked or rotated, or the user lost access to the budgeting account. Every OAuth access-token failure returns the same generic `401` response:
|
|
78
|
-
|
|
79
|
-
```http
|
|
80
|
-
HTTP/1.1 401
|
|
81
|
-
WWW-Authenticate: Bearer error="invalid_token"
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
```json
|
|
85
|
-
{
|
|
86
|
-
"message": "Unauthorized",
|
|
87
|
-
"errors": [
|
|
88
|
-
{
|
|
89
|
-
"errMsg": "Access token does not exist."
|
|
90
|
-
}
|
|
91
|
-
]
|
|
92
|
-
}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
The response does not identify the cause. Follow the refresh-first recovery path above rather than inferring whether the token expired or another event ended access.
|
|
96
|
-
|
|
97
|
-
### Insufficient scope
|
|
98
|
-
|
|
99
|
-
An `insufficient_scope` response cannot be fixed by retrying, refreshing, or asking the user to authorize the existing client again. It means the client was created without all the scopes required for the operation. This applies to development clients as well as approved clients. The only recovery is to [replace the client](#replace-a-client-to-change-scopes).
|
|
100
|
-
|
|
101
|
-
```http
|
|
102
|
-
HTTP/1.1 403
|
|
103
|
-
WWW-Authenticate: Bearer error="insufficient_scope", scope="transactions:read"
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
```json
|
|
107
|
-
{
|
|
108
|
-
"message": "Forbidden",
|
|
109
|
-
"errors": [
|
|
110
|
-
{
|
|
111
|
-
"errMsg": "Required OAuth scope: transactions:read"
|
|
112
|
-
}
|
|
113
|
-
]
|
|
114
|
-
}
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
The `scope` parameter names every scope the endpoint requires, including any the client may already have. It is not a list of only the missing scopes. Check the operation in the [V2 API reference](/v2/docs) or the [scope catalog](/oauth/scopes) to confirm its requirements.
|
|
118
|
-
|
|
119
|
-
### Replace a client to change scopes
|
|
120
|
-
|
|
121
|
-
Adding `scope` to an authorization URL cannot upgrade or narrow a grant. Lunch Money ignores the requested value and uses the client's complete registered scope set. To change scopes, create a replacement client, test all functionality, complete any required review, update the deployed client ID and credentials, and send every existing user through authorization again.
|
|
122
|
-
|
|
123
|
-
## Local callback failures
|
|
124
|
-
|
|
125
|
-
For local development, use a supported loopback host: `localhost`, `127.0.0.1`, or `[::1]`. Matching depends on the client type:
|
|
126
|
-
|
|
127
|
-
- **Native or public client:** The scheme, host, path, and query string must match exactly. The port is ignored for a loopback redirect, so register one URI without a port, such as `http://localhost/callback`, and let the application use the ephemeral port it binds at runtime.
|
|
128
|
-
- **Confidential web client:** Every component, including the port, must match the registered redirect URI exactly.
|
|
129
|
-
|
|
130
|
-
Host matching is exact for both client types: a redirect registered with `127.0.0.1` does not match one sent with `localhost`. The browser must also be able to reach the application on the selected host and port. See [development and loopback guidance](/oauth/development#local-loopback-callbacks).
|
|
131
|
-
|
|
132
|
-
If the safe guidance here does not resolve the problem, contact [developer support](mailto:developer-support@lunchmoney.app) with the client ID, stage, timestamp, and nonsensitive error code. Do not send tokens, secrets, codes, or cookies.
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="1120" height="780" viewBox="0 0 1120 780" role="img" aria-labelledby="title desc">
|
|
2
|
-
<title id="title">Lunch Money OAuth authorization-code flow</title>
|
|
3
|
-
<desc id="desc">A sequence diagram with three actors: your application, the Lunch Money user, and Lunch Money. The application redirects the user's browser to Lunch Money. When necessary, Lunch Money presents its sign-in screen and the user signs in directly with Lunch Money. Lunch Money then presents the budgeting-account selector and requested permissions, the user selects an account and approves access, Lunch Money returns an authorization code, and the application exchanges it for tokens and calls the API.</desc>
|
|
4
|
-
<defs>
|
|
5
|
-
<marker id="app-arrow" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto"><path d="M0,0 L0,6 L9,3 z" fill="#b45309"/></marker>
|
|
6
|
-
<marker id="user-arrow" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto"><path d="M0,0 L0,6 L9,3 z" fill="#9a6700"/></marker>
|
|
7
|
-
<marker id="lm-arrow" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto"><path d="M0,0 L0,6 L9,3 z" fill="#0f766e"/></marker>
|
|
8
|
-
</defs>
|
|
9
|
-
<style>
|
|
10
|
-
.actor{stroke-width:2}.app{fill:#ffedd5;stroke:#b45309}.user{fill:#fef3c7;stroke:#9a6700}.lm{fill:#ccfbf1;stroke:#0f766e}
|
|
11
|
-
.actor-label{font:700 19px system-ui,sans-serif;fill:#172b2a}.actor-detail{font:14px system-ui,sans-serif;fill:#334e4b}
|
|
12
|
-
.lifeline{stroke:#94a3b8;stroke-width:2;stroke-dasharray:7 7}.flow{stroke-width:2.5;fill:none}.app-flow{stroke:#b45309;marker-end:url(#app-arrow)}.user-flow{stroke:#9a6700;marker-end:url(#user-arrow)}.lm-flow{stroke:#0f766e;marker-end:url(#lm-arrow)}
|
|
13
|
-
.step-bg{fill:#fff;stroke:#cbd5e1;stroke-width:1}.step{font:600 14px system-ui,sans-serif;fill:#172b2a}
|
|
14
|
-
</style>
|
|
15
|
-
<rect class="actor app" x="40" y="25" width="260" height="72" rx="12"/>
|
|
16
|
-
<text class="actor-label" x="170" y="56" text-anchor="middle">Your application</text><text class="actor-detail" x="170" y="79" text-anchor="middle">browser route and server</text>
|
|
17
|
-
<rect class="actor user" x="430" y="25" width="260" height="72" rx="12"/>
|
|
18
|
-
<text class="actor-label" x="560" y="56" text-anchor="middle">Lunch Money user</text><text class="actor-detail" x="560" y="79" text-anchor="middle">browser, sign-in, and approval</text>
|
|
19
|
-
<rect class="actor lm" x="820" y="25" width="260" height="72" rx="12"/>
|
|
20
|
-
<text class="actor-label" x="950" y="56" text-anchor="middle">Lunch Money</text><text class="actor-detail" x="950" y="79" text-anchor="middle">authorization server and API</text>
|
|
21
|
-
<path class="lifeline" d="M170 105 V750"/><path class="lifeline" d="M560 105 V750"/><path class="lifeline" d="M950 105 V750"/>
|
|
22
|
-
<path class="flow app-flow" d="M170 140 H550"/><rect class="step-bg" x="278" y="118" width="180" height="28" rx="6"/><text class="step" x="368" y="137" text-anchor="middle">1. Redirect the user</text>
|
|
23
|
-
<path class="flow user-flow" d="M560 200 H940"/><rect class="step-bg" x="652" y="178" width="196" height="28" rx="6"/><text class="step" x="750" y="197" text-anchor="middle">2. Request authorization</text>
|
|
24
|
-
<path class="flow lm-flow" d="M950 260 H570"/><rect class="step-bg" x="640" y="238" width="240" height="28" rx="6"/><text class="step" x="760" y="257" text-anchor="middle">3. Show sign-in, when needed</text>
|
|
25
|
-
<path class="flow user-flow" d="M560 320 H940"/><rect class="step-bg" x="605" y="298" width="290" height="28" rx="6"/><text class="step" x="750" y="317" text-anchor="middle">4. Sign in directly with Lunch Money</text>
|
|
26
|
-
<path class="flow lm-flow" d="M950 380 H570"/><rect class="step-bg" x="590" y="358" width="340" height="28" rx="6"/><text class="step" x="760" y="377" text-anchor="middle">5. Present account and permission choices</text>
|
|
27
|
-
<path class="flow user-flow" d="M560 440 H940"/><rect class="step-bg" x="585" y="418" width="330" height="28" rx="6"/><text class="step" x="750" y="437" text-anchor="middle">6. Select budgeting account and approve</text>
|
|
28
|
-
<path class="flow lm-flow" d="M950 500 H180"/><rect class="step-bg" x="385" y="478" width="360" height="28" rx="6"/><text class="step" x="565" y="497" text-anchor="middle">7. Redirect to callback with authorization code</text>
|
|
29
|
-
<path class="flow app-flow" d="M170 580 H940"/><rect class="step-bg" x="335" y="558" width="460" height="28" rx="6"/><text class="step" x="565" y="577" text-anchor="middle">8. Exchange code with PKCE (+ client secret for confidential client)</text>
|
|
30
|
-
<path class="flow lm-flow" d="M950 640 H180"/><rect class="step-bg" x="385" y="618" width="360" height="28" rx="6"/><text class="step" x="565" y="637" text-anchor="middle">9. Return access token + optional refresh token</text>
|
|
31
|
-
<path class="flow app-flow" d="M170 710 H940"/><rect class="step-bg" x="466" y="688" width="198" height="28" rx="6"/><text class="step" x="565" y="707" text-anchor="middle">10. Call the V2 API</text>
|
|
32
|
-
</svg>
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="990" height="300" viewBox="0 0 990 300" role="img" aria-labelledby="title desc">
|
|
2
|
-
<title id="title">OAuth token lifecycle and recovery</title>
|
|
3
|
-
<desc id="desc">Authorization yields a short-lived access token and, when offline access applies, a finite refresh token. Refresh replaces tokens. Expiration, revocation, or a terminal refresh failure leads to fresh authorization.</desc>
|
|
4
|
-
<defs><marker id="arrow" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto"><path d="M0,0 L0,6 L9,3 z" fill="#0f766e"/></marker></defs>
|
|
5
|
-
<style>.box{fill:#f0f9f8;stroke:#2a6b64;stroke-width:2}.warn{fill:#fff4dc;stroke:#9a6a16;stroke-width:2}.label{font:600 17px system-ui,sans-serif;fill:#173f3b}.small{font:14px system-ui,sans-serif;fill:#294744}.line{stroke:#0f766e;stroke-width:2.5;fill:none;marker-end:url(#arrow)}.annotation-bg{fill:#fff;stroke:#cbd5e1;stroke-width:1}.annotation{font:600 14px system-ui,sans-serif;fill:#172b2a}</style>
|
|
6
|
-
<rect class="box" x="35" y="65" width="180" height="70" rx="12"/><text class="label" x="125" y="94" text-anchor="middle">Authorization</text><text class="small" x="125" y="117" text-anchor="middle">user present</text>
|
|
7
|
-
<rect class="box" x="300" y="35" width="200" height="70" rx="12"/><text class="label" x="400" y="64" text-anchor="middle">Access token</text><text class="small" x="400" y="87" text-anchor="middle">short-lived</text>
|
|
8
|
-
<rect class="box" x="300" y="165" width="200" height="70" rx="12"/><text class="label" x="400" y="194" text-anchor="middle">Refresh token</text><text class="small" x="400" y="217" text-anchor="middle">finite; offline_access</text>
|
|
9
|
-
<rect class="box" x="590" y="100" width="170" height="70" rx="12"/><text class="label" x="675" y="129" text-anchor="middle">Refresh</text><text class="small" x="675" y="152" text-anchor="middle">store replacements</text>
|
|
10
|
-
<rect class="warn" x="790" y="100" width="140" height="70" rx="12"/><text class="label" x="860" y="129" text-anchor="middle">Terminal failure</text><text class="small" x="860" y="152" text-anchor="middle">reauthorize</text>
|
|
11
|
-
<path class="line" d="M215 88 L290 72"/><path class="line" d="M215 112 L290 185"/><path class="line" d="M500 200 L580 150"/><path class="line" d="M760 135 H780"/><path class="line" d="M675 95 C675 25 500 15 470 35"/>
|
|
12
|
-
<rect class="annotation-bg" x="530" y="10" width="170" height="28" rx="6"/><text class="annotation" x="615" y="29" text-anchor="middle">replacement token set</text>
|
|
13
|
-
<rect class="annotation-bg" x="740" y="198" width="240" height="36" rx="6"/><text class="annotation" x="860" y="221" text-anchor="middle">expired, revoked, or rejected</text>
|
|
14
|
-
</svg>
|