Skip to content

Commit 062f44e

Browse files
committed
feat(auth): Improved NextAuth configuration to include allowed callback domains and custom redirect logic.
1 parent 1f9697d commit 062f44e

5 files changed

Lines changed: 18198 additions & 13472 deletions

File tree

.npmrc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
use-node-version=16.20.0
2+
node-version=16.20.0
3+
engine-strict=false
4+
auto-install-peers=true
15
strict-peer-dependencies=false
26
public-hoist-pattern[]=*prisma*
37
public-hoist-pattern[]=*playwright*

apps/scriptkit/src/lib/get-user-scripts.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,34 @@ export async function getReleases() {
108108
page: 2,
109109
})
110110

111-
releases = [...releaseResponse1.data, ...releaseResponse2.data]
111+
const releaseResponse3 = await octokit.repos.listReleases({
112+
owner: 'johnlindquist',
113+
repo: 'kitapp',
114+
per_page: 100,
115+
page: 3,
116+
})
117+
118+
const releaseResponse4 = await octokit.repos.listReleases({
119+
owner: 'johnlindquist',
120+
repo: 'kitapp',
121+
per_page: 100,
122+
page: 4,
123+
})
124+
125+
const releaseResponse5 = await octokit.repos.listReleases({
126+
owner: 'johnlindquist',
127+
repo: 'kitapp',
128+
per_page: 100,
129+
page: 5,
130+
})
131+
132+
releases = [
133+
...releaseResponse1.data,
134+
...releaseResponse2.data,
135+
...releaseResponse3.data,
136+
...releaseResponse4.data,
137+
...releaseResponse5.data,
138+
]
112139
console.log(`Releases`, releases.length)
113140

114141
return releases
Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import NextAuth, {type NextAuthOptions, Theme} from 'next-auth'
2-
32
import {createOptions} from '@skillrecordings/skill-api'
43
import {NextApiRequest, NextApiResponse} from 'next'
54
import GitHubProvider from 'next-auth/providers/github'
@@ -9,6 +8,33 @@ const productTheme: Theme = {
98
brandColor: '#10172a',
109
}
1110

11+
// Add your allowed callback domains here
12+
const allowedCallbackDomains = [
13+
'scriptkit.com',
14+
'dev-scriptkit.vercel.app',
15+
'staging-scriptkit.vercel.app',
16+
'localhost:3000',
17+
'localhost:3001',
18+
// Add a pattern for dynamic Vercel preview URLs
19+
'script-generator-*.vercel.app',
20+
]
21+
22+
const isAllowedDomain = (url: string) => {
23+
try {
24+
const hostname = new URL(url).hostname
25+
return allowedCallbackDomains.some((domain) => {
26+
// Handle wildcard patterns
27+
if (domain.includes('*')) {
28+
const pattern = domain.replace('*', '.*')
29+
return new RegExp(pattern).test(hostname)
30+
}
31+
return hostname === domain || hostname.endsWith(`.${domain}`)
32+
})
33+
} catch {
34+
return false
35+
}
36+
}
37+
1238
const providers = [
1339
GitHubProvider({
1440
clientId: process.env.GITHUB_ID,
@@ -17,20 +43,29 @@ const providers = [
1743
}),
1844
]
1945

20-
export const nextAuthOptions: NextAuthOptions = createOptions({
21-
theme: productTheme,
22-
})
46+
export const nextAuthOptions: NextAuthOptions = {
47+
...createOptions({
48+
theme: productTheme,
49+
}),
50+
callbacks: {
51+
async redirect({url, baseUrl}: {url: string; baseUrl: string}) {
52+
// First check if it's a relative URL
53+
if (url.startsWith('/')) return `${baseUrl}${url}`
54+
55+
// Then check our allowed domains
56+
if (isAllowedDomain(url)) {
57+
return url
58+
}
59+
60+
// Fall back to base URL
61+
return baseUrl
62+
},
63+
},
64+
}
2365

2466
export default async function NextAuthEndpoint(
2567
req: NextApiRequest,
2668
res: NextApiResponse,
2769
) {
28-
NextAuth(
29-
req,
30-
res,
31-
createOptions({
32-
req,
33-
theme: productTheme,
34-
}),
35-
)
70+
return await NextAuth(req, res, nextAuthOptions)
3671
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import {NextApiRequest, NextApiResponse} from 'next'
2+
import crypto from 'crypto'
3+
4+
const WEBHOOK_SECRET = process.env.GITHUB_WEBHOOK_SECRET
5+
6+
function verifyGithubWebhook(req: NextApiRequest) {
7+
const signature = req.headers['x-hub-signature-256']
8+
if (!signature || !WEBHOOK_SECRET) return false
9+
10+
const hmac = crypto.createHmac('sha256', WEBHOOK_SECRET)
11+
const digest = 'sha256=' + hmac.update(JSON.stringify(req.body)).digest('hex')
12+
return crypto.timingSafeEqual(
13+
Buffer.from(signature as string),
14+
Buffer.from(digest),
15+
)
16+
}
17+
18+
export default async function handler(
19+
req: NextApiRequest,
20+
res: NextApiResponse,
21+
) {
22+
// Only accept POST requests
23+
if (req.method !== 'POST') {
24+
res.setHeader('Allow', 'POST')
25+
return res.status(405).end('Method Not Allowed')
26+
}
27+
28+
// Verify webhook signature
29+
if (!verifyGithubWebhook(req)) {
30+
return res.status(401).json({error: 'Invalid signature'})
31+
}
32+
33+
const event = req.headers['x-github-event']
34+
const payload = req.body
35+
36+
// Handle different webhook events
37+
switch (event) {
38+
case 'installation':
39+
// Handle app installation events
40+
console.log('App installation event:', payload.action)
41+
break
42+
case 'installation_repositories':
43+
// Handle repository installation events
44+
console.log('Repository installation event:', payload.action)
45+
break
46+
// Add more event handlers as needed
47+
}
48+
49+
res.status(200).json({received: true})
50+
}

0 commit comments

Comments
 (0)