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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@rcigroup/horizon-auth-sdk

v0.1.4

Published

Authentication library for RCI Group Horizon applications. Provides Supabase Azure SSO login, protected routes, role-based access control, and pre-built UI components.

Downloads

648

Readme

@rcigroup/horizon-auth-sdk

Authentication library for RCI Group Horizon applications. Provides Supabase Azure SSO login, protected routes, role-based access control, and pre-built UI components.

Installation

npm install @rcigroup/horizon-auth-sdk

Peer Dependencies

These must be installed in your consuming project:

npm install @supabase/supabase-js react-router-dom @rcigroup/horizon-component-sdk react react-dom tailwindcss

| Package | Version | Purpose | |---|---|---| | @supabase/supabase-js | >=2 | Supabase client for authentication | | react-router-dom | >=6 | Routing (used by ProtectedRoute and RequireRole) | | @rcigroup/horizon-component-sdk | >=0.1.0 | UI components (Button, Card, etc.) | | react | >=18 | React | | react-dom | >=18 | React DOM | | tailwindcss | >=4 | Styling |

CSS Setup

In your main CSS file, add these lines so Tailwind picks up the auth SDK's class names and theme:

@import "tailwindcss";
@source "../node_modules/@rcigroup/horizon-auth-sdk/dist";
@import "@rcigroup/horizon-auth-sdk/styles.css";
@source "../node_modules/@rcigroup/horizon-component-sdk/dist";
@import "@rcigroup/horizon-component-sdk/styles.css";

Quick Start

import { createClient } from "@supabase/supabase-js"
import { BrowserRouter, Routes, Route } from "react-router-dom"
import {
  AuthProvider,
  LoginPage,
  LoginDisallowedPage,
  ProtectedRoute,
  RequireRole,
  CurrentUser,
} from "@rcigroup/horizon-auth-sdk"

const supabase = createClient(
  import.meta.env.VITE_SUPABASE_URL,
  import.meta.env.VITE_SUPABASE_ANON_KEY,
)

function App() {
  return (
    <BrowserRouter>
      <AuthProvider config={{ appName: "My App", supabaseClient: supabase }}>
        <Routes>
          {/* Public routes */}
          <Route path="/login" element={<LoginPage />} />
          <Route path="/unauthorized" element={<LoginDisallowedPage />} />

          {/* Protected routes — require authentication */}
          <Route element={<ProtectedRoute />}>
            <Route path="/dashboard" element={<Dashboard />} />
            <Route path="/profile" element={<Profile />} />
          </Route>

          {/* Role-protected routes */}
          <Route element={<RequireRole roles="admin" />}>
            <Route path="/admin" element={<AdminPanel />} />
          </Route>
        </Routes>
      </AuthProvider>
    </BrowserRouter>
  )
}

Components

<AuthProvider>

Root provider that initializes authentication and makes auth state available to all child components via React context. Must wrap your entire application (or at least the parts that use auth).

<AuthProvider config={config}>
  {children}
</AuthProvider>

Config (HorizonAuthConfig)

| Property | Type | Required | Default | Description | |---|---|---|---|---| | appName | string | Yes | — | Application name displayed on the login page as "Welcome to {appName}" | | supabaseClient | SupabaseClient | Yes | — | A configured Supabase client instance created via createClient() | | redirectTo | string | No | window.location.origin | URL to redirect to after a successful OAuth login | | supportContact | string | No | "Contact support to gain access." | Support contact text shown in the login page footer |


<LoginPage>

Full-page login screen with a centered card containing a welcome message, Microsoft SSO button, and support footer.

<LoginPage />
<LoginPage appName="Fleet Manager" supportContact="Email [email protected]" />

Props (LoginPageProps)

| Prop | Type | Required | Default | Description | |---|---|---|---|---| | appName | string | No | Value from AuthProvider config | Override the application name shown in the heading | | supportContact | string | No | "Contact support to gain access." | Override the support text in the footer |


<LoginDisallowedPage>

Full-page "Access Denied" screen shown when an authenticated user lacks permission. Includes a sign-out button and support footer.

<LoginDisallowedPage />
<LoginDisallowedPage
  appName="Fleet Manager"
  message="Your account has not been provisioned."
  supportContact="Email [email protected]"
