08 / 10Operator24 min lesson + 120 min lab

Add Identity, Secrets, and Integrations

Connect real users and external services while keeping credentials out of code and authorization on the server.

By the end

An authenticated, least-privilege app with per-user data rules, protected secrets, integration receipts, and tested denial paths.

01

Authentication is not authorization

Authentication establishes who a user is. Authorization decides what that user may see or do. A signed-in user should not automatically see every record. Define roles, ownership, tenant or organization boundaries, and action-level permissions. Enforce them on the server for every protected read and write.

Replit offers two Agent-provisioned choices. Replit Auth requires users to sign in with Replit accounts and keeps Replit branding. Clerk Auth gives the app an independent user store and customizable branding; its development and production environments have separate users and keys. Choose before real users exist. Changing identity systems later is a user-data migration, not a visual setting. In either case, keep domain permissions explicit rather than scattering provider-specific checks through the interface.

  • Choose Replit Auth when Replit accounts and Replit-branded sign-in fit the audience.
  • Choose Clerk Auth when the app needs independent accounts and branded sign-in.
  • Ask Agent to provision the selected built-in option; do not invent a parallel password system.
  • Test development and production identities separately.
02

Design user-data scope

Decide whether a record belongs to one user, a team, an organization, or the entire application. Store the relevant ownership relationship and filter every query by the authenticated scope. Test horizontal access: one ordinary user must not retrieve or mutate another user's record by changing a URL or request identifier.

Administrative capability needs its own boundary and audit history. Avoid a single hidden boolean that unlocks everything without explanation. Name administrative actions, require appropriate roles, and record who performed them. Consider a separate admin view when ordinary and privileged workflows differ substantially.

03

Secrets are runtime configuration

API keys, tokens, signing secrets, and connection strings do not belong in source code, prompts, screenshots, or Git history. Store them in Replit's Secrets tool and read them as environment variables on the server. The browser should receive only values explicitly designed to be public.

A secret has a lifecycle: creation, least-privilege scope, named owner, rotation, revocation, and incident response. Keep development and production values separate. If a secret is exposed, remove it from visible history where practical, revoke it at the provider, create a replacement, update the intended environment, and verify the old value no longer works.

Secrets are encrypted storage, not isolation from every collaborator who can run the app. A Multiplayer collaborator can view App Secret values. In an organization, a non-owner may not see a value in the pane but can still access it through the running environment. Treat project edit or runtime access as potential secret access, invite only trusted collaborators, prefer narrowly scoped development credentials, and revoke access when collaboration ends.

04

Treat connectors and APIs as authority

A connector or API grants the project access to another system. Begin read-only when possible and request the narrowest account and scopes. Verify which project, environment, and user owns the connection. Never assume Agent can see a service merely because you can access it in another browser tab.

Separate integration reads from writes. A read can still expose private data, but a write can notify people, change records, or spend money. Put consequential writes behind server authorization, validation, an explicit user action or approval, idempotency, and an attempt log. Use synthetic destinations until the workflow is proven.

05

Make dependency failure a product state

External services fail. Design pending, succeeded, failed, and retryable states. Store a safe provider reference and last attempt time. Tell the user whether their request was accepted locally, whether the external action completed, and what will happen next. Never show success before the authoritative system confirms it.

Set timeouts and bounded retry policies. Retry automatically only when the operation is idempotent or protected by a stable idempotency key. For ambiguous outcomes, reconcile by querying the provider with the local operation identifier rather than sending the action again blindly.

Working reference

Commands and patterns

Verify configuration without disclosure

node - <<'NODE'
const required = ['DATABASE_URL', 'INTEGRATION_API_KEY'];
console.log(Object.fromEntries(required.map((key) => [key, Boolean(process.env[key])])));
NODE

Report only presence. Never echo, log, or paste the values of credentials into Agent chat or public evidence.

Secret-pattern filename check

git grep -Il -E '(API[_-]?KEY|SECRET|TOKEN|PASSWORD)[[:space:]]*[:=]' -- ':!*.lock' || true

The -l form prints only matching filenames, not the lines that may contain credentials. Treat every match as sensitive, inspect it locally without pasting values into Agent chat, and use Replit Security Center or a dedicated secrets scanner for the real review.

When the happy path breaks

Failure modes

01

Symptom

A signed-in user can open another user's record by changing an ID in the URL.

Likely cause

The app authenticates users but does not scope server-side reads and writes by ownership or organization.

Recovery

Apply server authorization to every operation, query within the actor's scope, and add cross-user denial tests.

02

Symptom

