npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@thestartupfactory/react-auth

v1.0.9

Published

This library contains standard front end react componets required for auth flow. Flows supported and component included:

Downloads

393

Readme

tsf-react-auth

This library contains standard front end react componets required for auth flow. Flows supported and component included:

  • SignIn

  • Forgot Password

  • Confirm Email

  • Set Password

Usage

The library requires Auth API specified by the caller. The API is used to drive behaviour of the auth componets, as well as ensure the strong typing of the Aith models matching the application where library is used.

The Auth API contract:

signInFn: (details: SignInDetails) => Promise<ResponseState<AUTH_RESPONSE>>;
  requestPasswordResetFn: (
    request: EmailRequest
  ) => Promise<ResponseState<unknown>>;
confirmEmailFn: (
    request: ConfirmEmailRequest
  ) => Promise<ResponseState<unknown>>;
setPasswordFn: (
    request: SetPasswordRequest
  ) => Promise<ResponseState<AUTH_RESPONSE>>;
getAuthFn: () => Promise<ResponseState<AUTH_RESPONSE>>;
signOutFn: () => Promise<unknown>;

The generic type AUTH_RESPONSE must confirm to the signIn and getAuth API functions, is definted by the library user to match the auth model, e.g.:

export const authOutputModel = z.object({
  id: z.string(),
  email: z.string().min(1),
  orgId: z.string(),
  role: role,
  status: activationStatus,
  token: z.string().min(1),
});

export type AuthOutputModel = z.infer<typeof authOutputModel>;

In order to initialize the auth library, use createAuthComponents init function, passing your own AuthAPI implementation, then export the library-provided compoents and hooks:

const authComponents = createAuthComponents({
  signInFn: (details: Auth.signin.Input) =>
    client.provide('post', '/auth', details),
  requestPasswordResetFn: (request: Auth.emailrequest.Input) =>
    client.provide('post', '/auth/passwordreset', request),
  confirmEmailFn: (request: Auth.confirmemail.Input) =>
    client.provide('put', '/auth/emailconfirmation', request),
  setPasswordFn: (request: Auth.resetpassword.Input) =>
    client.provide('put', '/auth/passwordreset', request),
  getAuthFn: () => client.provide('get', '/auth', {}),
  signOutFn: () => client.provide('delete', '/auth', {}),
});

export const useAuth = authComponents.useAuth;
export const AuthProvider = authComponents.AuthProvider;
export const SignIn = authComponents.SignIn;
export const PasswordResetRequest = authComponents.PasswordResetRequest;
export const ConfirmEmail = authComponents.ConfirmEmail;
export const SetPassword = authComponents.SetPassword;

Next, wrap up authenticated routes with the AuthProvider component, to get access to useAuth hook

 {
    path: '/',
    element: <AuthProvider><AuthedRoot /></AuthProvider>),
    errorElement: <ErrorScreen />,
    children: [
      {
        path: '/organizations',
        element: <Organizations.List />,
      },

Next, set up routes for standard auth componet,s such as SignIn, ResetPassword...

const router = createBrowserRouter([
  {
    path: '/p',
    element: <UnauthedRoot />,
    errorElement: <ErrorScreen />,

    children: [
      {
        path: '/p/signin',
        element: authSettingRoute(
          <SignIn />
        ),
        errorElement: <ErrorScreen />,
      },
      {
        path: '/p/passwordresetrequest',
        element: (
          <PasswordResetRequest />
        ),
        errorElement: <ErrorScreen />,
      },
      {
        path: '/p/confirmemail/:token',
        element: <ConfirmEmail />,
        errorElement: <ErrorScreen />,
      },
      {
        path: '/p/setpassword/:token',
        element: <SetPassword/>
        ,
        errorElement: <ErrorScreen />,
      },
    ],
  },

Use useAuth hook to get the current authenticated user in the component - e.g. to render different menus depending of user role or auth status:

  const auth = useAuth();
  const role =
    auth?.user.status === 'success' ? auth.user.data.role : undefined;
  return (
    <>
      <SideBar>
        <img src={logo} alt="Coperceptuo" />
        {role && ['PLATFORM_ADMIN', 'ORG_LEAD'].includes(role) && (
          <StyledNavLink to={`dashboards/`}>Dashboards</StyledNavLink>
        )}

To handle failed authorization (redirecting the user to the SignIn Screen), use AuthAwareFailedRequest component

switch (request.status) {
    case 'loading':
      return <Loading />;
    case 'error':
      return <AuthAwareFailedRequestComponent
        message={message}
        unauthorized={message === 'Unauthorized'}
      />
    case 'success': {
      return <BarChart title={title} data={data} />;
    }
    default:
      return exhaustivenessCheck(request);
  }

Customizing components

Form style and structure

There are a number of React ElementTypes you can pass to the auth componets to override look&feel (not behaviour).

type ComponentOverrides = {
  pageContainer?: React.ElementType;
  formElement?: React.ElementType;
  submitButton?: React.ElementType;
  formRow?: React.ElementType;
  textInput?: React.ElementType;
  contactUsButton?: React.ReactElement;
};

For example, to change the top level container of auth components:

const container = styled.div`
  background-color: yellow;
`;

<SignIn
  components={{
    pageContainer: container,
  }}
/>

Custom extensions

Auth library has come extension points that allow you to add non-auth related behaviour to auth pagee. Currently only one extension is upported - adding a Contact Us button to each page, so that user can ask for help if they have trouble signing in:

const contactUs = (
  <ContactButton darker={false} onClick={() => alert('Contact us')}>
    Contact us
  </ContactButton>
);

<PasswordResetRequest components={{ contactUsButton: contactUs }} />

Navigation behaviour

By default, the library will use redirect strategy to redirect user to sign in page on auth failure or logout. This requires specific auth routes to be set, as descibed in the Usage section above.

You can override this behaviour to use different strategy: rendering sign in component in place in case of auth failure. To do this, provide signinNavStrategy config to the AuthAPI:

const authComponents = createAuthComponents({
  signInFn: (details: Auth.signin.Input) =>
    client.provide('post', '/auth', details),
  requestPasswordResetFn: (request: Auth.emailrequest.Input) =>
    client.provide('post', '/auth/passwordreset', request),
  confirmEmailFn: (request: Auth.confirmemail.Input) =>
    client.provide('put', '/auth/emailconfirmation', request),
  setPasswordFn: (request: Auth.resetpassword.Input) =>
    client.provide('put', '/auth/passwordreset', request),
  getAuthFn: () => client.provide('get', '/auth', {}),
  signOutFn: () => client.provide('delete', '/auth', {}),
  signinNavStrategy:{
    renderSigninScreenInPlace:true
  }
});

In addition, make sure to provide the SignIn component to be rendered when user is not authenticated:

  <AuthProvider
    signInComponent={<SignIn/>}
  >
    {element}
  </AuthProvider>