Skip to main content

Embedded Sign-In (Clerk-style)

Render a complete sign-in form inline on your page. No redirects, no popups. The form calls the ZewstID API directly and returns an authorization code for server-side token exchange.

SDK Version: Requires

@zewstid/nextjs
v0.9.0+

When to Use Embedded Sign-In

Use CaseRecommended
Clerk-style inline sign-in on your marketing pageEmbedded
Full control over auth UX positioning and stylingEmbedded
Simple login page with ZewstID brandingRedirect
Need popup blocker immunityRedirect

Quick Start

1. Add the EmbeddedSignIn Component

'use client'; import { EmbeddedSignIn } from '@zewstid/nextjs'; export default function LoginPage() { return ( <div style={{ maxWidth: 400, margin: '100px auto' }}> <EmbeddedSignIn clientId={process.env.NEXT_PUBLIC_ZEWSTID_CLIENT_ID!} onSuccess={({ code, email }) => { // Exchange auth code for tokens server-side fetch('/api/auth/exchange', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ code }), }).then(() => { window.location.href = '/dashboard'; }); }} /> </div> ); }

2. Create the Token Exchange Endpoint

// app/api/auth/exchange/route.ts import { NextRequest, NextResponse } from 'next/server'; export async function POST(req: NextRequest) { const { code } = await req.json(); // Exchange auth code for tokens via ZewstID API const response = await fetch('https://api.zewstid.com/api/v1/embedded/auth/code/exchange', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ code, client_id: process.env.ZEWSTID_CLIENT_ID, client_secret: process.env.ZEWSTID_CLIENT_SECRET, }), }); const tokens = await response.json(); // Set tokens in httpOnly cookies or session // ... return NextResponse.json({ success: true }); }

How It Works

1. User enters email in EmbeddedSignIn form 2. Component calls POST /api/v1/embedded/auth/check-email 3. API returns available auth methods for that email 4. User selects method (password, OTP, or magic link) 5. User authenticates via the selected method 6. API returns an authorization code (valid 10 minutes) 7. onSuccess({ code, email }) fires in your app 8. Your server exchanges the code for tokens

Multi-Step Flow

The embedded form follows a multi-step flow:

  1. Email Entry - User enters their email address
  2. Method Selection - Shows available methods (password, OTP, magic link)
  3. Authentication - User completes the selected method
  4. Success - Authorization code returned to your app

If only one method is available, the method selection step is skipped.

API Reference

<EmbeddedSignIn>

PropTypeDefaultDescription
clientId
string
(required)Your ZewstID client ID
apiUrl
string
"https://api.zewstid.com"
ZewstID API URL
methods
EmbeddedAuthMethod[]
['password', 'otp', 'magic-link']
Allowed auth methods
onSuccess
(result: { code: string; email: string }) => void
-Called on successful auth
onError
(error: string) => void
-Called on auth failure
codeChallenge
string
-PKCE code challenge
codeChallengeMethod
string
-PKCE method (
S256
)
showSocialLogins
boolean
false
Show social login buttons
socialProviders
SocialProvider[]
All providersWhich social providers to show
authUrl
string
"https://auth.zewstid.com"
Auth URL for social popup
appearance
EmbeddedSignInAppearance
-Custom appearance
labels
EmbeddedSignInLabels
-Custom labels
className
string
-CSS class
style
CSSProperties
-Inline styles

<UserButton>

Clerk-style user avatar with dropdown menu.

import { UserButton } from '@zewstid/nextjs'; function Header() { return ( <nav> <UserButton afterSignOutUrl="/" userProfileUrl="https://account.zewstid.com" /> </nav> ); }
PropTypeDefaultDescription
afterSignOutUrl
string
"/"
Redirect URL after sign out
userProfileUrl
string
"https://account.zewstid.com"
"Manage Account" link
appearance
UserButtonAppearance
-Custom appearance
labels
UserButtonLabels
-Custom labels
children
ReactNode
-Custom menu items
className
string
-CSS class

Customization

Appearance

<EmbeddedSignIn clientId="my-app" appearance={{ primaryColor: '#6366f1', backgroundColor: '#fafafa', textColor: '#1a1a2e', borderRadius: '16px', logo: '/logo.svg', logoHeight: '40px', boxShadow: '0 4px 24px rgba(0,0,0,0.08)', fontFamily: '"Inter", sans-serif', }} onSuccess={handleSuccess} />

Labels

<EmbeddedSignIn clientId="my-app" labels={{ title: 'Welcome to MyApp', subtitle: 'Sign in to continue', emailPlaceholder: '[email protected]', continueButton: 'Next', signInButton: 'Log in', orDivider: 'or continue with', }} onSuccess={handleSuccess} />

Social Logins

Social logins open in a popup (since they require redirect to Google/GitHub/etc.) and return the result to the embedded form.

<EmbeddedSignIn clientId="my-app" showSocialLogins socialProviders={['google', 'github', 'microsoft']} onSuccess={handleSuccess} />

PKCE Support

For enhanced security, use PKCE with the embedded flow:

import { randomBytes, createHash } from 'crypto'; // Generate PKCE pair const codeVerifier = randomBytes(32).toString('base64url'); const codeChallenge = createHash('sha256') .update(codeVerifier) .digest('base64url'); <EmbeddedSignIn clientId="my-app" codeChallenge={codeChallenge} codeChallengeMethod="S256" onSuccess={({ code }) => { // Pass codeVerifier when exchanging fetch('/api/auth/exchange', { method: 'POST', body: JSON.stringify({ code, code_verifier: codeVerifier }), }); }} />

API Endpoints

The embedded sign-in component calls these API Gateway endpoints:

EndpointMethodDescription
/api/v1/embedded/auth/check-email
POSTCheck if user exists, get available methods
/api/v1/embedded/auth/password
POSTAuthenticate with password
/api/v1/embedded/auth/otp/send
POSTSend OTP code to email
/api/v1/embedded/auth/otp/verify
POSTVerify OTP code
/api/v1/embedded/auth/magic-link/send
POSTSend magic link email
/api/v1/embedded/auth/magic-link/verify
GETVerify magic link token
/api/v1/embedded/auth/code/exchange
POSTExchange auth code for tokens (server-side)

Rate Limits

  • IP-based: 20 requests per minute
  • Email-based: 5 attempts per 15 minutes

Origin Validation

Requests must come from an origin registered in your application's

webOrigins
setting. Configure this in the ZewstID Admin Dashboard when creating your OAuth client.

Security

  • Origin validation: Only registered origins can call embedded auth endpoints
  • PKCE: S256 code challenge support for enhanced security
  • Rate limiting: Per-IP and per-email rate limits prevent brute force
  • Auth codes: Cryptographically random, 10-minute TTL, single-use
  • Constant-time comparison: Prevents timing attacks on code verification
  • No credentials in browser: Auth codes are exchanged server-side for tokens

Choosing an Integration Style

FeatureRedirectPopupEmbedded
ComplexitySimplestSimpleModerate
User stays on your pageNoYesYes
Popup blocker safeYesNo (fallback)Yes
Custom stylingLimitedLimitedFull
Social loginNativeNativeVia popup
Mobile friendlyYesNoYes
SecurityHighestHighHigh

Was this page helpful?

Let us know how we can improve our documentation