/>

Props (LoginDisallowedPageProps)

| Prop | Type | Required | Default | Description | |---|---|---|---|---| | appName | string | No | Value from AuthProvider config | Override the application name in the denial message | | message | string | No | "You do not have permission to access {appName}..." | Custom denial message | | supportContact | string | No | "Contact support to gain access." | Override the support text in the footer |


<ProtectedRoute>

Route layout wrapper that requires authentication. Renders child routes when authenticated, redirects to the login page otherwise. Designed for use as a React Router layout route.

{/* As a layout route (recommended) */}
<Route element={<ProtectedRoute />}>
  <Route path="/dashboard" element={<Dashboard />} />
  <Route path="/settings" element={<Settings />} />
</Route>

{/* With direct children */}
<ProtectedRoute>
  <Dashboard />
</ProtectedRoute>

{/* Custom login path */}
<Route element={<ProtectedRoute loginPath="/auth/login" />}>
  <Route path="/dashboard" element={<Dashboard />} />
</Route>

Props (ProtectedRouteProps)

| Prop | Type | Required | Default | Description | |---|---|---|---|---| | loginPath | string | No | "/login" | Path to redirect unauthenticated users to | | loadingFallback | ReactNode | No | Built-in "Loading…" text | Custom component shown while auth state is loading | | children | ReactNode | No | <Outlet /> | Content to render when authenticated. Uses React Router <Outlet /> if omitted |


<RequireRole>

Route layout wrapper that requires the user to have specific role(s). Checks authentication first, then validates roles. Designed for use as a React Router layout route.

Roles are read from user.app_metadata.roles by default. You can provide a custom getRoles function to change this behavior.

{/* Single role */}
<Route element={<RequireRole roles="admin" />}>
  <Route path="/admin" element={<AdminPanel />} />
</Route>

{/* Multiple roles (user needs at least one) */}
<Route element={<RequireRole roles={["admin", "manager"]} />}>
  <Route path="/admin" element={<AdminPanel />} />
</Route>

{/* Custom role extraction */}
<Route element={
  <RequireRole
    roles="editor"
    getRoles={(user) => user.app_metadata?.custom_roles as string[]}
  />
}>
  <Route path="/editor" element={<Editor />} />
</Route>

Props (RequireRoleProps)

| Prop | Type | Required | Default | Description | |---|---|---|---|---| | roles | string \| string[] | Yes | — | Role(s) required. If an array, the user must have at least one | | unauthorizedPath | string | No | "/unauthorized" | Path to redirect users who lack the required role | | getRoles | (user) => string[] | No | Reads user.app_metadata.roles | Custom function to extract roles from the Supabase user object | | loadingFallback | ReactNode | No | Built-in "Loading…" text | Custom component shown while auth state is loading | | children | ReactNode | No | <Outlet /> | Content to render when authorized. Uses React Router <Outlet /> if omitted |


<SignOutButton>

A pre-wired button that triggers sign-out. Accepts all Button props from @rcigroup/horizon-component-sdk (variant, size, className, etc.). Automatically disables itself and shows "Signing out…" while the request is in progress.

<SignOutButton />
<SignOutButton variant="outline" size="sm" />
<SignOutButton label="Log out" variant="ghost" />
<SignOutButton variant="destructive">Leave application</SignOutButton>

Props (SignOutButtonProps)

Inherits all props from Button except onClick.

| Prop | Type | Required | Default | Description | |---|---|---|---|---| | label | string | No | "Sign Out" | Button text. Ignored if children is provided | | variant | string | No | "default" | Button style variant ("default", "outline", "ghost", "destructive") | | size | string | No | "default" | Button size ("default", "sm", "lg", "icon") | | children | ReactNode | No | — | Custom button content (overrides label) | | disabled | boolean | No | false | Disable the button | | className | string | No | — | Additional CSS classes |


<CurrentUser>

Adaptive component that displays the current user's identity when logged in, or a sign-in button when logged out. Useful for headers, navbars, and toolbars.

{/* Default: show email + sign-out button */}
<CurrentUser />

{/* Show full name, hide sign-out */}
<CurrentUser display="fullName" showSignOut={false} />

