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

@owizzo/kratos-ui

v1.3.0

Published

White-label authentication UI for Ory Kratos: Ory Elements flows rendered with Ozora components.

Readme

@owizzo/kratos-ui

White-label authentication UI for Ory Kratos as a reusable React library. It renders all Kratos self-service flows of Ory Elements (@ory/elements-react) with components of the Ozora design system.

The library ships no branding: product name and logo come from the configuration, colors from the app's Ozora theme. The same package serves owizzo products as well as white-label tenants.

| Flow | Component | Default route | | ------------ | -------------------- | -------------------- | | Login | KratosLogin | /auth/sign-in | | Registration | KratosRegistration | /auth/sign-up | | Recovery | KratosRecovery | /auth/recovery | | Verification | KratosVerification | /auth/verification | | Settings | KratosSettings | /settings | | Errors | KratosError | /auth/error | | Signed in | AccountCard | / |

The UI adapts to the identity schema and the methods enabled in Kratos (password, OIDC, passkeys, TOTP, lookup secrets, …). On top of Ory Elements it adds a password confirmation on registration and a current-password check when changing the password in the settings flow.

Installation

npm install @owizzo/kratos-ui @owizzo/ozora @ory/[email protected] @ory/[email protected] [email protected]

Peer dependencies: React 19, Tailwind CSS 4, @owizzo/ozora (^2.0.0), @ory/elements-react, @ory/client-fetch and react-intl.

react-intl and @ory/client-fetch are pinned to the exact versions @ory/elements-react pins, and @ory/elements-react itself to the version those pins belong to. A second copy would give the library components a different React context than Ory's IntlProvider (runtime error "Could not find required intl object"). src/config/peerVersions.test.ts fails when an Ory upgrade changes the pins — then align peerDependencies and devDependencies.

react-intl 7.1.13 declares TypeScript ^5.6 as optional peer. Apps on TypeScript 6 get a peer warning from npm; legacy-peer-deps=true in the app's .npmrc silences it until Ory moves to a newer react-intl.

Styles

Like Ozora, the library ships Tailwind classes, not compiled CSS. Add it to the app's Tailwind entry stylesheet. The stylesheet registers its own sources (@source) and puts the Ory Elements styles into Tailwind's components layer — no @layer declaration or @source for kratos-ui needed:

@import "tailwindcss";
@import "@owizzo/ozora/index.css";
@import "@owizzo/kratos-ui/styles.css";

/* Your brand — see "Branding / white label" */
:root {
  --ozora-primary: #7c3aed;
  --ozora-secondary: #f59e0b;
  --ozora-link: #7c3aed;
  --ozora-link-hover: #5b21b6;
}

styles.css contains the Ory Elements base styles (scoped to .ory-elements), a theme for them derived from the Ozora tokens, the card styling, a type scale aligned with Ozora (14 px body, labels and buttons; inputs 16 px on phones so iOS does not zoom) and the .kratos-ui-scene page background used by <AuthScene>.

Upgrading from 1.0: the @layer theme, base, ory-elements, … line and the @source for kratos-ui can be removed; keeping them does no harm.

Usage

useKratosFlow loads the flow for a UI route: it resumes the flow from ?flow=<id> (Kratos redirects there), replaces an expired one, otherwise creates a new browser flow, and follows Kratos redirects (e.g. "already signed in"). Then render the matching component:

import { AuthScene, createOryConfig, KratosLogin, useKratosFlow } from "@owizzo/kratos-ui"

import { ProductLogo } from "./ProductLogo"

const sdkUrl = "https://auth.example.com"
const config = createOryConfig({ name: "Northwind", sdkUrl })

export function SignInPage() {
  const { flow, error, reload } = useKratosFlow("login", { sdkUrl })
  if (error) return <ErrorView message={error.message} onRetry={reload} />
  return (
    <AuthScene>
      {flow && <KratosLogin flow={flow} config={config} logo={<ProductLogo />} />}
    </AuthScene>
  )
}

The flow type follows the kind (useKratosFlow("settings") returns a SettingsFlow). Pass search when the router owns the query string; server-rendered apps can keep fetching the flow on the server (see getFlowError in @owizzo/kratos-ui/server).

Inside an app page, render the settings embedded — without Ory's page header (logo, account menu) and with forms flush to the page content:

<KratosSettings flow={flow} config={config} embedded />

Building your own flow layout? Spread ozoraComponents into the components prop of any Ory Elements flow, or pass extra overrides via the components prop of the Kratos* components (merged on top of the Ozora components).

The current-password check in the settings flow calls /self-service/login/browser on the same origin, i.e. it expects Kratos to be reachable through the app's own domain (reverse proxy), which is also what keeps the session cookie first-party.

Branding / white label

Everything brand-specific is supplied by the app:

