mirror of
https://github.com/heymoosh/ticktick-quick-add-obsidian.git
synced 2026-07-22 05:43:55 +00:00
Normalize redirect URI to fix OAuth invalid_grant (1.2.3)
TickTick's OAuth server requires byte-exact match between the redirect_uri the plugin sends and the value registered in the developer portal. Users who register the URI with a trailing slash (common on iOS paste, or by hand) get rejected with: error="invalid_grant" error_description="Invalid redirect: ...vercel.app does not match one of the registered values: [...vercel.app/]" (Reported in issue #2.) Normalize the redirect URI by stripping trailing slashes and whitespace at all four use/save sites: - main.ts: startAuthFlow() and exchangeAuthCodeForToken() clean the URI before sending — protects existing users with a slash already saved - settings.ts: both Redirect URI inputs strip on save so the persisted value matches what's displayed - settings.ts: both descriptions now warn against trailing slashes - README: new Troubleshooting entry for the invalid_grant error https://claude.ai/code/session_01V2fsiatACzjUCNwSEhwER9
This commit is contained in:
parent
c036f5ab67
commit
0c25564337
7 changed files with 13 additions and 10 deletions
|
|
@ -114,6 +114,7 @@ After triggering, you'll see a notice confirming the task was created.
|
|||
|
||||
- **"TickTick auth failed: state mismatch"** — the OAuth flow expired or was started in a different session. Tap Connect again and complete the flow without delays.
|
||||
- **"Failed to obtain access token"** — most often a bad Client ID or Secret, or the Redirect URI you set in the TickTick developer portal doesn't exactly match the one in the plugin. Copy/paste both rather than typing.
|
||||
- **`"invalid_grant"` / `"Invalid redirect: ... does not match one of the registered values"`** — the URI registered in the TickTick Developer Portal isn't byte-equal to the one the plugin sends. The most common cause is a trailing `/` in the portal entry. Edit your TickTick app and remove any trailing slash so it matches the plugin's Redirect URI field exactly.
|
||||
- **The Connect popup link does nothing** — make sure your default browser is set and you've allowed Obsidian to open external links. Try long-pressing the link to copy it, then paste into Safari/Chrome.
|
||||
- **Callback page shows the code as text instead of returning to Obsidian** — that's the manual-fallback case. Paste the code into the "Authorization code" field; the plugin will exchange it for a token. (This happens if the callback page hasn't been deployed with the deep-link redirect.)
|
||||
- **The "Open in Obsidian" link in TickTick does nothing** — confirm the Advanced URI plugin is installed and enabled in the same vault.
|
||||
|
|
|
|||
4
main.js
4
main.js
File diff suppressed because one or more lines are too long
4
main.ts
4
main.ts
|
|
@ -236,7 +236,7 @@ export default class TickTickPlugin extends Plugin {
|
|||
new Notice('Please enter your Client ID in the settings.');
|
||||
return;
|
||||
}
|
||||
const redirectUri = this.settings.redirectUri || 'https://ticktick-quick-add-obsidian-6yawfmvnj-mooshs-projects-0635287d.vercel.app';
|
||||
const redirectUri = (this.settings.redirectUri || 'https://ticktick-quick-add-obsidian-6yawfmvnj-mooshs-projects-0635287d.vercel.app').trim().replace(/\/+$/, '');
|
||||
const scope = encodeURIComponent('tasks:read tasks:write');
|
||||
const { codeVerifier, codeChallenge } = await generatePKCECodes();
|
||||
const state = generateRandomString(32);
|
||||
|
|
@ -253,7 +253,7 @@ export default class TickTickPlugin extends Plugin {
|
|||
*/
|
||||
async exchangeAuthCodeForToken(code: string): Promise<void> {
|
||||
const tokenEndpoint = 'https://ticktick.com/oauth/token';
|
||||
const redirectUri = this.settings.redirectUri || 'https://ticktick-quick-add-obsidian-6yawfmvnj-mooshs-projects-0635287d.vercel.app';
|
||||
const redirectUri = (this.settings.redirectUri || 'https://ticktick-quick-add-obsidian-6yawfmvnj-mooshs-projects-0635287d.vercel.app').trim().replace(/\/+$/, '');
|
||||
const clientId = this.settings.clientId;
|
||||
const clientSecret = this.settings.clientSecret;
|
||||
const codeVerifier = this.settings.tempCodeVerifier;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "ticktick-quickadd-task",
|
||||
"name": "TickTick Quick Add Task",
|
||||
"version": "1.2.2",
|
||||
"version": "1.2.3",
|
||||
"minAppVersion": "1.4.0",
|
||||
"description": "Create TickTick tasks from text at your cursor with automatic deep links back to your notes. Requires the Advanced URI plugin.",
|
||||
"author": "Muxin Li",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "ticktick-quickadd-task",
|
||||
"version": "1.2.2",
|
||||
"version": "1.2.3",
|
||||
"description": "Create TickTick tasks from text at your cursor with automatic deep links back to your notes. Requires the Advanced URI plugin.",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
|
|
|||
|
|
@ -89,13 +89,13 @@ export class TickTickSettingTab extends PluginSettingTab {
|
|||
|
||||
new Setting(containerEl)
|
||||
.setName('Redirect URI')
|
||||
.setDesc('Copy this exact value into your TickTick app\'s Redirect URI field in the developer portal. Only change it here if you self-host the callback page.')
|
||||
.setDesc('Copy this exact value into your TickTick app\'s Redirect URI field in the developer portal. Do not add a trailing slash — the URIs must match exactly. Only change it here if you self-host the callback page.')
|
||||
.addText(text =>
|
||||
text
|
||||
.setPlaceholder(DEFAULT_SETTINGS.redirectUri!)
|
||||
.setValue(this.plugin.settings.redirectUri || '')
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.redirectUri = value.trim();
|
||||
this.plugin.settings.redirectUri = value.trim().replace(/\/+$/, '');
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
|
@ -241,11 +241,12 @@ export class TickTickSettingTab extends PluginSettingTab {
|
|||
|
||||
new Setting(details)
|
||||
.setName('Redirect URI')
|
||||
.setDesc('Must match the value registered in your TickTick app exactly, with no trailing slash.')
|
||||
.addText(text =>
|
||||
text
|
||||
.setValue(this.plugin.settings.redirectUri || '')
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.redirectUri = value.trim();
|
||||
this.plugin.settings.redirectUri = value.trim().replace(/\/+$/, '');
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
|
|
|||
|
|
@ -3,5 +3,6 @@
|
|||
"1.1.0": "1.4.0",
|
||||
"1.2.0": "1.4.0",
|
||||
"1.2.1": "1.4.0",
|
||||
"1.2.2": "1.4.0"
|
||||
"1.2.2": "1.4.0",
|
||||
"1.2.3": "1.4.0"
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue