Back to guides

How to build fully branded authentication in a Replit app


Replit Auth is one of the fastest ways to put a login screen in a Replit app. Ask Agent to add it, choose the login methods, set an app name and icon, and your application can start identifying users without building an authentication backend.

That convenience comes with a product decision. Replit Auth users sign in with Replit accounts, and the login experience remains Replit-branded. That can be exactly right for a prototype, internal tool, developer utility, or product whose audience already uses Replit. It can feel wrong when the application needs to present itself as a completely independent product.

What can you customize in Replit Auth?

Replit currently lets you configure the application name, application icon, and enabled login methods. Supported choices include Google, GitHub, X, Apple, and email. These controls improve the entry screen, but they do not turn Replit Auth into a first-party account system.

  • Users still create or use a Replit account
  • The login page still carries Replit branding
  • Replit manages the underlying identity flow
  • Replit sends password-reset emails for the account flow
  • Manual implementation is not supported because Replit Agent provisions the integration

This is not a hidden limitation. Replit's own documentation positions Replit Auth as the zero-setup, Replit-branded option. It recommends a separate Clerk tenant when independent accounts and deeper visual customization are required.

The real question is not how to restyle a screen

When builders ask for more customization, they often mean more than colors and a logo. They want the entire authentication relationship to belong to their product.

  • Returning users should see a direct sign-in path
  • Sign-up and sign-in should use the product's own language and layout
  • Authentication emails should clearly identify the product
  • Users should not need an account with the hosting platform
  • Email and password users should not see an unrelated OAuth consent screen
  • User and session data should remain in the application's database

Those are ownership requirements, not styling requests. Solving them means choosing a different authentication boundary instead of adding more CSS around Replit Auth.

Three sensible authentication choices on Replit

Use Replit Auth for speed

Choose Replit Auth when zero setup matters more than account independence. It is a strong fit for prototypes, hackathon projects, internal tools, educational applications, and developer products whose users already understand Replit.

Use Replit-managed Clerk for a hosted branded tenant

Replit also offers Clerk Auth. It creates accounts independent of Replit, supports a fully branded sign-in interface, separates development and production users, and can use your own social-provider credentials in production. It remains a hosted identity platform with its own tenant and data model.

Use Own Auth when the application should own auth

Own Auth runs inside your Replit application backend and stores users, password accounts, one-time tokens, and sessions in your Postgres database. You build the sign-in UI as part of your product and decide how authentication emails are rendered and delivered.

  • No Replit account is required for your users
  • No hosted auth tenant owns the user store
  • The login and account-recovery interface is your code
  • Email, password, magic-link, and phone flows can be enabled independently
  • Sessions are database-backed and immediately revocable
  • The application can leave Own Auth later because its data is already in its database

Set up Own Auth in a Replit app

Own Auth needs a Node.js backend and Postgres. Replit's SQL database is PostgreSQL-compatible and exposes its connection through DATABASE_URL, so the normal Own Auth setup works without a Replit-specific storage adapter.

Replit Shell
npm install own-auth zod
npx own-auth migrate
npx own-auth status

Add the token pepper to Replit Secrets. Replit provides DATABASE_URL when its SQL database is attached. Do not place either value in source code or expose it to browser JavaScript.

Replit Secrets
DATABASE_URL=provided-by-replit-database
OWN_AUTH_TOKEN_PEPPER=replace-with-a-long-random-secret
APP_URL=https://your-app.example.com

Create the auth instance

Create one server-only Own Auth instance in the backend. The application URL becomes the base for verification, reset, and magic-link routes.

src/auth.ts
import { createOwnAuth } from "own-auth";

const appUrl = process.env.APP_URL;
if (!appUrl) throw new Error("APP_URL is required");

export const auth = createOwnAuth({
  tokenPepper: process.env.OWN_AUTH_TOKEN_PEPPER,
  baseUrl: appUrl,
  redirectAllowlist: [appUrl],
});

Build the login experience you actually want

Own Auth does not force a hosted sign-in page. Your application can present separate Sign in and Create account routes, put the returning-user path first, use the same typography and components as the rest of the product, and explain errors in the product's own voice.

Sign-in page
<main>
  <h1>Welcome back</h1>
  <p>Sign in to continue to Acme.</p>

  <form method="post" action="/auth/signin">
    <label>
      Email
      <input name="email" type="email" autocomplete="email" required />
    </label>
    <label>
      Password
      <input name="password" type="password" autocomplete="current-password" required />
    </label>
    <button type="submit">Sign in</button>
  </form>

  <a href="/signup">Create an account</a>
</main>

Your Replit app can implement the same structure with React, Next.js, Express templates, Vue, Svelte, or another Node.js framework.

Create the sign-in endpoint

