mirror of
https://github.com/wasp-lang/open-saas.git
synced 2025-04-10 04:49:03 +02:00
Vertical auth (#210)
* Vertically organized auth logic. * Updated opensaas-sh app. * Updated docs.
This commit is contained in:
parent
10b7596f1d
commit
138552d541
@ -47,25 +47,25 @@
|
||||
clientRoute: EmailVerificationRoute,
|
||||
@@ -44,16 +44,14 @@
|
||||
},
|
||||
userSignupFields: import { getEmailUserFields } from "@src/server/auth/userSignupFields",
|
||||
userSignupFields: import { getEmailUserFields } from "@src/auth/userSignupFields",
|
||||
},
|
||||
- // Uncomment to enable Google Auth (check https://wasp-lang.dev/docs/auth/social-auth/google for setup instructions):
|
||||
- // google: { // Guide for setting up Auth via Google
|
||||
- // userSignupFields: import { getGoogleUserFields } from "@src/server/auth/userSignupFields",
|
||||
- // configFn: import { getGoogleAuthConfig } from "@src/server/auth/userSignupFields",
|
||||
- // userSignupFields: import { getGoogleUserFields } from "@src/auth/userSignupFields",
|
||||
- // configFn: import { getGoogleAuthConfig } from "@src/auth/userSignupFields",
|
||||
- // },
|
||||
- // Uncomment to enable GitHub Auth (check https://wasp-lang.dev/docs/auth/social-auth/github for setup instructions):
|
||||
- // gitHub: {
|
||||
- // userSignupFields: import { getGitHubUserFields } from "@src/server/auth/userSignupFields",
|
||||
- // configFn: import { getGitHubAuthConfig } from "@src/server/auth/userSignupFields",
|
||||
- // userSignupFields: import { getGitHubUserFields } from "@src/auth/userSignupFields",
|
||||
- // configFn: import { getGitHubAuthConfig } from "@src/auth/userSignupFields",
|
||||
- // },
|
||||
+ google: {
|
||||
+ userSignupFields: import { getGoogleUserFields } from "@src/server/auth/userSignupFields",
|
||||
+ configFn: import { getGoogleAuthConfig } from "@src/server/auth/userSignupFields",
|
||||
+ userSignupFields: import { getGoogleUserFields } from "@src/auth/userSignupFields",
|
||||
+ configFn: import { getGoogleAuthConfig } from "@src/auth/userSignupFields",
|
||||
+ },
|
||||
+ gitHub: {
|
||||
+ userSignupFields: import { getGitHubUserFields } from "@src/server/auth/userSignupFields",
|
||||
+ configFn: import { getGitHubAuthConfig } from "@src/server/auth/userSignupFields",
|
||||
+ userSignupFields: import { getGitHubUserFields } from "@src/auth/userSignupFields",
|
||||
+ configFn: import { getGitHubAuthConfig } from "@src/auth/userSignupFields",
|
||||
+ },
|
||||
},
|
||||
onAuthFailedRedirectTo: "/login",
|
||||
|
@ -1,14 +1,13 @@
|
||||
--- template/app/src/client/auth/LoginPage.tsx
|
||||
+++ opensaas-sh/app/src/client/auth/LoginPage.tsx
|
||||
@@ -1,8 +1,15 @@
|
||||
-import { LoginForm } from 'wasp/client/auth';
|
||||
--- template/app/src/auth/LoginPage.tsx
|
||||
+++ opensaas-sh/app/src/auth/LoginPage.tsx
|
||||
@@ -1,8 +1,14 @@
|
||||
-import { Link } from 'react-router-dom';
|
||||
+import { LoginForm, useAuth } from 'wasp/client/auth';
|
||||
-import { LoginForm } from 'wasp/client/auth';
|
||||
+import { Redirect, Link } from 'react-router-dom';
|
||||
import { AuthWrapper } from './authWrapper';
|
||||
+import { LoginForm, useAuth } from 'wasp/client/auth';
|
||||
import { AuthPageLayout } from './AuthPageLayout';
|
||||
|
||||
export default function Login() {
|
||||
+
|
||||
+ const { data: user } = useAuth();
|
||||
+
|
||||
+ if (user) {
|
||||
@ -16,5 +15,5 @@
|
||||
+ }
|
||||
+
|
||||
return (
|
||||
<AuthWrapper>
|
||||
<AuthPageLayout>
|
||||
<LoginForm />
|
@ -20,7 +20,7 @@ Setting up your app's authentication is easy with Wasp. In fact, it's already se
|
||||
},
|
||||
```
|
||||
|
||||
The great part is, by defining your auth config in the `main.wasp` file, Wasp manages most of the Auth process for you, including the auth-related database entities for user credentials and sessions, as well as auto-generated client components for your app on the fly (aka AuthUI -- you can see them in the `src/client/auth` folder).
|
||||
The great part is, by defining your auth config in the `main.wasp` file, Wasp manages most of the Auth process for you, including the auth-related database entities for user credentials and sessions, as well as auto-generated client components for your app on the fly (aka AuthUI -- you can see them in use in the `src/auth` folder).
|
||||
|
||||
## Email Verified Auth
|
||||
|
||||
|
@ -62,6 +62,7 @@ If you are using a version of the OpenSaaS template with Wasp `v0.11.x` or below
|
||||
│ ├── client/ # Your client code (React) goes here.
|
||||
│ ├── server/ # Your server code (NodeJS) goes here.
|
||||
│ ├── shared/ # Your shared (runtime independent) code goes here.
|
||||
│ ├── auth/ # All auth-related pages/components and logic.
|
||||
│ ├── file-upload/ # Logic for uploading files to S3.
|
||||
│ └── .waspignore
|
||||
├── .env.server # Dev environment variables for your server code.
|
||||
@ -109,7 +110,6 @@ The `src/client` folder contains the code that runs in the browser. It's a stand
|
||||
└── client
|
||||
├── admin # Admin dashboard pages and components
|
||||
├── app # Your user-facing app that sits behind the paywall/login.
|
||||
├── auth # All auth-related pages and components.
|
||||
├── components # Your shared React components.
|
||||
├── hooks # Your shared React hooks.
|
||||
├── landing-page # Landing page related code
|
||||
@ -127,7 +127,6 @@ All you have to do is define your server-side functions in the `main.wasp` file,
|
||||
|
||||
```sh
|
||||
└── server
|
||||
├── auth # Some small auth-related functions to customize the auth flow.
|
||||
├── payments # Payments utility functions.
|
||||
├── scripts # Scripts to run via Wasp, e.g. database seeding.
|
||||
├── webhooks # The webhook handler for Stripe.
|
||||
|
@ -36,23 +36,23 @@ app OpenSaaS {
|
||||
},
|
||||
emailVerification: {
|
||||
clientRoute: EmailVerificationRoute,
|
||||
getEmailContentFn: import { getVerificationEmailContent } from "@src/server/auth/email",
|
||||
getEmailContentFn: import { getVerificationEmailContent } from "@src/auth/email-and-pass/emails",
|
||||
},
|
||||
passwordReset: {
|
||||
clientRoute: PasswordResetRoute,
|
||||
getEmailContentFn: import { getPasswordResetEmailContent } from "@src/server/auth/email",
|
||||
getEmailContentFn: import { getPasswordResetEmailContent } from "@src/auth/email-and-pass/emails",
|
||||
},
|
||||
userSignupFields: import { getEmailUserFields } from "@src/server/auth/userSignupFields",
|
||||
userSignupFields: import { getEmailUserFields } from "@src/auth/userSignupFields",
|
||||
},
|
||||
// Uncomment to enable Google Auth (check https://wasp-lang.dev/docs/auth/social-auth/google for setup instructions):
|
||||
// google: { // Guide for setting up Auth via Google
|
||||
// userSignupFields: import { getGoogleUserFields } from "@src/server/auth/userSignupFields",
|
||||
// configFn: import { getGoogleAuthConfig } from "@src/server/auth/userSignupFields",
|
||||
// userSignupFields: import { getGoogleUserFields } from "@src/auth/userSignupFields",
|
||||
// configFn: import { getGoogleAuthConfig } from "@src/auth/userSignupFields",
|
||||
// },
|
||||
// Uncomment to enable GitHub Auth (check https://wasp-lang.dev/docs/auth/social-auth/github for setup instructions):
|
||||
// gitHub: {
|
||||
// userSignupFields: import { getGitHubUserFields } from "@src/server/auth/userSignupFields",
|
||||
// configFn: import { getGitHubAuthConfig } from "@src/server/auth/userSignupFields",
|
||||
// userSignupFields: import { getGitHubUserFields } from "@src/auth/userSignupFields",
|
||||
// configFn: import { getGitHubAuthConfig } from "@src/auth/userSignupFields",
|
||||
// },
|
||||
},
|
||||
onAuthFailedRedirectTo: "/login",
|
||||
@ -197,27 +197,27 @@ page LandingPage {
|
||||
//#region Auth Pages
|
||||
route LoginRoute { path: "/login", to: LoginPage }
|
||||
page LoginPage {
|
||||
component: import Login from "@src/client/auth/LoginPage"
|
||||
component: import Login from "@src/auth/LoginPage"
|
||||
}
|
||||
|
||||
route SignupRoute { path: "/signup", to: SignupPage }
|
||||
page SignupPage {
|
||||
component: import { Signup } from "@src/client/auth/SignupPage"
|
||||
component: import { Signup } from "@src/auth/SignupPage"
|
||||
}
|
||||
|
||||
route RequestPasswordResetRoute { path: "/request-password-reset", to: RequestPasswordResetPage }
|
||||
page RequestPasswordResetPage {
|
||||
component: import { RequestPasswordReset } from "@src/client/auth/RequestPasswordReset",
|
||||
component: import { RequestPasswordResetPage } from "@src/auth/email-and-pass/RequestPasswordResetPage",
|
||||
}
|
||||
|
||||
route PasswordResetRoute { path: "/password-reset", to: PasswordResetPage }
|
||||
page PasswordResetPage {
|
||||
component: import { PasswordReset } from "@src/client/auth/PasswordReset",
|
||||
component: import { PasswordResetPage } from "@src/auth/email-and-pass/PasswordResetPage",
|
||||
}
|
||||
|
||||
route EmailVerificationRoute { path: "/email-verification", to: EmailVerificationPage }
|
||||
page EmailVerificationPage {
|
||||
component: import { EmailVerification } from "@src/client/auth/EmailVerification",
|
||||
component: import { EmailVerificationPage } from "@src/auth/email-and-pass/EmailVerificationPage",
|
||||
}
|
||||
//#endregion
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
export function AuthWrapper({children} : {children: ReactNode }) {
|
||||
export function AuthPageLayout({children} : {children: ReactNode }) {
|
||||
return (
|
||||
<div className='flex min-h-full flex-col justify-center pt-10 sm:px-6 lg:px-8'>
|
||||
<div className='sm:mx-auto sm:w-full sm:max-w-md'>
|
@ -1,10 +1,10 @@
|
||||
import { LoginForm } from 'wasp/client/auth';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { AuthWrapper } from './authWrapper';
|
||||
import { LoginForm } from 'wasp/client/auth';
|
||||
import { AuthPageLayout } from './AuthPageLayout';
|
||||
|
||||
export default function Login() {
|
||||
return (
|
||||
<AuthWrapper>
|
||||
<AuthPageLayout>
|
||||
<LoginForm />
|
||||
<br />
|
||||
<span className='text-sm font-medium text-gray-900 dark:text-gray-900'>
|
||||
@ -22,6 +22,6 @@ export default function Login() {
|
||||
</Link>
|
||||
.
|
||||
</span>
|
||||
</AuthWrapper>
|
||||
</AuthPageLayout>
|
||||
);
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
import { SignupForm } from 'wasp/client/auth';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { AuthWrapper } from './authWrapper';
|
||||
import { SignupForm } from 'wasp/client/auth';
|
||||
import { AuthPageLayout } from './AuthPageLayout';
|
||||
|
||||
export function Signup() {
|
||||
return (
|
||||
<AuthWrapper>
|
||||
<AuthPageLayout>
|
||||
<SignupForm />
|
||||
<br />
|
||||
<span className='text-sm font-medium text-gray-900'>
|
||||
@ -15,6 +15,6 @@ export function Signup() {
|
||||
).
|
||||
</span>
|
||||
<br />
|
||||
</AuthWrapper>
|
||||
</AuthPageLayout>
|
||||
);
|
||||
}
|
@ -1,15 +1,15 @@
|
||||
import { VerifyEmailForm } from 'wasp/client/auth';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { AuthWrapper } from './authWrapper';
|
||||
import { VerifyEmailForm } from 'wasp/client/auth';
|
||||
import { AuthPageLayout } from '../AuthPageLayout';
|
||||
|
||||
export function EmailVerification() {
|
||||
export function EmailVerificationPage() {
|
||||
return (
|
||||
<AuthWrapper>
|
||||
<AuthPageLayout>
|
||||
<VerifyEmailForm />
|
||||
<br />
|
||||
<span className='text-sm font-medium text-gray-900'>
|
||||
If everything is okay, <Link to='/login' className='underline'>go to login</Link>
|
||||
</span>
|
||||
</AuthWrapper>
|
||||
</AuthPageLayout>
|
||||
);
|
||||
}
|
@ -1,15 +1,15 @@
|
||||
import { ResetPasswordForm } from 'wasp/client/auth';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { AuthWrapper } from './authWrapper';
|
||||
import { ResetPasswordForm } from 'wasp/client/auth';
|
||||
import { AuthPageLayout } from '../AuthPageLayout';
|
||||
|
||||
export function PasswordReset() {
|
||||
export function PasswordResetPage() {
|
||||
return (
|
||||
<AuthWrapper>
|
||||
<AuthPageLayout>
|
||||
<ResetPasswordForm />
|
||||
<br />
|
||||
<span className='text-sm font-medium text-gray-900'>
|
||||
If everything is okay, <Link to='/login'>go to login</Link>
|
||||
</span>
|
||||
</AuthWrapper>
|
||||
</AuthPageLayout>
|
||||
);
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
import { ForgotPasswordForm } from 'wasp/client/auth';
|
||||
import { AuthPageLayout } from '../AuthPageLayout';
|
||||
|
||||
export function RequestPasswordResetPage() {
|
||||
return (
|
||||
<AuthPageLayout>
|
||||
<ForgotPasswordForm />
|
||||
</AuthPageLayout>
|
||||
);
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import { type GetVerificationEmailContentFn, type GetPasswordResetEmailContentFn } from "wasp/server/auth";
|
||||
import { type GetVerificationEmailContentFn, type GetPasswordResetEmailContentFn } from 'wasp/server/auth';
|
||||
|
||||
export const getVerificationEmailContent: GetVerificationEmailContentFn = ({ verificationLink }) => ({
|
||||
subject: 'Verify your email',
|
||||
@ -16,4 +16,4 @@ export const getPasswordResetEmailContent: GetPasswordResetEmailContentFn = ({ p
|
||||
<p>Click the link below to reset your password</p>
|
||||
<a href="${passwordResetLink}">Reset password</a>
|
||||
`,
|
||||
});
|
||||
});
|
@ -1,5 +1,5 @@
|
||||
import { defineUserSignupFields } from 'wasp/auth/providers/types';
|
||||
import { z } from 'zod';
|
||||
import { defineUserSignupFields } from 'wasp/auth/providers/types';
|
||||
|
||||
const adminEmails = process.env.ADMIN_EMAILS?.split(',') || [];
|
||||
|
@ -1,10 +0,0 @@
|
||||
import { ForgotPasswordForm } from 'wasp/client/auth';
|
||||
import { AuthWrapper } from './authWrapper';
|
||||
|
||||
export function RequestPasswordReset() {
|
||||
return (
|
||||
<AuthWrapper>
|
||||
<ForgotPasswordForm />
|
||||
</AuthWrapper>
|
||||
);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user