| What | How | | ------------ | ------------------------------------------------------------------------- | | Product name | createOryConfig({ name }) (required): card heading if there is no logo | | Logo | logo prop of the Kratos* components and AccountCard (any React element, e.g. an SVG component), or createOryConfig({ logoUrl }) | | Colors | Ozora tokens on :root: --ozora-primary, --ozora-secondary, --ozora-background, --ozora-text, --ozora-link, --ozora-link-hover (or Ozora's ThemeProvider) | | Card / page | optional --kratos-ui-* variables (below) | | Texts | locale + customTranslations (Ory message IDs and kratosUi.*) | | Single parts | components prop: replace any Ory Elements slot | | Flow content | customization prop: methods, SSO, fields, steps (see below) |

The Ory Elements color scale (--brand-*), the card accent strip and the page background are derived from the Ozora tokens, so a tenant theme is just a set of Ozora tokens. Surfaces, text, borders and validation colors use Ozora's semantic tokens (--ozora-surface, --ozora-border, --ozora-text-muted, --ozora-danger, …), so Ozora's dark mode (<html data-ozora-theme="dark">) applies to the whole auth UI, including the parts Ory Elements renders itself. Optional fine-tuning:

| Variable | Default | | ------------------------------ | -------------------------------------------------------- | | --kratos-ui-card-radius | 1.25rem | | --kratos-ui-card-shadow | soft shadow tinted with the primary color | | --kratos-ui-card-accent | primary → secondary gradient (none removes the strip) | | --kratos-ui-border | --ozora-border, else slate-200 | | --kratos-ui-scene-background | --ozora-background | | --kratos-ui-scene-orb-1/-2 | primary / secondary, translucent (transparent hides them) |

Ozora components

Inputs, password fields, checkboxes, buttons, SSO buttons, labels, field messages, flow messages (Alert), links, text nodes, the TOTP secret (CopyField), the card itself, the logo/name heading, custom card headers, the registration stepper and dividers are Ozora components (ozoraComponents). A few parts are still rendered by Ory Elements because their logic is internal to it: the default card header texts, the card footer links (sign up / sign in / choose another method), the method list of the "choose a method" screen, the OTP code input and the settings section frames. They are themed through the same Ozora tokens.

Fields, methods, SSO and registration steps

What a user has to provide is decided in two layers:

| Layer | Decides | Where | | ----- | ------- | ----- | | Kratos (server) | which fields exist and are required (identity schema traits), which methods are enabled (password, code, passkey, TOTP, …), which SSO providers exist, one- or two-step registration | Kratos config + identity schema(s) | | This library (per app, at runtime) | which of these are offered, in which order, with which labels/icons, and how the registration form is split into steps | customization prop |

The UI renders whatever the Kratos flow contains, so enabling a method or adding a trait in Kratos needs no UI change. customization can only narrow down and present — a field Kratos requires cannot be removed client-side.

Different requirements per app: identity schemas

For apps that need different registration data (e.g. a product app vs. a tenant portal), define one identity schema per app in Kratos, mark it selfservice_selectable: true and start the flow with it:

identity:
  default_schema_id: default
  schemas:
    - id: default
      url: file:///etc/config/kratos/identity.default.schema.json
    - id: partner-portal
      url: file:///etc/config/kratos/identity.partner-portal.schema.json
      selfservice_selectable: true
import { selfServiceUrl } from "@owizzo/kratos-ui"

// e.g. the app's "sign up" button
location.href = selfServiceUrl(sdkUrl, "registration", {
  identitySchema: "partner-portal",
  returnTo: "https://portal.example.com/",
})

Required fields, formats and the field order come from that schema.

customization

Every Kratos* flow component takes a customization object. It is plain data (apart from optional icon elements), so it can live in code or be loaded per tenant from a backend:

const login: FlowCustomization = {
  // Only offer these methods (Kratos may have more enabled).
  methods: ["password", "oidc"],
  sso: {
    providers: ["microsoft", "google"], // allow-list + order (Kratos provider IDs)
    position: "top",                    // or "bottom" (default)
    display: { microsoft: { label: "Mit Microsoft 365 anmelden" } },
  },
  fields: {
    identifier: { label: "Geschäftliche E-Mail", placeholder: "[email protected]" },
  },
  // Replaces the card title/subtitle Ory Elements derives from the flow.
  title: "Anmelden",
  description: "Willkommen zurück.",
}

<KratosLogin flow={flow} config={config} customization={login} />

| Key | Effect | | ------------- | ------ | | methods | Allow-list of method groups: password, code, link, passkey, webauthn, totp, lookup_secret, oidc, saml. Without any identifier-based method (e.g. SSO only), the login identifier field is hidden too. | | sso.providers | Which providers to show, in this order. | | sso.display | Label and icon (element or image URL) per provider. Built-in logos: apple, auth0, discord, github, gitlab, google, linkedin, microsoft, slack, spotify, x, yandex. | | sso.position / sso.hidden | SSO above/below the credentials, or not at all. | | fields | Per node name (identifier, password, traits.email, traits.name.first, …): label, placeholder, description (help text), hidden (optional fields only). | | title / description | Card heading and subtitle. | | steps | Registration only, see below. |

Registration steps

steps splits the fields of a Kratos registration screen into client-side steps with an Ozora Stepper and next/back buttons:

const registration: FlowCustomization = {
  steps: [
    { id: "account", title: "Konto", fields: ["traits.email"] },
    {
      id: "profile",
      title: "Profil",
      description: "Wie dürfen wir Sie ansprechen?",
      fields: ["traits.name.first", "traits.name.last", "traits.company"],
    },
    { id: "security", title: "Sicherheit", fields: ["password"] },
  ],
}
  • Steps adapt to what Kratos shows: steps without fields on the current screen are skipped, and fields no step lists go to the last one. With Kratos' two-step registration (profile screen → credentials screen) the steps apply to whichever screen has at least two of them; with fewer, the form renders without steps.
  • "Next" validates the step's fields (required per identity schema, formats such as e-mail); Enter advances as well. All steps are one Kratos submit.
  • Kratos validation errors after submit jump back to the first step with an affected field. SSO is only offered on the first step.

Configuration

createOryConfig(options) returns an OryClientConfiguration (no Ory branding, standard routes):

| Option | Default | Description | | -------------------- | ------------------- | ------------------------------------------------------------ | | name | – (required) | Product name | | logoUrl | – | Logo image URL (alternative to the logo prop) | | locale | "de" | UI language (any Ory Elements locale) | | routes | defaultAuthRoutes | Route overrides; must match the Kratos ui_urls | | sdkUrl | – | Kratos public URL (or the app origin when proxied) | | customTranslations | – | Extra/overriding messages per locale (kratosUi.*, Ory IDs) | | project | – | Any other Ory project setting (enabled flows, …) |

Texts rendered by the library itself use kratosUi.* message IDs (see src/config/messages.ts, German and English included). AccountCard and LogoutButton live outside the Ory context and take their texts via the labels / label props.

Kratos configuration

Point the Kratos self-service UI URLs at the app, e.g.:

selfservice:
  default_browser_return_url: https://account.example.com/
  flows:
    login:
      ui_url: https://account.example.com/auth/sign-in
    registration:
      ui_url: https://account.example.com/auth/sign-up
    recovery:
      ui_url: https://account.example.com/auth/recovery
    verification:
      ui_url: https://account.example.com/auth/verification
    settings:
      ui_url: https://account.example.com/settings
    error:
      ui_url: https://account.example.com/auth/error

SSO via Microsoft (Entra ID)

SSO buttons appear automatically once Kratos has an OIDC provider configured (selfservice.methods.oidc). The Microsoft provider is configured in the Kratos config (see ocip.core.service/docker/kratos/config/kratos.yml for local dev, mapper: oidc.microsoft.jsonnet):

  1. Create an Azure App Registration (Entra ID → App registrations) with redirect URI (type "Web") <kratos public base_url>/self-service/methods/oidc/callback/microsoft and a client secret.
  2. Set client_id / client_secret in the Kratos config (or via env: SELFSERVICE_METHODS_OIDC_CONFIG_PROVIDERS_0_CLIENT_ID / ..._CLIENT_SECRET).
  3. microsoft_tenant: common, organizations or a specific tenant ID.

Package entry points

| Import | Contents | | ------------------------------- | ---------------------------------------------------------- | | @owizzo/kratos-ui | all components, flows, config and helpers | | @owizzo/kratos-ui/config | createOryConfig, defaultAuthRoutes, selfServiceUrl, messages | | @owizzo/kratos-ui/server | getFlowError (no React, usable server-side) | | @owizzo/kratos-ui/styles.css | stylesheet (see above) |

Development

src/
├─ components/   AccountCard, AuthScene, BackToSignIn, LogoutButton (+ stories)
├─ nodes/        Ozora overrides for Ory Elements nodes (ozoraComponents)
├─ card/         Ozora card root, header, logo, content and divider slots
├─ customization/ FlowCustomization types and context
├─ steps/        registration steps (provider, stepper, navigation)
├─ sso/          SSO root/button overrides, provider logos
├─ flows/        Kratos* flow components (+ stories, tests)
├─ config/       createOryConfig, routes, messages
├─ server/       getFlowError
├─ styles/       styles.css (shipped as-is)
└─ test/         flow fixtures and a demo brand for stories and tests
npm run storybook   # component development with fixture flows (no Kratos needed)*
npm test            # vitest
npm run typecheck
npm run build       # Vite library build → dist/ (ESM + CJS + .d.ts, one file per module)

* The Storybook configuration (.storybook/) is local and not versioned, like in Ozora: @storybook/react-vite with a separate Vite config (@vitejs/plugin-react, @tailwindcss/vite), stories src/**/*.stories.tsx and a preview stylesheet importing Tailwind, the Ozora theme and src/styles/index.css.

The build keeps one output file per source module (preserveModules), so the "use client" directives of the components are preserved for React Server Components setups.