Skip to content

Commit af840b2

Browse files
elpntThangHuuVu
andauthoredOct 23, 2022
feat(providers): Add Todoist provider (#5253)
* feat: Add Todoist provider * fix: use openid-client * chore: add Todoist provider to issue template Co-authored-by: Thang Vu <hi@thvu.dev>
1 parent ba89907 commit af840b2

File tree

4 files changed

+96
-0
lines changed

4 files changed

+96
-0
lines changed
 

‎.github/ISSUE_TEMPLATE/2_bug_provider.yml

+1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ body:
6868
- "Slack"
6969
- "Spotify"
7070
- "Strava"
71+
- "Todoist"
7172
- "Trakt"
7273
- "Twitch"
7374
- "Twitter"

‎apps/dev/pages/api/auth/[...nextauth].ts

+2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import Osu from "next-auth/providers/osu"
3030
import Patreon from "next-auth/providers/patreon"
3131
import Slack from "next-auth/providers/slack"
3232
import Spotify from "next-auth/providers/spotify"
33+
import Todoist from "next-auth/providers/todoist"
3334
import Trakt from "next-auth/providers/trakt"
3435
import Twitch from "next-auth/providers/twitch"
3536
import Twitter, { TwitterLegacy } from "next-auth/providers/twitter"
@@ -105,6 +106,7 @@ export const authOptions: NextAuthOptions = {
105106
Patreon({ clientId: process.env.PATREON_ID, clientSecret: process.env.PATREON_SECRET }),
106107
Slack({ clientId: process.env.SLACK_ID, clientSecret: process.env.SLACK_SECRET }),
107108
Spotify({ clientId: process.env.SPOTIFY_ID, clientSecret: process.env.SPOTIFY_SECRET }),
109+
Todoist({ clientId: process.env.TODOIST_ID, clientSecret: process.env.TODOIST_SECRET }),
108110
Trakt({ clientId: process.env.TRAKT_ID, clientSecret: process.env.TRAKT_SECRET }),
109111
Twitch({ clientId: process.env.TWITCH_ID, clientSecret: process.env.TWITCH_SECRET }),
110112
Twitter({ version: "2.0", clientId: process.env.TWITTER_ID, clientSecret: process.env.TWITTER_SECRET }),

‎docs/docs/providers/todoist.md

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
id: todoist
3+
title: Todoist
4+
---
5+
6+
## Documentation
7+
8+
https://developer.todoist.com/guides/#oauth
9+
10+
## Configuration
11+
12+
https://developer.todoist.com/appconsole.html
13+
14+
## Options
15+
16+
The **Todoist Provider** comes with a set of default options:
17+
18+
- [Todoist Provider options](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/providers/todoist.ts)
19+
20+
You can override any of the options to suit your own use case.
21+
22+
## Example
23+
24+
```js
25+
import TodoistProvider from "next-auth/providers/todoist";
26+
27+
...
28+
providers: [
29+
TodoistProvider({
30+
clientId: process.env.TODOIST_ID,
31+
clientSecret: process.env.TODOIST_SECRET
32+
})
33+
]
34+
...
35+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import type { OAuthConfig, OAuthUserConfig } from "."
2+
3+
/**
4+
* @see https://developer.todoist.com/sync/v9/#user
5+
*/
6+
interface TodoistProfile extends Record<string, any> {
7+
avatar_big: string
8+
email: string
9+
full_name: string
10+
id: string
11+
}
12+
13+
export default function TodoistProvider<P extends TodoistProfile>(
14+
options: OAuthUserConfig<P>
15+
): OAuthConfig<P> {
16+
return {
17+
id: "todoist",
18+
name: "Todoist",
19+
type: "oauth",
20+
authorization: {
21+
url: "https://todoist.com/oauth/authorize",
22+
params: { scope: "data:read" },
23+
},
24+
token: "https://todoist.com/oauth/access_token",
25+
client: {
26+
token_endpoint_auth_method: "client_secret_post",
27+
},
28+
userinfo: {
29+
request: async ({ tokens }) => {
30+
// To obtain Todoist user info, we need to call the Sync API
31+
// See https://developer.todoist.com/sync/v9
32+
const res = await fetch("https://api.todoist.com/sync/v9/sync", {
33+
method: "POST",
34+
headers: {
35+
Authorization: `Bearer ${tokens.access_token}`,
36+
"Content-Type": "application/json",
37+
},
38+
body: JSON.stringify({
39+
sync_token: "*",
40+
resource_types: '["user"]',
41+
}),
42+
})
43+
44+
const { user: profile } = await res.json()
45+
return profile
46+
},
47+
},
48+
profile: async (profile) => {
49+
return {
50+
id: profile.id,
51+
email: profile.email,
52+
name: profile.full_name,
53+
image: profile.avatar_big,
54+
}
55+
},
56+
...options,
57+
}
58+
}

1 commit comments

Comments
 (1)
Please sign in to comment.