The backend validates the body, calls Own Auth, and stores the opaque session token in a Secure HttpOnly cookie. The example below uses an Express-style handler, but the Own Auth call is framework-independent.

src/validation/auth.ts
import { z } from "zod";

export const signInSchema = z.object({
  email: z.string().trim().email(),
  password: z.string(),
});
src/routes/auth.ts
app.post("/auth/signin", async (request, response) => {
  const { email, password } = signInSchema.parse(request.body);
  const result = await auth.signInEmailPassword({ email, password });

  response.cookie("own_auth_session", result.sessionToken, {
    httpOnly: true,
    secure: process.env.NODE_ENV === "production",
    sameSite: "lax",
    expires: result.session.expiresAt,
    path: "/",
  });

  return response.json({ user: result.user });
});

When credentials are wrong, Own Auth returns invalid_credentials without revealing whether the email or password was incorrect. Preserve that generic response to prevent account discovery.

Send email that belongs to the product

Own Auth sends magic links, verification messages, password resets, and invitations through an EmailProvider. You can connect your own outbound provider and templates, or use Own Auth Delivery to avoid building the delivery queue and abuse controls yourself.

The product name, sender name, reply-to address, links, subject, and message copy should all make it obvious which application initiated the email. If you use a custom sender domain, configure SPF, DKIM, and DMARC before sending production traffic.

src/auth.ts
import {
  createOwnAuth,
  OwnAuthManagedEmailProvider,
} from "own-auth";

const appUrl = process.env.APP_URL;
if (!appUrl) throw new Error("APP_URL is required");

export const auth = createOwnAuth({
  tokenPepper: process.env.OWN_AUTH_TOKEN_PEPPER,
  baseUrl: appUrl,
  emailProvider: new OwnAuthManagedEmailProvider({
    deliveryKey: process.env.OWN_AUTH_EMAIL_DELIVERY_KEY,
  }),
});

Avoid unrelated consent screens

Email and password authentication and magic links do not require an OAuth consent screen. The user creates an account directly with your product. If you add Google, Apple, GitHub, or another external provider later, use your own provider credentials and request only the scopes your application genuinely needs.

Social sign-in always introduces the provider's own interface and consent rules. It should be an optional login method, not a hidden requirement for users who only want a first-party account.

What about existing Replit Auth users?

Changing authentication systems is a data migration, not a component swap. Existing users authenticated through Replit do not have Own Auth passwords, and you should never try to copy credentials that your application does not possess.

  1. Keep the old Replit user ID on existing application records as a legacy identifier.
  2. Create an Own Auth user only after the person verifies control of the same email address.
  3. Use a single-use magic link to let returning users claim their existing application data.
  4. Store an explicit mapping from the verified Own Auth user ID to the legacy Replit user ID.
  5. Run both identity lookups only for the migration window, then remove the Replit Auth path after active users have moved.

When you should keep Replit Auth

Do not migrate only because a different stack sounds more flexible. Replit Auth may remain the better choice when the application is early, the audience already has Replit accounts, the current flow is converting acceptably, and the team does not want to operate any authentication or email infrastructure.

Move when the product requirements are concrete: independent accounts, first-party UX, owned data, branded recovery flows, provider choice, or a need to leave Replit later without migrating the identity store again.

Production checklist

  • Use the production Replit database and production secrets in the published app
  • Run Own Auth migrations against production before switching traffic
  • Keep the token pepper and delivery key server-only
  • Use HTTPS and Secure HttpOnly session cookies
  • Validate sessions and authorization on every protected backend request
  • Protect cookie-authenticated mutations against CSRF
  • Rate-limit sign-in, sign-up, and email request endpoints
  • Never log passwords, session tokens, magic-link URLs, or provider tokens
  • Test account recovery and the existing-user migration before removing Replit Auth

FAQ

Can I remove all Replit branding from Replit Auth?

No. You can configure the app name, icon, and login methods, but Replit's documentation describes the login page as Replit-branded and the users as Replit accounts. Use a different authentication option when a fully first-party identity experience is required.

Does Own Auth work with Replit's Postgres database?

Yes. Own Auth uses standard Postgres and reads DATABASE_URL. Replit's SQL database is PostgreSQL-compatible and exposes the connection through environment variables.

Do my users need an Own Auth account?

They create an account with your application. Own Auth is the library your backend uses, not a separate consumer account or hosted identity profile.

Will Own Auth generate the sign-in page?

No. Your Replit app owns the UI. That requires more work than Replit Auth, but it is also what gives you full control over the sign-up, sign-in, recovery, and onboarding experience.

Conclusion

Replit Auth optimizes for getting authentication working immediately. Own Auth optimizes for making authentication part of the product you own. The right choice depends on whether Replit's identity experience is a helpful shortcut or an unwanted layer between your application and its users.