Skip to content

Commit

Permalink
feat: add github auth integrate
Browse files Browse the repository at this point in the history
  • Loading branch information
moonrailgun committed Aug 2, 2024
1 parent 03bc9b5 commit 7f7c95b
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 26 deletions.
28 changes: 28 additions & 0 deletions src/client/api/authjs/useAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useUserStore } from '@/store/user';
import { toast } from 'sonner';
import { trpc } from '../trpc';
import { useTranslation } from '@i18next-toolkit/react';
import { BuiltInProviderType } from '@auth/core/providers';

export function useAuth() {
const trpcUtils = trpc.useUtils();
Expand Down Expand Up @@ -38,6 +39,32 @@ export function useAuth() {
}
);

const loginWithOAuth = useEvent(async (provider: BuiltInProviderType) => {
let res: SignInResponse | undefined;
try {
res = await signIn(provider, {
redirect: false,
});
console.log('res', res);
} catch (err) {
toast.error(t('Login failed'));
throw err;
}

if (res?.error) {
toast.error(t('Login failed'));
throw new Error('Login failed');
}

const userInfo = await trpcUtils.user.info.fetch();
if (!userInfo) {
toast.error(t('Can not get current user info'));
throw new Error('Login failed, ');
}

return userInfo;
});

const logout = useEvent(async () => {
await signOut({
redirect: false,
Expand All @@ -49,6 +76,7 @@ export function useAuth() {

return {
loginWithPassword,
loginWithOAuth,
logout,
};
}
1 change: 1 addition & 0 deletions src/client/hooks/useConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const defaultGlobalConfig: AppRouterOutput['global']['config'] = {
allowRegister: false,
alphaMode: false,
disableAnonymousTelemetry: false,
authProvider: [],
};

const callAnonymousTelemetry = once(() => {
Expand Down
23 changes: 20 additions & 3 deletions src/client/routes/login.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { createFileRoute, redirect, useNavigate } from '@tanstack/react-router';
import { useGlobalConfig } from '@/hooks/useConfig';
import { Form, Typography } from 'antd';
import { Divider, Form, Typography } from 'antd';
import { useTranslation } from '@i18next-toolkit/react';
import { setUserInfo } from '@/store/user';
import { z } from 'zod';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { useAuth } from '@/api/authjs/useAuth';
import { useEventWithLoading } from '@/hooks/useEvent';
import { LuGithub } from 'react-icons/lu';

export const Route = createFileRoute('/login')({
validateSearch: z.object({
Expand All @@ -29,7 +30,7 @@ function LoginComponent() {
const { t } = useTranslation();
const search = Route.useSearch();

const { loginWithPassword } = useAuth();
const { loginWithPassword, loginWithOAuth } = useAuth();

const [handleLogin, loading] = useEventWithLoading(async (values: any) => {
const userInfo = await loginWithPassword(values.username, values.password);
Expand All @@ -41,7 +42,7 @@ function LoginComponent() {
replace: true,
});
});
const { allowRegister } = useGlobalConfig();
const { allowRegister, authProvider } = useGlobalConfig();

return (
<div className="flex h-full w-full items-center justify-center dark:bg-gray-900">
Expand Down Expand Up @@ -96,6 +97,22 @@ function LoginComponent() {
</Form.Item>
)}
</Form>

{authProvider.length > 0 && (
<>
<Divider>{t('Or')}</Divider>

<div className="flex justify-center">
<Button
variant="secondary"
className="h-12 w-12 p-3"
onClick={() => loginWithOAuth('github')}
>
<LuGithub size={24} />
</Button>
</div>
</>
)}
</div>
</div>
);
Expand Down
61 changes: 38 additions & 23 deletions src/server/model/auth.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Auth, AuthConfig, createActionURL } from '@auth/core';
import Nodemailer from '@auth/core/providers/nodemailer';
import Credentials from '@auth/core/providers/credentials';
import Github from '@auth/core/providers/github';
import { env } from '../utils/env.js';
import { prisma } from './_client.js';
import type { PrismaClient, Prisma, User } from '@prisma/client';
Expand Down Expand Up @@ -28,7 +29,8 @@ export interface UserAuthPayload {
export const authConfig: Omit<AuthConfig, 'raw'> = {
debug: env.isProd ? false : true,
basePath: '/api/auth',
providers: [
trustHost: true,
providers: _.compact([
Credentials({
id: 'account',
name: 'Account',
Expand All @@ -52,28 +54,41 @@ export const authConfig: Omit<AuthConfig, 'raw'> = {
return toAdapterUser(user);
},
}),
Nodemailer({
id: 'email',
name: 'Email',
...env.auth.email,
async sendVerificationRequest(params) {
const { identifier, url, provider, theme } = params;
const { host } = new URL(url);
const transport = createTransport(provider.server);
const result = await transport.sendMail({
to: identifier,
from: provider.from,
subject: `Sign in Tianji to ${host}`,
text: `Sign in Tianji to ${host}\n${url}\n\n`,
html: nodemailHtmlBody({ url, host, theme }),
});
const failed = result.rejected.concat(result.pending).filter(Boolean);
if (failed.length) {
throw new Error(`Email (${failed.join(', ')}) could not be sent`);
}
},
}),
],
env.auth.provider.includes('email') &&
Nodemailer({
id: 'email',
name: 'Email',
...env.auth.email,
async sendVerificationRequest(params) {
const { identifier, url, provider, theme } = params;
const { host } = new URL(url);
const transport = createTransport(provider.server);
const result = await transport.sendMail({
to: identifier,
from: provider.from,
subject: `Sign in Tianji to ${host}`,
text: `Sign in Tianji to ${host}\n${url}\n\n`,
html: nodemailHtmlBody({ url, host, theme }),
});
const failed = result.rejected.concat(result.pending).filter(Boolean);
if (failed.length) {
throw new Error(`Email (${failed.join(', ')}) could not be sent`);
}
},
}),
env.auth.provider.includes('github') &&
Github({
id: 'github',
name: 'Github',
...env.auth.github,
}),
env.auth.provider.includes('google') &&
Github({
id: 'google',
name: 'Google',
...env.auth.google,
}),
]),
adapter: TianjiPrismaAdapter(prisma),
secret: env.auth.secret,
session: {
Expand Down
2 changes: 2 additions & 0 deletions src/server/trpc/routers/global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const globalRouter = router({
alphaMode: z.boolean(),
disableAnonymousTelemetry: z.boolean(),
customTrackerScriptName: z.string().optional(),
authProvider: z.array(z.string()),
})
)
.query(async ({ input }) => {
Expand All @@ -34,6 +35,7 @@ export const globalRouter = router({
alphaMode: env.alphaMode,
disableAnonymousTelemetry: env.disableAnonymousTelemetry,
customTrackerScriptName: env.customTrackerScriptName,
authProvider: env.auth.provider,
};
}),
});
14 changes: 14 additions & 0 deletions src/server/utils/env.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { v1 as uuid } from 'uuid';
import md5 from 'md5';
import _ from 'lodash';

const jwtSecret =
!process.env.JWT_SECRET ||
Expand All @@ -13,11 +14,24 @@ export const env = {
jwtSecret,
port: Number(process.env.PORT || 12345),
auth: {
provider: _.compact([
!!process.env.EMAIL_SERVER && 'email',
!!process.env.AUTH_GITHUB_ID && 'github',
!!process.env.AUTH_GOOGLE_ID && 'google',
]),
secret: process.env.AUTH_SECRET || md5(jwtSecret),
email: {
server: process.env.EMAIL_SERVER,
from: process.env.EMAIL_FROM,
},
github: {
clientId: process.env.AUTH_GITHUB_ID,
clientSecret: process.env.AUTH_GITHUB_SECRET,
},
google: {
clientId: process.env.AUTH_GOOGLE_ID,
clientSecret: process.env.AUTH_GOOGLE_SECRET,
},
},
allowRegister: checkEnvTrusty(process.env.ALLOW_REGISTER),
allowOpenapi: checkEnvTrusty(process.env.ALLOW_OPENAPI ?? 'true'),
Expand Down

0 comments on commit 7f7c95b

Please sign in to comment.