Passwords
This package from X-Framework gives you fully integrated passwords system, with GraphQL endpoints and customisable emails. This bundle makes use of the original PasswordBundle to allow-it plug-in into your X-stack.
Install
import { XPasswordBundle } from "@bluelibs/x-password-bundle";
// For this to work you need the following: SecurityBundle, ApolloBundle, ApolloSecurityBundle, SecurityMongoBundle, XBundle
kernel.addBundle(new XPasswordBundle());Ensure you have a type user in your graphql, or disable the me query:
type User { _id: ObjectID!}new XPasswordBundle({ graphql: { queries: { me: false, }, },});Emails
We have the following emails setup:
Welcomeonce that user has registeredVerify Emailwhen we want to verify the user's emailForgot Passwordto receive the reset password link on your emailReset Password Confirmationafter you've reset your password you'll get a confirmation.
All these emails can be overriden like this:
Customise
import { IReactEmailTemplate } from "@bluelibs/email-bundle";import { IWelcomeEmailProps } from "@bluelibs/x-password-bundle";
export const CustomWelcomeEmail: IReactEmailTemplate<IWelcomeEmailProps> = ( props) => ( <div> <p>Hello {props.name},</p> Go here: <a href={props.welcomeUrl}>{props.welcomeUrl}</a> <p> Regards, <br /> {props.regardsName} </p> </div>);
new XPasswordBundle({ emails: { templates: { welcome: CustomWelcomeEmail, verifyEmail: "...", forgotPassword: "...", resetPasswordConfirmation: "...", }, },});Registration Flow
- User registers with
firstName,lastName,emailandpassword - We assume that the username will be the email. This can be customised by you.
- If verify email is enabled, the
VerifyEmailwill be sent (ifsendEmailVerification)- After the email gets verified, the
WelcomeEmailis sent (ifsendWelcomeEmailis enabled)
- After the email gets verified, the
- If verify email is disabled and
sendWelcomeEmailis enabled, theWelcomeEmailwill be initially sent.
By default user is able to login without having the email verified. However, using the emails.requiresEmailVerificationBeforeLoggingIn config on the bundle, this will not be an option. The register will return a null token and user cannot login until his email gets verified.
This is done by playing with isEnabled from IUser which doesn't allow the user to login.
After email gets verified, isEnabled is marked as true.
If you later introduce processes of email verification (like when he changes the email, etc) please note that we mark isEnabled to true. So if you have suspended the user and somehow he can request an email verification, be careful.
Urls
You can also modify the paths based on the X-Framework application url:
new XPasswordBundle({ emails: { paths: { welcomePath: "/welcome", resetPasswordPath: "/reset-password/:token", verifyEmailPath: "/verify-email/:token", }, },});Other Configuration
new XPasswordBundle({ emails: { applicationName: "My App"; regardsName: "My App Team"; // Sometimes the email verification can be the welcome one // In that case, don't send an welcome email and customise your email verification one sendEmailVerification: true; sendWelcomeEmail: true; } // Don't allow users with email unverified to login: requiresEmailVerificationBeforeLoggingIn: false,})Mutations
Once you added this bundle, you will see some mutations appearing in your GraphQL docs, these can be toggled on/off using this:
// The configuration is:export interface IXPasswordBundleConfig { graphql: { mutations: { register: boolean; changePassword: boolean; login: boolean; logout: boolean; resetPassword: boolean; forgotPassword: boolean; verifyEmail: boolean; }; };}Custom Registration
By default registration accepts firstName, lastName, email and password. If you have a more complex registration, we recommend disabling register mutation as shown above and implement your own:
input RegisterInput { email: String! password: String! firstName: String! lastName: String!}
type RegisterResponse { token: String}
type Mutation { register(input: RegisterInput!): RegisterResponse}import { IGraphQLContext, InputType } from "@bluelibs/graphql-bundle";import { RegisterInput, XPasswordService } from "@bluelibs/x-password-bundle";
class MyCustomInput extends RegisterInput { age: string;}
function register(_, args: InputType<RegisterInput>, context: IGraphQLContext) { const { input } = args; const xPasswordService = context.container.get(XPasswordService);
const { email, password, firstName, lastName } = input; const { userId, token } = xPasswordService.register({ email, password, firstName, lastName, });
// Do additional operations, call another service with the "age" part. return { token, };}Override Logic
You can modify behavior of your mutation resolvers by creating your own XPasswordService:
import { RegistrationInput, XPasswordService } from "@bluelibs/x-password-bundle";
class MyXPasswordService extends XPasswordService { register(input: RegistrationInput) { // Do your thingie here. // Or you can disable the mutation, and simply implement your own. }}
// ...new XPasswordBundle({ services: { XPasswordService: MyXPasswordService, },});