Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 181 additions & 5 deletions mintlify/docs/react-sdk/ur-auth.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ export default function LoginPage() {
return (
<div style={{ display: 'flex', minHeight: '100vh', alignItems: 'center', justifyContent: 'center' }}>
<UrAuth
providers={['google', 'github']}
providers={['google', 'github']}
enableEmailPassword={true}
theme="light"
/>
</div>
Expand All @@ -28,12 +29,187 @@ export default function LoginPage() {

| Prop | Type | Default | Description |
|---|---|---|---|
| `theme` | `'light' \| 'dark'` | `'light'` | The visual theme of the component. |
| `providers` | `Array<'google' \| 'github'>` | `[]` | Social auth providers to display. These must be enabled in your urBackend Dashboard first. |
| `theme` | `'light' \| 'dark'` | `'light'` | Visual theme mode (`ThemeMode` internally). |
| `providers` | `('google' \| 'github')[] \| { google?: boolean; github?: boolean; emailPassword?: boolean }` | `['google', 'github']` | Auth methods to show. Supports legacy array form and v0.2.0 object form. |
| `enableEmailPassword` | `boolean` | `true` | Top-level shorthand to enable/disable email/password auth. |
| `colors` | `Partial<AuthColors>` | `undefined` | Overrides for auth widget theme colors. |
| `branding` | `AuthBranding` | `undefined` | Branding/white-label configuration (logo, app name, subtitle, brand color). |
| `labels` | `Partial<AuthLabels>` | `undefined` | Text/copy overrides for tabs, titles, buttons, and footer prompts. |
| `onSuccess` | `() => void` | `undefined` | Called after successful sign-in or sign-up flow. |

## Customizing the Design
> All customization props are optional. If omitted, `<UrAuth>` falls back to the same default behavior/UI style as v0.1.x.

The `<UrAuth>` component uses a modern, square design aesthetic (sharp corners). It adapts well to both light and dark backgrounds depending on the `theme` prop you provide.
## `providers` and `enableEmailPassword`

`providers` now accepts either:

```ts
('google' | 'github')[]
```

or:

```ts
{
google?: boolean;
github?: boolean;
emailPassword?: boolean;
}
```

### Example: Email/password only

```tsx
<UrAuth
providers={{ google: false, github: false, emailPassword: true }}
/>
```

### Example: Google only

```tsx
<UrAuth
providers={{ google: true, github: false, emailPassword: false }}
/>
```

### Example: Disable all methods

```tsx
<UrAuth providers={{ google: false, github: false, emailPassword: false }} />
```

This renders the built-in `No authentication methods are enabled for this screen.` message.

### `enableEmailPassword` interaction

- `enableEmailPassword` is a shorthand global toggle.
- When `providers` is an object and includes `emailPassword`, that object value takes precedence.
- If `providers.emailPassword` is omitted, `enableEmailPassword` is used.

## `colors` theme customization

Use `colors` to override theme tokens:

```ts
type AuthColors = {
background: string;
surface: string;
text: string;
textMuted: string;
border: string;
inputBackground: string;
primary: string;
primaryColor?: string; // alias for primary button color
primaryText: string;
footerBackground: string;
dividerText: string;
socialButtonBackground: string;
};
```

Set a custom brand color on the primary sign-in button:

```tsx
<UrAuth colors={{ primaryColor: '#6366f1' }} />
```

If both `colors.primaryColor` and `branding.primaryColor` are provided, `branding.primaryColor` takes precedence.

## `branding` white-label options

```ts
type AuthBranding = {
brandName?: string;
appName?: string;
title?: string;
subtitle?: string;
logo?: React.ReactNode | string; // URL string or custom React node
logoUrl?: string; // URL alias
primaryColor?: string;
};
```

Example:

```tsx
<UrAuth
branding={{
appName: 'Acme',
logoUrl: 'https://acme.com/logo.png',
subtitle: 'Secure access for your team',
}}
/>
```

## `labels` text overrides (with aliases)

Supported label keys:

- Tabs: `loginTab` (`signInTab` alias), `signupTab` (`signUpTab` alias)
- Titles: `loginTitle` (`signInTitle` alias), `signupTitle` (`signUpTitle` alias), `forgotTitle`, `resetTitle`, `forgotSubtitle`, `resetSubtitle`
- Buttons: `loginButton` (`signInButton` alias), `signupButton` (`signUpButton` alias), `forgotButton`, `resetButton`, `googleButton`, `githubButton`
- Field labels/placeholders: `emailLabel`, `emailPlaceholder`, `passwordLabel`, `passwordPlaceholder`, `nameLabel`, `namePlaceholder`, `otpLabel`, `otpPlaceholder`
- Footer/misc: `forgotPasswordLink`, `socialDivider`, `footerSigninPrompt`, `footerSignupPrompt`, `footerForgotPrompt`, `noAuthMethods`

Example:

```tsx
<UrAuth
labels={{
signInTitle: 'Welcome back to Acme',
signInButton: 'Continue',
footerSigninPrompt: 'Need an account?',
}}
/>
```

## Full v0.2.0 customization example

```tsx
import { UrAuth, GuestRoute } from '@urbackend/react';

export default function LoginPage() {
return (
<GuestRoute fallback={<div>Loading...</div>} onRedirect={() => (window.location.href = '/dashboard')}>
<UrAuth
providers={{
github: true,
google: true,
emailPassword: true,
}}
enableEmailPassword={true}
theme="light"
colors={{
primaryColor: '#4F46E5',
socialButtonBackground: '#ffffff',
}}
branding={{
appName: 'My Custom App',
logoUrl: 'https://vite.dev/logo.svg',
subtitle: 'Secure authentication',
primaryColor: '#4F46E5',
}}
labels={{
signInTitle: 'Welcome back to Custom App',
signInButton: 'Proceed to App',
signUpButton: 'Create your account',
}}
onSuccess={() => {
// route after successful auth
window.location.href = '/dashboard';
}}
/>
</GuestRoute>
);
}
```

## Migration (v0.1.x → v0.2.0)

- `providers` now also accepts object form: `{ google?, github?, emailPassword? }`
- Existing array usage (`['google', 'github']`) still works
- No breaking API changes otherwise

## Behavior

Expand Down
20 changes: 20 additions & 0 deletions sdks/urbackend-react/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Changelog

All notable changes to `@urbackend/react` are documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this package adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [v0.2.0] - 2026-06-13

### Added
- Expanded `<UrAuth>` customization with object-form `providers` config (`google`, `github`, `emailPassword`)
- Added `enableEmailPassword` shorthand toggle support
- Added customizable `colors`, `branding`, and `labels` props for theme/copy overrides
- Added label alias support (for example: `signInTitle`/`loginTitle`, `signInButton`/`loginButton`)
- Added configurable branding logo URL support (`branding.logoUrl` alias)

### Changed
- Internal theme typing for `<UrAuth>` uses `ThemeMode` while keeping public values as `'light' | 'dark'`
- Defaults remain backward compatible with v0.1.x when new props are omitted

15 changes: 9 additions & 6 deletions sdks/urbackend-react/src/components/UrAuth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ interface AuthColors {
border: string;
inputBackground: string;
primary: string;
primaryColor?: string;
primaryText: string;
footerBackground: string;
dividerText: string;
Expand All @@ -25,6 +26,7 @@ interface AuthBranding {
title?: string;
subtitle?: string;
logo?: React.ReactNode | string;
logoUrl?: string;
primaryColor?: string;
}

Expand Down Expand Up @@ -200,7 +202,7 @@ export const UrAuth: React.FC<UrAuthProps> = ({
};

const themeColors = { ...defaultThemeColors[theme], ...colors };
const primaryColor = branding?.primaryColor || themeColors.primary;
const primaryColor = branding?.primaryColor || colors?.primaryColor || themeColors.primary;
const secondStopColor = adjustColor(primaryColor, -15);

let isGoogleEnabled = true;
Expand All @@ -222,6 +224,7 @@ export const UrAuth: React.FC<UrAuthProps> = ({
const hasSocialAuth = isGoogleEnabled || isGithubEnabled;
const brandName = branding?.brandName || branding?.appName || branding?.title || 'urBackend';
const headerTitle = branding?.title || brandName;
const brandingLogo = branding?.logo ?? branding?.logoUrl;
const headerSubtitle = branding?.subtitle || (mode === 'signin'
? text.loginTitle
: mode === 'signup'
Expand Down Expand Up @@ -524,15 +527,15 @@ export const UrAuth: React.FC<UrAuthProps> = ({
)}

<div style={styles.body}>
{(branding?.logo || branding?.brandName || branding?.appName || branding?.title || branding?.subtitle || headerTitle || headerSubtitle) && (
{(brandingLogo || branding?.brandName || branding?.appName || branding?.title || branding?.subtitle || headerTitle || headerSubtitle) && (
<div style={styles.header}>
<div style={styles.brandRow}>
{branding?.logo ? (
{brandingLogo ? (
<div style={styles.brandLogo}>
{typeof branding.logo === 'string' ? (
<img src={branding.logo} alt={brandName} style={{ width: '100%', height: '100%', objectFit: 'contain' }} />
{typeof brandingLogo === 'string' ? (
<img src={brandingLogo} alt={brandName} style={{ width: '100%', height: '100%', objectFit: 'contain' }} />
) : (
branding.logo
brandingLogo
)}
</div>
) : (
Expand Down
19 changes: 17 additions & 2 deletions sdks/urbackend-react/tests/UrAuth.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ describe('UrAuth Component', () => {
expect(primaryButton.style.background).toContain('#4F46E5');
});

it('applies custom primary color from colors.primaryColor', () => {
render(<UrAuth colors={{ primaryColor: '#6366f1' }} />);
const primaryButton = screen.getByRole('button', { name: 'Log In' });
expect(primaryButton.style.background).toContain('#6366f1');
});

it('hides email/password form when disabled via providers object', () => {
render(<UrAuth providers={{ emailPassword: false, google: true }} />);
expect(screen.queryByPlaceholderText('Enter your email address')).not.toBeInTheDocument();
Expand All @@ -103,14 +109,14 @@ describe('UrAuth Component', () => {
});

it('only shows GitHub login when configured via providers object', () => {
render(<UrAuth providers={{ github: true }} />);
render(<UrAuth providers={{ github: true, emailPassword: false }} />);
expect(screen.queryByPlaceholderText('Enter your email address')).not.toBeInTheDocument();
expect(screen.getByText('Continue with GitHub')).toBeInTheDocument();
expect(screen.queryByText('Continue with Google')).not.toBeInTheDocument();
});

it('displays message when all authentication methods are disabled', () => {
render(<UrAuth providers={{}} />);
render(<UrAuth providers={{ google: false, github: false, emailPassword: false }} />);
expect(screen.getByText('No authentication methods are enabled for this screen.')).toBeInTheDocument();
});

Expand All @@ -130,4 +136,13 @@ describe('UrAuth Component', () => {
expect(logoImg).toBeInTheDocument();
expect(logoImg?.getAttribute('src')).toBe('/assets/logo.png');
});

it('supports logoUrl branding alias', () => {
render(
<UrAuth branding={{ appName: 'My Custom App', logoUrl: '/assets/logo-url.png' }} />
);
const logoImg = screen.getByRole('img', { name: 'My Custom App' });
expect(logoImg).toBeInTheDocument();
expect(logoImg.getAttribute('src')).toBe('/assets/logo-url.png');
});
});
Loading