SSO (Single Sign-On) components, hooks, and utilities for React
npm install @famgia/omnify-react-ssoSSO (Single Sign-On) schemas, types, React hooks, components, and utilities for Omnify Console integration.
``bash`
npm install @famgia/omnify-react-ssoor
pnpm add @famgia/omnify-react-sso
- React Hooks: useSso(), useAuth(), useOrganization() for SSO state managementSsoProvider
- React Components: , SsoCallback, OrganizationSwitcher, ProtectedRoute@omnify-base
- SSO Services: Individual services for auth, roles, permissions, branches, teams
- SSO Schemas: User, Role, Permission, Branch, Team with Zod validation and i18n
- Bundled Types: types included - no extra setup needed
- Multi-locale Support: Japanese and English labels/messages
- Query Keys: Pre-defined TanStack Query keys for SSO data
- Test Utilities: Mock factories and helpers for testing
`tsx
// 1. Wrap your app with SsoProvider
import { SsoProvider } from '@famgia/omnify-react-sso';
function App() {
return (
consoleUrl: process.env.NEXT_PUBLIC_SSO_URL,
loginPath: '/login',
callbackPath: '/sso/callback',
}}>
);
}
// 2. Use hooks in your components
import { useSso } from '@famgia/omnify-react-sso';
function Dashboard() {
const { user, isAuthenticated, currentOrg, logout } = useSso();
if (!isAuthenticated) return
return (
// 3. Import types directly from package
import type { Role, Permission, Branch, User } from '@famgia/omnify-react-sso';
`
---
> β CRITICAL: DO NOT MODIFY THIS BUILD PROCESS
>
> Quy trΓ¬nh build nΓ y ΔΓ£ Δược thiαΊΏt kαΊΏ vΓ test kα»Ή lΖ°α»‘ng. TUYα»T Δα»I KHΓNG ΔΖ―α»’C THAY Δα»I cΓ‘c bΖ°α»c sau:
> 1. build:schemas - Fetch vΓ generate TypeScript tα»« YAMLbuild:lib
> 2. - Bundle vα»i tsupbuild:copy-base
> 3. - Copy @omnify-base vΓ o dist (QUAN TRα»NG cho TypeScript consumers)postinstall
> 4. - Tα»± Δα»ng tαΊ‘o @omnify-base cho consumers
>
> NαΊΏu thay Δα»i, TypeScript consumers sαΊ½ khΓ΄ng resolve Δược types!
This package bundles SSO schemas from the Laravel backend (omnify-client-laravel-sso) into a self-contained npm package. Consumers don't need to generate schemas - everything is included.
``
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Source: omnify-client-laravel-sso β
β database/schemas/Sso/*.yaml β
β (Branch, Permission, Role, Team, User, etc.) β
βββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββ
β
βΌ pnpm build
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Package: @famgia/omnify-react-sso β
β β
β dist/ β
β βββ index.js (hooks, components, services) β
β βββ index.d.ts (type definitions) β
β βββ schemas/ (bundled SSO schemas) β
β βββ testing/ (test utilities) β
β βββ @omnify-base/ (bundled for TypeScript consumers) β
βββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββ
β
βΌ npm install
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Consumer App (Boilerplate, etc.) β
β β
β import { useSso, Role, Permission } from '@famgia/...' β
β // Everything just works - no schema generation needed! β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
1. Node.js 18+ and pnpm
2. SSH Access to git@github.com:omnifyjp/omnify-client-laravel-sso.gitssh -T git@github.com
3. Test SSH:
| Command | Description |
| ---------------------- | -------------------------------------------- |
| pnpm build | Full build (schemas β types β bundle β copy) |pnpm build:schemas
| | Fetch schemas and generate TypeScript types |pnpm build:lib
| | Bundle with tsup (requires schemas) |pnpm build:copy-base
| | Copy @omnify-base to dist for consumers |pnpm test
| | Run all tests |pnpm typecheck
| | Type check without emitting |
``
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β pnpm build β
β "pnpm build:schemas && pnpm build:lib && pnpm build:copy-base" β
βββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββΌββββββββββββββββββββ
βΌ βΌ βΌ
βββββββββββββββββ βββββββββββββββββ βββββββββββββββββββββββββ
β build:schemas β β build:lib β β build:copy-base β
β β β β β β
β 1. Clean β β 1. tsup β β cp -r node_modules/ β
β - schemas/ β β bundle β β @omnify-base dist/ β
β - src/ β β β β β
β schemas/ β β 2. Generate β β β οΈ CRITICAL STEP! β
β β β .d.ts β β Without this, TS β
β 2. Get YAML β β β β consumers can't β
β schemas β β 3. Output: β β resolve types β
β (local or β β dist/*.js β β β
β git clone) β β dist/*.d.tsβ β β
β β β β β β
β 3. omnify β β β β β
β generate β β β β β
β --types- β β β β β
β only β β β β β
βββββββββββββββββ βββββββββββββββββ βββββββββββββββββββββββββ
β β β
βββββββββββββββββββββΌββββββββββββββββββββ
βΌ
dist/ (complete)
βββ index.js
βββ index.d.ts
βββ schemas/
βββ testing/
βββ @omnify-base/ β TypeScript types
#### Step 1: pnpm build:schemas (scripts/build-schemas.ts)
`typescript
// 1. Clean previous builds
rm -rf schemas/ src/schemas/ src/enum/
// 2. Obtain SSO schema YAML files
if (exists('../omnify-client-laravel-sso/database/schemas/Sso')) {
// Local copy (fastest)
cp -r ../omnify-client-laravel-sso/database/schemas/Sso β schemas/
} else {
// Git clone (fallback)
git clone --sparse git@github.com:omnifyjp/omnify-client-laravel-sso.git
git sparse-checkout set database/schemas/Sso
cp schemas...
}
// 3. Generate TypeScript from YAML
npx omnify generate --types-only
// Creates:
// - node_modules/@omnify-base/schemas/*.ts
// - src/schemas/*.ts
`
#### Step 2: pnpm build:lib (tsup)
`typescript`
// tsup.config.ts
export default defineConfig({
entry: {
index: 'src/index.ts',
'schemas/index': 'src/schemas/index.ts',
'testing/index': 'src/testing/index.ts',
},
format: ['esm', 'cjs'],
dts: true, // Generate .d.ts
clean: true, // Clean dist/ first
external: ['zod', 'react', ...], // Don't bundle these
noExternal: [/@omnify-base\/.*/], // Bundle @omnify-base JS
});
Important: noExternal: [/@omnify-base\/.*/] bundles the JavaScript, but .d.ts files still reference @omnify-base externally.
#### Step 3: pnpm build:copy-base
`bash`
cp -r node_modules/@omnify-base dist/
Why this is critical:
- The generated .d.ts files contain: export { User } from '@omnify-base/schemas/User'@omnify-base
- TypeScript in consumer apps needs to resolve Cannot find module '@omnify-base/...'
- Without this step, consumers get:
#### Postinstall Script (scripts/postinstall.cjs)
When consumers install the package, this script copies @omnify-base to their node_modules:
`javascript`
// Runs automatically after npm install
// Copies dist/@omnify-base β node_modules/@omnify-base
// This allows TypeScript to resolve the types
`bashOption A: Build with auto-fetch (requires SSH access)
pnpm install
pnpm build
$3
| Scenario | Action |
| -------------------------------- | ------------------------------------------- |
| First time setup |
pnpm build |
| Schema YAML changed in Laravel | pnpm build |
| Added new hook/component/service | pnpm build:lib |
| Before publishing to npm | pnpm build && pnpm test |
| After pnpm install | Usually not needed (postinstall handles it) |$3
`bash
1. Ensure you're on main branch
git checkout main && git pull2. Full build
pnpm build3. Run tests
pnpm test4. Type check
pnpm typecheck5. Bump version
npm version patch # or minor/major6. Publish
npm publish --access public7. Verify on npm
npm view @famgia/omnify-react-sso
`---
π¦ Package Contents
After build,
dist/ contains:`
dist/
βββ index.js # Main entry (ESM)
βββ index.cjs # Main entry (CJS)
βββ index.d.ts # Type definitions
βββ schemas/
β βββ index.js # SSO schemas bundle
β βββ index.d.ts
βββ testing/
β βββ index.js # Test utilities
β βββ index.d.ts
βββ @omnify-base/ # Bundled types for TS resolution
β βββ package.json
β βββ schemas/
β βββ User.ts
β βββ Role.ts
β βββ Permission.ts
β βββ Branch.ts
β βββ Team.ts
β βββ ...
βββ types-*.d.ts # Internal type chunks
`---
Local Development with Boilerplate
$3
`bash
In boilerplate/frontend
pnpm add @famgia/omnify-react-sso@latest
`The postinstall script automatically sets up
@omnify-base for TypeScript.$3
`bash
In boilerplate/frontend
pnpm add link:/path/to/omnify/packages/omnify-client-react-sso
`After linking, manually run postinstall:
`bash
node node_modules/@famgia/omnify-react-sso/scripts/postinstall.cjs
`$3
#### 1. Exclude SSO Schemas from Local Generation
In
omnify.config.ts:`typescript
typescriptPlugin({
modelsPath: "./frontend/src/omnify/schemas",
exclude: [
// SSO types come from @famgia/omnify-react-sso
"Branch",
"Permission",
"Role",
"RolePermission",
"Team",
"TeamPermission",
"User", // Important!
],
})
`#### 2. Import Patterns
`typescript
// β
CORRECT: SSO types from package
import type { User, Role, Permission, Branch } from '@famgia/omnify-react-sso';
import { useSso, useAuth } from '@famgia/omnify-react-sso';
import { roleService, permissionService } from '@/lib/ssoService'; // configured instances// β
CORRECT: App-specific types from local
import type { Product, Order } from '@/omnify/schemas';
import { getProductFieldLabel } from '@/omnify/schemas';
// β WRONG: Don't import SSO types from local schemas
import type { Role } from '@/omnify/schemas'; // Error or duplicate!
`#### 3. Service Configuration
Create
lib/ssoService.ts to configure services with your API URL:`typescript
import {
createAuthService,
createRoleService,
createPermissionService,
createBranchService,
createUserRoleService,
} from '@famgia/omnify-react-sso';const apiUrl = process.env.NEXT_PUBLIC_API_URL!;
export const authService = createAuthService({ apiUrl });
export const roleService = createRoleService({ apiUrl });
export const permissionService = createPermissionService({ apiUrl });
export const branchService = createBranchService({ apiUrl });
export const userRoleService = createUserRoleService({ apiUrl });
`$3
`
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β omnify-client-laravel-sso (Laravel Package) β
β database/schemas/Sso/*.yaml (Source of truth) β
βββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββ
β pnpm build (copies + generates)
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β @famgia/omnify-react-sso (This Package) β
β dist/ β
β βββ index.js (hooks, components, services) β
β βββ schemas/ (SSO types: User, Role, Permission...) β
β βββ @omnify-base/(TypeScript resolution) β
βββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββ
β npm install / pnpm link
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Boilerplate / Your App β
β β
β Import from package: β
β - useSso, useAuth, useOrganization β
β - User, Role, Permission, Branch, Team β
β - createRoleService, ssoQueryKeys, etc. β
β β
β Generate locally (via omnify.config.ts): β
β - App-specific schemas only β
β - Product, Order, Invoice, etc. β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
`$3
1. Edit YAML in
omnify-client-laravel-sso/database/schemas/Sso/
2. Rebuild package:
`bash
cd packages/omnify-client-react-sso
pnpm build
`
3. If using npm (not link): Publish and update
`bash
npm version patch
npm publish --access public
# In boilerplate:
pnpm update @famgia/omnify-react-sso
`
4. If using link: Rebuild triggers automatic update---
Architecture Note
This package provides client-side schemas for Omnify Console's ServiceInstance architecture:
`
Console (SSO Provider) Your React App (SSO Client)
βββββββββββββββββββββββββββββββ βββββββββββββββββββββββββββ
β Service: "your-service" β β β
β β β Uses: service_slug β
β ServiceInstance (per-org): βββββββββββΆβ Schemas from this pkg β
β - Unique credentials β β JWT token handling β
β - Environment config β β β
βββββββββββββββββββββββββββββββ βββββββββββββββββββββββββββ
`> Note: Your app only needs the
service_slug. Console manages credentials per-organization through ServiceInstance.---
API Reference
$3
`typescript
import { useSso, useAuth, useOrganization } from '@famgia/omnify-react-sso';// Main hook - all SSO functionality
const {
user, // Current user
isAuthenticated, // Auth status
isLoading, // Loading state
organizations, // User's organizations
currentOrg, // Current organization
hasMultipleOrgs, // Has more than one org?
login, // Redirect to login
logout, // Logout current session
globalLogout, // Logout from all sessions
switchOrg, // Switch organization
getHeaders, // Get auth headers
config, // SSO config
} = useSso();
// Auth-focused hook
const { user, isAuthenticated, login, logout } = useAuth();
// Organization-focused hook
const { organizations, currentOrg, switchOrg, hasMultipleOrgs } = useOrganization();
`$3
`tsx
import {
SsoProvider,
SsoCallback,
OrganizationSwitcher,
ProtectedRoute,
} from '@famgia/omnify-react-sso';// Provider - wrap your app
// Callback page - handle OAuth redirect
onSuccess={(user) => router.push('/dashboard')}
onError={(error) => console.error(error)}
/>
// Organization switcher dropdown
// Protected route wrapper
}>
`$3
Use individual services for better tree-shaking and type safety:
`typescript
import {
createAuthService,
createRoleService,
createPermissionService,
createBranchService,
createUserRoleService,
} from '@famgia/omnify-react-sso';const config = { apiUrl: 'https://api.example.com' };
// Auth Service
const authService = createAuthService(config);
await authService.callback({ code: 'oauth-code' });
await authService.getUser();
await authService.logout();
// Role Service
const roleService = createRoleService(config);
await roleService.list();
await roleService.get(roleId);
await roleService.create({ name: 'Editor', slug: 'editor' });
await roleService.syncPermissions(roleId, { permissions: ['read', 'write'] });
// Permission Service
const permissionService = createPermissionService(config);
await permissionService.list();
await permissionService.getMatrix();
// Branch Service
const branchService = createBranchService(config);
await branchService.list();
await branchService.getPrimary();
// User Role Service (Scoped Assignments)
const userRoleService = createUserRoleService(config);
await userRoleService.listForUser(userId);
await userRoleService.assign({ user_id, role_id, scope: 'branch', branch_id });
`$3
`typescript
// @deprecated - Use individual services instead
import { createSsoService } from '@famgia/omnify-react-sso';const ssoService = createSsoService({ apiUrl: 'https://api.example.com' });
await ssoService.getRoles(); // Use roleService.list() instead
`$3
`typescript
import {
// User
userSchemas,
userCreateSchema,
userI18n,
type User,
type UserCreate,
// Role
roleSchemas,
roleCreateSchema,
roleI18n,
type Role,
// Permission
permissionSchemas,
permissionI18n,
type Permission,
// Team
teamSchemas,
teamI18n,
type Team,
} from '@famgia/omnify-react-sso';
`$3
`typescript
import { ssoQueryKeys } from '@famgia/omnify-react-sso';// Use with TanStack Query
useQuery({
queryKey: ssoQueryKeys.auth.user(),
queryFn: () => ssoService.getUser(),
});
useQuery({
queryKey: ssoQueryKeys.roles.list(),
queryFn: () => ssoService.getRoles(),
});
`---
i18n Support
Each schema includes internationalization support:
`typescript
import { userI18n, getUserLabel, getUserFieldLabel } from '@famgia/omnify-react-sso';// Get model label
const label = getUserLabel('ja'); // 'γ¦γΌγΆγΌ'
// Get field label
const emailLabel = getUserFieldLabel('email', 'ja'); // 'γ‘γΌγ«γ’γγ¬γΉ'
`---
Testing
$3
`bash
pnpm test # Run once
pnpm test:watch # Watch mode
pnpm typecheck # Type check
`$3
The package provides official test mocks:
`typescript
import {
createMockUser,
createMockOrganization,
setMockSsoData,
resetMockSsoData,
mockUseSso,
} from '@famgia/omnify-react-sso/testing';// Create mock data
const user = createMockUser({ name: 'Custom User' });
const org = createMockOrganization({ slug: 'my-org' });
// Setup mock for tests
beforeEach(() => {
setMockSsoData({
user,
organizations: [org],
currentOrg: org,
isAuthenticated: true,
});
});
afterEach(() => {
resetMockSsoData();
});
// Mock the hooks in vitest
vi.mock('@famgia/omnify-react-sso', async () => {
const testing = await import('@famgia/omnify-react-sso/testing');
return {
useSso: testing.mockUseSso,
useAuth: testing.mockUseAuth,
useOrganization: testing.mockUseOrganization,
SsoProvider: ({ children }) => children,
};
});
`> Note: Subpath exports (
/testing) may not work with linked packages in Vite/Vitest. Use direct imports or install from npm.---
Troubleshooting
$3
Cause: TypeScript can't resolve the bundled types.
Solutions:
1. If installed from npm: Run postinstall manually
`bash
node node_modules/@famgia/omnify-react-sso/scripts/postinstall.cjs
`2. If using pnpm link: Same as above
`bash
cd your-app/frontend
node node_modules/@famgia/omnify-react-sso/scripts/postinstall.cjs
`3. Verify @omnify-base exists:
`bash
ls node_modules/@omnify-base/schemas/
# Should show: User.ts, Role.ts, Permission.ts, etc.
`$3
Cause: You're importing SSO types from local schemas instead of the package.
Fix: Change imports:
`typescript
// β Wrong
import type { Role } from '@/omnify/schemas';// β
Correct
import type { Role } from '@famgia/omnify-react-sso';
`$3
Cause: SSO schemas generated locally AND imported from package.
Fix: Add to
omnify.config.ts:
`typescript
typescriptPlugin({
exclude: ["User", "Role", "Permission", "Branch", "Team", "RolePermission", "TeamPermission"],
})
`$3
Cause: No SSH access to omnifyjp/omnify-client-laravel-sso.
Fix:
`bash
Test SSH access
ssh -T git@github.comIf needed, add SSH key to GitHub
Or clone manually as sibling:
git clone git@github.com:omnifyjp/omnify-client-laravel-sso.git ../omnify-client-laravel-sso
`$3
Cause: Subpath exports don't work well with linked packages in Vite.
Fix: Create local mock file instead:
`typescript
// src/test/mocks/sso.ts
export function createMockUser(overrides = {}) {
return { id: '1', name: 'Test User', email: 'test@example.com', ...overrides };
}
``---
| Version | Changes |
| ------- | -------------------------------------------------------- |
| 2.2.1 | Bundled @omnify-base for TS consumers, added postinstall |
| 2.2.0 | Added testing utilities subpath export |
| 2.1.0 | Split services into individual factories |
| 2.0.0 | Initial stable release |
---
MIT