A key appears in source history, logs, browser code, or an Agent transcript.

Likely cause

The credential was treated as ordinary configuration or debug output.

Recovery

Revoke and rotate it immediately, move the replacement to Secrets, limit scope, and add source and client-bundle checks.

03

Symptom

A retry sends the same external notification or creates the same record twice.

Likely cause

The app lacks an idempotency key, durable attempt state, or provider reconciliation.

Recovery

Assign a stable operation ID, persist each attempt and provider ID, and reconcile ambiguous results before retrying.

04

Symptom

Preview works, but the published app cannot authenticate or call the integration.

Likely cause

Development and published environments have different domains, callback configuration, secrets, or resource scope.

Recovery

Maintain an environment configuration matrix and verify callback URLs, domains, and secret presence separately before republishing.

Hands-on lab

Add an authenticated approval with a safe integration

Require sign-in for the approval workflow, restrict records by scope, and send one synthetic external action with durable evidence.

  1. 01Choose Replit Auth or Clerk Auth using the account and branding tradeoff above. Use Agent to provision it and connect the authenticated identity to database users; record that development and production identities are separate where applicable.
  2. 02Define requester, reviewer, and administrator capabilities and enforce each protected operation on the server.
  3. 03Create two synthetic development users. Use separate browser profiles or private sessions to prove each is denied access to the other's private records; never reuse a production identity for this test.
  4. 04Add a development-only FAKE_PROVIDER_TOKEN through Secrets. Record its name, owner, and scope but never its value. Confirm every collaborator with project runtime access is trusted to access it.
  5. 05Ask Agent to create a development-only POST /api/fake-provider/notifications endpoint. It must return 404 when REPLIT_DEPLOYMENT equals 1, require the server-supplied fake token, and accept { operationId, requestId, event, scenario }. Store fake provider operations under a unique operationId. For scenario=success return 200 with { status: 'accepted', providerId: 'fake_' + operationId }; for scenario=reject return 503 with { code: 'FAKE_PROVIDER_UNAVAILABLE' }; for scenario=timeout return 504 with { code: 'FAKE_PROVIDER_TIMEOUT' }; for a repeated operationId return the original result without a second record.
  6. 06Wire the approval server action—not browser code—to call the fake endpoint. Use operationId op_success_001 with requestId req_success_001 for success, op_reject_001 with req_reject_001 for rejection, and op_timeout_001 with req_timeout_001 for timeout. Persist each attempt before its call and then the safe providerId or error code. The UI must show pending, succeeded, and failed/retryable states while keeping the local request and attempt history truthful.
  7. 07Trigger each scenario once with its distinct IDs. Then repeat exactly the success operation op_success_001 with the same request ID and event. Verify the repeated call returns the original provider ID without creating a second provider operation or side effect. Confirm no token appears in browser or network receipts and every scenario can be traced through its own attempt record.

Deliverable: A role matrix, denial-test evidence, secrets inventory without values, integration attempt history, and a failed-dependency recovery receipt.

Reusable artifact

Identity and integration control sheet

Review this before any external write or production credential is enabled.

IDENTITY PROVIDER: [provider and environment]
USER SCOPE: [user / team / organization / global]
ROLE -> ALLOWED ACTIONS: [matrix]
DENIAL TESTS: [unauthenticated, wrong user, wrong role, invalid transition]
SECRET NAME: [name only] | OWNER: [...] | SCOPE: [...] | ROTATE BY: [...]
COLLABORATOR ACCESS: [who can edit or run the project and therefore may access values]
INTEGRATION: [service and narrow purpose]
ACCESS: [account, scopes, read/write, environment]
OPERATION ID: [generation and uniqueness]
FAILURE POLICY: [timeout, retry, reconcile, manual recovery]
AUDIT: [actor, local record, provider ID, timestamps, result]
STOP GATE: No real-user write until [tests and approval].

Before you move on

Receipt checklist

  • Unauthenticated, wrong-user, wrong-role, and invalid-transition requests are denied by the server.
  • No secret value appears in source, Git diff, browser output, logs, screenshots, or receipts.
  • Every project collaborator with runtime access is intentionally trusted for the development credentials, or access is removed before adding them.
  • A successful external action can be traced from local operation ID to attempt record and safe provider reference.
  • The fake provider's success, reject, timeout, and duplicate-operation scenarios produce deterministic, truthful local state and bounded recovery actions.
  • Development and published identity/secret configuration are documented separately.

Primary sources

Continue with the source

Home
Book
Blog
Calugaru Labs
GitHub
LinkedIn
Email
Theme