Skip to content

Commit b13cb2c

Browse files
committed
Add email OTP auth & update dev configs
1 parent a38f6ff commit b13cb2c

15 files changed

Lines changed: 66 additions & 23 deletions

File tree

apps/api/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"lint": "eslint src/",
1010
"test": "bun test --ignore='src/e2e*.test.ts'",
1111
"test:e2e": "bun test src/e2e.test.ts src/e2e-http.test.ts",
12-
"dev": "bun run src/index.ts"
12+
"dev": "bun --env-file=../../.env --watch run src/index.ts"
1313
},
1414
"dependencies": {
1515
"@effect/platform": "^0.94.5",

apps/api/src/auth-client.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { createAuthClient } from 'better-auth/client'
2-
import { organizationClient, apiKeyClient } from 'better-auth/client/plugins'
2+
import { organizationClient, apiKeyClient, emailOTPClient } from 'better-auth/client/plugins'
33

44
export const authClient = createAuthClient({
5-
plugins: [organizationClient(), apiKeyClient()],
5+
plugins: [organizationClient(), apiKeyClient(), emailOTPClient()],
66
})

apps/api/src/auth.ts

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,33 @@
11
import { betterAuth } from 'better-auth'
2-
import { organization, apiKey } from 'better-auth/plugins'
2+
import { organization, apiKey, emailOTP } from 'better-auth/plugins'
33
import { createPool } from 'mysql2/promise'
4+
import { Resend } from 'resend'
5+
6+
const resend = new Resend(process.env.RESEND_API_KEY!)
47

58
export const auth = betterAuth({
9+
baseURL: process.env.BETTER_AUTH_BASE_URL ?? 'http://localhost:3000',
610
database: createPool({
711
uri: process.env.DATABASE_URL!,
812
waitForConnections: true,
913
connectionLimit: 10,
1014
}),
11-
emailAndPassword: { enabled: true },
12-
socialProviders: {
13-
github: {
14-
clientId: process.env.GITHUB_CLIENT_ID!,
15-
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
16-
},
17-
google: {
18-
clientId: process.env.GOOGLE_CLIENT_ID!,
19-
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
20-
},
21-
},
2215
plugins: [
2316
organization(),
2417
apiKey({
2518
enableMetadata: true,
2619
}),
20+
emailOTP({
21+
otpLength: 6,
22+
expiresIn: 300,
23+
async sendVerificationOTP({ email, otp, type }) {
24+
await resend.emails.send({
25+
from: process.env.RESEND_FROM_EMAIL ?? 'Sandchest Auth <noreply@send.sandchest.com>',
26+
to: email,
27+
subject: type === 'sign-in' ? `Your Sandchest login code: ${otp}` : `Your Sandchest verification code: ${otp}`,
28+
text: `Your code is ${otp}. It expires in 5 minutes.`,
29+
})
30+
},
31+
}),
2732
],
2833
})

apps/api/src/server.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { HttpApp, HttpRouter, HttpServer } from '@effect/platform'
1+
import { HttpRouter, HttpServer, HttpServerRequest, HttpServerResponse } from '@effect/platform'
22
import { Effect } from 'effect'
33
import { auth } from './auth.js'
44
import { formatApiError } from './errors.js'
@@ -15,7 +15,12 @@ import { ArtifactRouter } from './routes/artifacts.js'
1515
import { NodeRouter } from './routes/nodes.js'
1616
import { DocsRouter } from './routes/docs.js'
1717

18-
const betterAuthApp = HttpApp.fromWebHandler((request: Request) => auth.handler(request))
18+
const handleBetterAuth = Effect.gen(function* () {
19+
const req = yield* HttpServerRequest.HttpServerRequest
20+
const webReq = yield* HttpServerRequest.toWeb(req)
21+
const webRes = yield* Effect.tryPromise(() => auth.handler(webReq))
22+
return yield* Effect.succeed(HttpServerResponse.fromWeb(webRes))
23+
})
1924

2025
export const ApiRouter = HttpRouter.empty.pipe(
2126
HttpRouter.concat(HealthRouter),
@@ -26,7 +31,8 @@ export const ApiRouter = HttpRouter.empty.pipe(
2631
HttpRouter.concat(ArtifactRouter),
2732
HttpRouter.concat(NodeRouter),
2833
HttpRouter.concat(DocsRouter),
29-
HttpRouter.mountApp('/api/auth', betterAuthApp, { includePrefix: true }),
34+
HttpRouter.all('/api/auth/*', handleBetterAuth),
35+
HttpRouter.all('/api/auth', handleBetterAuth),
3036
HttpRouter.catchAll((error) => Effect.succeed(formatApiError(error))),
3137
)
3238

apps/web/next-env.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/// <reference types="next" />
2+
/// <reference types="next/image-types/global" />
3+
/// <reference path="./.next/types/routes.d.ts" />
4+
5+
// NOTE: This file should not be edited
6+
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

apps/web/src/app/verify/page.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { Suspense } from 'react'
33
import AuthLayout from '@/components/AuthLayout'
44
import VerifyOtpForm from '@/components/auth/VerifyOtpForm'
55

6+
export const dynamic = 'force-dynamic'
7+
68
export const metadata: Metadata = {
79
title: 'Verify — Sandchest',
810
}

apps/web/src/lib/format.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ export {
44
formatDuration,
55
formatCmd,
66
formatBytes,
7-
} from '@sandchest/contract'
7+
} from '@sandchest/contract/format'

apps/web/src/lib/validation.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export { isValidEmail, isValidOtp } from '@sandchest/contract'
1+
export { isValidEmail, isValidOtp } from '@sandchest/contract/validation'

bun.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"lint": "turbo lint",
1212
"test": "turbo test",
1313
"test:e2e": "turbo test:e2e",
14-
"dev": "bun run --filter @sandchest/api dev",
14+
"dev": "turbo run dev",
1515
"db:generate": "bun run --filter @sandchest/db db:generate",
1616
"db:push": "bun run --filter @sandchest/db db:push",
1717
"db:migrate": "bun run --filter @sandchest/db db:migrate",

0 commit comments

Comments
 (0)