{/* Show first name with custom labels */}
<CurrentUser display="firstName" signInLabel="Log in" signOutLabel="Log out" />

Props (CurrentUserProps)

| Prop | Type | Required | Default | Description | |---|---|---|---|---| | display | "email" \| "firstName" \| "fullName" | No | "email" | What user info to display when logged in | | showSignOut | boolean | No | true | Whether to show a sign-out button next to the user info | | signInLabel | string | No | "Sign in with Microsoft" | Text for the sign-in button shown when logged out | | signOutLabel | string | No | "Sign Out" | Text for the sign-out button |

The display options:

  • "email" — Shows the user's email address (e.g. [email protected])
  • "firstName" — Shows the first name from user_metadata.full_name (e.g. Jane)
  • "fullName" — Shows the full name from user_metadata.full_name (e.g. Jane Doe)

Hooks

useAuth()

Returns the full auth context. Must be called inside an <AuthProvider>.

const { user, session, isAuthenticated, isLoading, signIn, signOut, appName, supabaseClient } = useAuth()

| Property | Type | Description | |---|---|---| | user | User \| null | Current Supabase user object | | session | Session \| null | Current Supabase session (contains access_token, refresh_token) | | isAuthenticated | boolean | true when a valid session exists | | isLoading | boolean | true while the initial session is being loaded | | signIn | () => Promise<void> | Triggers Azure SSO sign-in (redirects the browser) | | signOut | () => Promise<void> | Signs out the current user | | appName | string | Application name from config | | supabaseClient | SupabaseClient | The Supabase client instance |


useUser()

Returns the current Supabase User object, or null if not authenticated.

const user = useUser()
if (user) console.log(user.email)

useSession()

Returns the current Supabase Session object, or null. The session contains the JWT access token.

const session = useSession()
if (session) {
  fetch("/api/data", {
    headers: { Authorization: `Bearer ${session.access_token}` },
  })
}

useAuthLoading()

Returns true while the initial auth state is being loaded from Supabase. Use this to display loading indicators.

const loading = useAuthLoading()
if (loading) return <Spinner />

useHasRole(roles, getRoles?)

Checks if the current user has at least one of the specified roles.

const isAdmin = useHasRole("admin")
const canEdit = useHasRole(["admin", "editor"])

// Custom role extraction:
const isSuperUser = useHasRole("super", (user) => user.app_metadata?.custom_roles as string[])

| Parameter | Type | Required | Default | Description | |---|---|---|---|---| | roles | string \| string[] | Yes | — | Role(s) to check. Returns true if the user has at least one | | getRoles | (user: User) => string[] | No | Reads user.app_metadata.roles | Custom function to extract roles |


Exported Types

| Type | Description | |---|---| | HorizonAuthConfig | Configuration object for <AuthProvider> | | AuthState | Auth state shape: session, user, isLoading, isAuthenticated | | AuthContextValue | Full context value returned by useAuth() | | LoginPageProps | Props for <LoginPage> | | LoginDisallowedPageProps | Props for <LoginDisallowedPage> | | ProtectedRouteProps | Props for <ProtectedRoute> | | RequireRoleProps | Props for <RequireRole> | | SignOutButtonProps | Props for <SignOutButton> | | CurrentUserProps | Props for <CurrentUser> | | CurrentUserDisplay | Union type: "email" \| "firstName" \| "fullName" | | Session | Re-exported from @supabase/supabase-js | | User | Re-exported from @supabase/supabase-js | | SupabaseClient | Re-exported from @supabase/supabase-js |


Supabase Setup

This library uses Supabase Azure SSO (OAuth with the azure provider). To configure:

  1. Supabase Dashboard → Authentication → Providers → Enable Azure
  2. Azure AD → App registrations → Create a new app → Set the redirect URI to your Supabase project's callback URL (https://<project-ref>.supabase.co/auth/v1/callback)
  3. Role-based access → Set user roles in app_metadata.roles (e.g. ["admin", "editor"]) via the Supabase dashboard or a server-side function

Development

npm run dev          # Run the dev app (Vite)
npm run storybook    # Run Storybook for component previews
npm run build        # Build the library
npm run typecheck    # Type-check
npm run test         # Run tests