DEV Community

Cover image for Deploying Logto as a GCP Identity Platform Alternative
Sanskriti Harmukh for Vultr

Posted on with Aashish Chaurasiya Originally published at docs.vultr.com

Deploying Logto as a GCP Identity Platform Alternative

Google Cloud Identity Platform is Google's managed CIAM service for web and mobile applications, providing user account management, customizable authentication flows, social and enterprise identity federation, MFA, and integration with Google Cloud services. It removes the need to operate an identity store, but it bills per monthly active user (MAU) in tiers where email, phone, anonymous, and social sign-in are free to 50,000 MAU while OIDC and SAML federation are free only to 50 MAU before per-user charges begin, meters phone and multi-factor messages separately, and ties the user store and its flows to a Google Cloud project. Logto is an open-source Customer Identity and Access Management (CIAM) platform built on OAuth 2.1 and OpenID Connect (OIDC) that covers the same ground on self-hosted infrastructure without per-user billing or cloud provider API dependencies — a branded sign-in experience, social and enterprise SSO federation, MFA, role-based access control (RBAC), organizations for multi-tenancy, and webhooks, all stored in a PostgreSQL database you control. This guide walks through deploying Logto as an alternative to Google Cloud Identity Platform: the Docker Compose deployment with Traefik and automatic HTTPS, the admin console, sign-in experience and branding, email and social login connectors, enterprise SSO, MFA, RBAC and API resources, organizations, application registration, webhooks, deployment verification, and migration from Identity Platform. By the end, you'll have a fully configured, self-hosted CIAM platform and a documented path for moving an existing Identity Platform user base onto it.

Before you begin, you need a Linux-based server with at least 2 CPU cores and 8 GB of RAM as a non-root user with sudo privileges, Docker and Docker Compose installed, and DNS A records pointing to your server's IP address for two subdomains: auth.example.com (Logto Core API and sign-in experience) and admin.example.com (Admin Console).


Understanding Logto Architecture

Logto covers most Identity Platform components through a self-hosted, OIDC-standard platform. The following table maps each Identity Platform feature to its Logto counterpart and notes where no equivalent exists.

Identity Platform Logto Description
Identity Platform Users Logto Users User management and hosted login pages.
Identity Platform SAML/OIDC Federation Logto Enterprise SSO Connectors (SAML/OIDC) Federation with external identity providers.
Identity Platform FirebaseUI Logto Sign-in Experience Fully customizable branded authentication flow.
Identity Platform Social Providers Logto Social Connectors Integration with over 30 social identity providers.
Identity Platform MFA Logto MFA TOTP, WebAuthn/Passkeys, SMS, Email OTP, and backup codes.
Identity Platform Blocking Functions Logto Webhooks Asynchronous event-driven webhooks (not inline).
Identity Platform OAuth Clients / SDK Configs Logto Applications OIDC clients for SPAs, web apps, and M2M services.
Identity Platform Tenants (multi-tenancy) Logto Organizations Role-based access control and multi-tenant management.
Identity Platform Account Defender No direct equivalent Use WAF, rate limiting, or a reverse proxy for protection.
Firebase / GCP Admin SDKs Logto SDKs Official SDKs for over 30 modern development frameworks.

The Logto Core service (auth.example.com) exposes the OIDC endpoints, Management API (/api), and the user-facing sign-in experience. The Admin Console (admin.example.com) is a separate frontend that manages tenant configuration through the Management API.

1. Deploy Logto with Docker Compose

Logto requires PostgreSQL 14 or later to store users, configuration, and session data. This section deploys Logto for production using Docker Compose, Traefik for automatic HTTPS with Let's Encrypt, and PostgreSQL for durable storage.

1. Create the project directory structure:

$ mkdir -p ~/logto/traefik/letsencrypt
Enter fullscreen mode Exit fullscreen mode

2. Navigate to the project directory:

$ cd ~/logto
Enter fullscreen mode Exit fullscreen mode

3. Create the Logto environment file:

$ nano .env
Enter fullscreen mode Exit fullscreen mode

4. Add the following configuration:

# Domain Configuration
LOGTO_CORE_DOMAIN=auth.example.com
LOGTO_ADMIN_DOMAIN=admin.example.com

# Logto Endpoints
ENDPOINT=https://auth.example.com
ADMIN_ENDPOINT=https://admin.example.com

# SSL Configuration
LETSENCRYPT_EMAIL=admin@example.com

# Database
DB_PASSWORD=DB-PASSWORD

# Logto image version
TAG=1.40.1

# Pins the Docker Engine API version to avoid socket communication errors with newer Traefik releases
DOCKER_API_VERSION=1.54
Enter fullscreen mode Exit fullscreen mode

Replace auth.example.com and admin.example.com with your subdomains, admin@example.com with your Let's Encrypt notification address, DB-PASSWORD with a strong PostgreSQL password, and 1.40.1 with the Logto release you want to deploy (check the Logto releases page for the latest stable version).

5. Download the Logto Docker Compose file for the pinned release. Pin the compose file URL to the same release tag as TAG in the environment file — this file is maintained by Logto.

$ wget https://raw.githubusercontent.com/logto-io/logto/v1.40.1/docker-compose.yml
Enter fullscreen mode Exit fullscreen mode

6. Update the docker-compose.yml file for production use. The official compose file ships with hardcoded database credentials labeled for demonstration; replace those defaults before deployment.

$ nano docker-compose.yml
Enter fullscreen mode Exit fullscreen mode

Find the app service and update the DB_URL under environment:

- DB_URL=postgres://postgres:${DB_PASSWORD}@postgres:5432/logto
Enter fullscreen mode Exit fullscreen mode

Find the postgres service and update POSTGRES_PASSWORD:

POSTGRES_PASSWORD: ${DB_PASSWORD}
Enter fullscreen mode Exit fullscreen mode

Pin the PostgreSQL image to a specific release for reproducible deployments:

image: postgres:17.5-alpine
Enter fullscreen mode Exit fullscreen mode

7. Create the Traefik Docker Compose override file:

$ nano traefik/docker-compose.yml
Enter fullscreen mode Exit fullscreen mode

8. Add the following configuration:

services:
  traefik:
    image: traefik:v3.7.0
    command:
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.myresolver.acme.httpchallenge=true"
      - "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web"
      - "--certificatesresolvers.myresolver.acme.email=${LETSENCRYPT_EMAIL}"
      - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
      - "--entrypoints.web.http.redirections.entryPoint.to=websecure"
      - "--entrypoints.web.http.redirections.entryPoint.scheme=https"
    ports:
      - "80:80"
      - "443:443"
    environment:
      - DOCKER_API_VERSION=${DOCKER_API_VERSION}
      - TRUST_PROXY_HEADER=true
    volumes:
      - ./letsencrypt:/letsencrypt
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      default:
        aliases:
          - ${LOGTO_CORE_DOMAIN}
          - ${LOGTO_ADMIN_DOMAIN}
  app:
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.logto-core.rule=Host(`${LOGTO_CORE_DOMAIN}`)"
      - "traefik.http.routers.logto-core.entrypoints=websecure"
      - "traefik.http.routers.logto-core.tls.certresolver=myresolver"
      - "traefik.http.routers.logto-core.service=logto-core"
      - "traefik.http.services.logto-core.loadbalancer.server.port=3001"
      - "traefik.http.routers.logto-admin.rule=Host(`${LOGTO_ADMIN_DOMAIN}`)"
      - "traefik.http.routers.logto-admin.entrypoints=websecure"
      - "traefik.http.routers.logto-admin.tls.certresolver=myresolver"
      - "traefik.http.routers.logto-admin.service=logto-admin"
      - "traefik.http.services.logto-admin.loadbalancer.server.port=3002"
Enter fullscreen mode Exit fullscreen mode

Traefik routes HTTPS traffic to Logto on subdomain-based host rules — port 3001 serves the Core API and sign-in experience, port 3002 serves the Admin Console. Let's Encrypt certificates are provisioned automatically once DNS resolves to this server. This stack pins svhd/logto to the TAG value in .env, traefik to v3.7.0, and PostgreSQL to 17.5-alpine.

9. Start the Logto stack:

$ docker compose -f docker-compose.yml -f traefik/docker-compose.yml up -d
Enter fullscreen mode Exit fullscreen mode

10. Verify the containers are running:

$ docker ps
Enter fullscreen mode Exit fullscreen mode

The output displays running containers for Traefik, Logto, and PostgreSQL.

11. Verify HTTPS on the Admin Console:

$ curl -sI https://admin.example.com
Enter fullscreen mode Exit fullscreen mode

The output returns HTTP/2 302 with location: /console/welcome on first boot.

12. Verify the OIDC discovery endpoint:

$ curl -s https://auth.example.com/oidc/.well-known/openid-configuration | head -c 200
Enter fullscreen mode Exit fullscreen mode

The output returns JSON containing authorization_endpoint and issuer values scoped to your auth.example.com domain.

2. Access the Admin Console

The Admin Console is the central management interface for configuring the Logto tenant.

  1. Open a web browser and navigate to the Logto Admin Console at https://admin.example.com.
  2. Follow the on-screen instructions to create the initial administrator account, then log in with the new credentials.
  3. Review the sidebar to confirm access to Applications, Sign-in & account, Multi-factor auth, Connectors, Enterprise SSO, API resources, Roles, Organizations, Webhooks, and Audit logs.

3. Configure the Sign-in Experience

The sign-in experience defines the look, feel, and authentication flow for your users.

Set the brand identity: navigate to Sign-in & account and select Branding, upload your logo (for example, https://example.com/logo.png) and set the primary brand color (for example, #6139F6), then click Done.

Configure the email connector: navigate to Connectors and select the Email and SMS connectors tab, click Set up under the Email connector and select SMTP. Obtain the SMTP host, port, username, and password from your email provider, and enter them in the Logto Console:

  • host: SMTP-HOST
  • Port: SMTP-PORT
  • Auth: type: login, user: SMTP-USERNAME, pass: SMTP-PASSWORD
  • From email: SENDER-EMAIL-ADDRESS
  • Reply to: REPLY-TO-EMAIL-ADDRESS

Toggle Secure to On if your provider requires TLS, send a test email, then click Save and Done.

Define sign-up identifiers and sign-in methods: on Sign-in & account → Sign-up and sign-in, select sign-up identifiers (Username, Email address, Phone number), configure sign-in methods, and click Save Changes.

Enable passwordless sign-in: on the same tab, enable Email verification code or SMS verification code under Sign-in methods, ensure the corresponding connector is configured, then click Save Changes.

Preview the sign-in UI: click Live preview on the Sign-up and sign-in page to test the branded interface and enabled sign-in methods before applying changes to production traffic.

Logto also supports SMS-based registration and sign-in via third-party providers such as Twilio or Vonage — configure an SMS connector the same way as the email connector. Users access the hosted sign-in UI through a registered application with a valid client_id and redirect URI, not by visiting auth.example.com directly; direct navigation without an application context returns an unknown-session page.

4. Set Up Social Login Connectors

  1. Navigate to Connectors in the left sidebar and select the Social connectors tab, then click Add social connector and select Google.
  2. Create a project in the Google Cloud Console: create a new project, go to APIs & Services → OAuth consent screen, configure the consent screen and add your domain (for example, example.com) as an authorized domain, go to Credentials → Create Credentials → OAuth client ID, select Web application, and add the Logto callback URI (for example, https://auth.example.com/callback/google) to Authorized redirect URIs.
  3. Copy the Client ID and Client Secret from Google and paste them into the Logto social connector configuration.
  4. Configure the Scope field — Logto requests openid, profile, and email by default; append additional scope URLs if the application needs more Google API access.
  5. Click Save and Done, then repeat the process for GitHub and Apple.
  6. On Sign-in & account → Sign-up and sign-in, under Social sign-in, click Add social connector and select the connectors you configured, then Save Changes and test with Live preview.

5. Configure Enterprise SSO

Enterprise Single Sign-On (SSO) enables corporate users to authenticate via their own Identity Provider (IdP), such as Okta or Microsoft Entra ID.

  1. Navigate to Enterprise SSO, click Add enterprise connector, and select Okta (or SAML / OIDC for a generic connector). Use the Connection guide button for provider-specific setup instructions.
  2. In your Okta dashboard, register a new OIDC application, set the Login redirect URI to the value provided by Logto, and obtain the Client ID, Client Secret, and Issuer URL.
  3. Enter these details into the Logto connector configuration and click Save. For SAML connectors, exchange IdP metadata by uploading the metadata file or entering the metadata URL.
  4. On the SSO Experience tab, add the email domains associated with the organization (for example, example.com) — users with matching email domains are automatically routed to the enterprise IdP login page, and other sign-in methods are disabled for those domains.
  5. Enable JIT provisioning to create users automatically on first SSO sign-in, then click Save changes.

6. Enable Multi-Factor Authentication

  1. Navigate to Multi-factor auth in the left sidebar.
  2. Toggle the desired MFA methods to On: Authenticator app (TOTP), WebAuthn / Passkeys (biometric or hardware key), Backup codes, and SMS or Email OTP (requires the corresponding connector).
  3. Configure the MFA Policy (optional MFA or required on every login), then click Save changes.

7. Configure RBAC and API Resources

  1. Navigate to API Resources, click Create API resource, enter an API Name and a unique API Identifier (for example, https://api.example.com/orders), and define Permissions (Scopes) such as read:orders and write:orders.
  2. Navigate to Roles, click Create role, assign the API permissions to the role, and click Save. On the Assign user screen, assign users now or click Skip to assign them later from User management.
  3. If global roles must appear in access tokens, navigate to Custom JWT and configure an access token script to inject role claims into issued JWTs.
  4. Open the API resource you created and click Check guide to view framework-specific integration code (Express, Python, Spring Boot, and others) for initializing the Logto SDK, protecting API routes, and validating the access token.

8. Set Up Organizations for Multi-Tenancy

Organizations offer multi-tenant isolation for B2B applications where users belong to different corporate entities. An organization template is a blueprint defining a consistent set of roles and permissions available to every organization in your Logto tenant.

  1. Navigate to Organization template and create Organization permissions (fine-grained, non-API actions such as read:resource, edit:resource, delete:resource).
  2. Create Organization roles (for example, Admin or Member) and map the permissions to each role.
  3. Navigate to Organizations, click Create organization, select it, and go to the Members tab.
  4. Click Add Members, assign an organization role to each member from the dropdown — Logto scopes JWT tokens to include the organization context when organization-scoped tokens are requested.
  5. Click Check guide to view integration tutorials for multi-tenant features and org-scoped tokens.

9. Register Applications

Register your frontend and backend services as applications within Logto to authenticate users and obtain tokens. Specific steps vary by application type — Single-Page App, Traditional Web App, Native App, or Machine-to-Machine — and the console provides a framework-specific tutorial for each.

  1. Navigate to Applications. If none exist, select a supported framework (React, Next.js, Node.js, and others) and click Start building; otherwise click Create application.
  2. Enter your application name, click Create application, and follow the Jumpstart guide to integrate Logto.
  3. Configure the Redirect URIs and Post Sign-out Redirect URIs, note the App ID and integration endpoint, then click Save changes.

Register at least three application types to cover common architectures: a Single-Page App (SPA) for React/Vue/Angular frontends, a Traditional Web App for server-rendered applications with a backend session, and a Machine-to-Machine (M2M) application for backend services that call the Management API without user interaction. Open the application sign-in URL or use the Logto SDK in a test client to confirm the redirect-based sign-in flow completes successfully.

10. Configure Webhooks

  1. Navigate to Webhooks, click Create webhook, enter the backend Endpoint URL and a descriptive name.
  2. Select the Webhook events to monitor (for example, User.Created, PostSignIn, User.Data.Updated), add optional Custom headers if needed, and click Create webhook.
  3. Use the Signing Key shown in the webhook settings to cryptographically verify that incoming payloads originated from your Logto instance, then send a test payload to confirm the endpoint receives and processes events.

11. Verify the Deployment

  • Infrastructure: Confirm all containers are running with docker ps — Traefik, Logto, and PostgreSQL should report an Up status.
  • TLS: Open https://admin.example.com and https://auth.example.com in a browser; both should load with valid Let's Encrypt certificates.
  • OIDC discovery: Run curl -s https://auth.example.com/oidc/.well-known/openid-configuration and confirm the issuer matches https://auth.example.com/oidc.
  • Admin Console: Create the initial admin account and confirm the dashboard loads with all sidebar sections.
  • User registration and sign-in: Register a test user through your application and confirm password-based sign-in works.
  • Social login, MFA, RBAC, and organizations: Test each configured method end to end — social sign-in through Live preview, MFA enforcement on a test user's next sign-in, an access token containing expected scopes after role assignment, and organization context appearing in the token after adding a user to an organization.
  • Audit logs: Navigate to Audit logs in the Admin Console and confirm sign-in and configuration events are recorded.

12. Migrate from GCP Identity Platform to Logto

Migrating from GCP Identity Platform to Logto involves mapping Identity Platform Users and Tenants to Logto Organizations and Users, replacing Firebase/GCP Admin SDK calls with Logto SDKs and the Management API, and converting Blocking Functions to webhooks or Custom JWT scripts. Because Identity Platform does not export password hashes or MFA secrets, most migrations follow a bulk user import with mandatory re-authentication strategy. The steps below assume you already completed the deployment, admin console, and application registration sections above.

User migration. GCP Identity Platform bundles user directories, authentication flows, OAuth client configurations, and tenant isolation into a single managed service; Logto splits these across users, the sign-in experience, applications, roles, and organizations.

  • Export: retrieve user profiles using the Firebase Admin SDK (listUsers()) or the Identity Toolkit API. For multi-tenant projects, iterate through each tenant to export tenant-scoped users.
  • Import: create users through the Logto Management API (POST /api/users at https://auth.example.com/api), authenticated with an access token from a Logto Machine-to-Machine application.
  • Passwords: Identity Platform does not expose password hashes — import users with temporary credentials and trigger a password reset on first login.
  • MFA enrollments: store the original Identity Platform/Firebase localId (UID) in Logto customData (for example, legacy_firebase_uid) to preserve linkages in downstream application databases.

Application migration. If applications use the Firebase Authentication SDK, replace Firebase Auth APIs with the Logto SDK: signInWithEmailAndPassword/signInWithPopup/embedded forms become redirect-based Universal Login; the Firebase API Key/OAuth Client ID becomes the Logto Application ID (client_id); Authorized Domains/Callback URLs become Redirect URIs and Post Sign-out Redirect URIs; token refresh moves to the Logto SDK's session management or standard OIDC refresh flows. If applications call the Identity Toolkit REST API or Firebase Admin SDK directly, replace verifyPassword/verifyCustomToken/signUp with the OIDC authorization code flow (PKCE) or client credentials flow (M2M), getAccountInfo with the OIDC UserInfo endpoint or Management API user lookup, and validate Firebase ID tokens against the Logto JWKS endpoint (https://auth.example.com/oidc/jwks, issuer https://auth.example.com/oidc) instead.

Role and group migration. Identity Platform has no native group primitive — roles are typically assigned via custom claims (setCustomUserClaims) or tenant isolation. Custom claims that gate API access or admin capabilities map to global Logto Roles: create each role (POST /api/roles), define API resource permissions, and assign users (POST /api/users/{userId}/roles) — configure a Custom JWT script to inject role claims, since global roles aren't included by default. Tenant-scoped users representing B2B customers map to Logto Organizations: create the organization (POST /api/organizations), define organization roles in the Organization template, and add members (POST /api/organizations/{id}/users), importing any relational tenant-membership data from Firestore or custom claims. Update backend route guards to parse the claims your Custom JWT script emits instead of Firebase custom claims (for example, decodedToken.admin or decodedToken.tenant_id).

Blocking Function migration. Post-confirmation/post-authentication triggers (async) map to Logto Webhooks (User.Created, PostSignIn, User.Data.Updated). Custom claims and token enrichment map to Custom JWT access token scripts, replacing setCustomUserClaims or blocking-function logic. Pre-authentication/pre-sign-up triggers (sync, blocking) map to application middleware, API gateway rules, or a custom authentication proxy — Logto webhooks cannot block or reject an in-progress sign-in or sign-up synchronously. Custom message triggers map to email/SMS connectors or a webhook consumer. Unlike Cloud Functions, which scale per invocation, Custom JWT scripts run on every token issuance and webhook consumers run as always-on services — plan capacity accordingly.

Data storage considerations. Identity Platform sessions and refresh tokens become invalid at cutover — force re-authentication and clear local Firebase SDK session state (onAuthStateChanged listeners will fire with null). Applications that store Identity Platform localId values rely on the legacy_identity_platform_uid mapping in Logto customData until updated. Replace calls to the Identity Toolkit/Firebase Admin SDK (getUser, listUsers, updateUser) with the Logto Management API at https://auth.example.com/api. Recreate any Identity Platform SAML/OIDC federation as Logto Enterprise SSO or social connectors.

Things to take care of during migration: moving embedded Firebase sign-in forms (signInWithEmailAndPassword, signInWithPopup) and direct Identity Toolkit API calls to redirect-based OIDC is the largest application-code change in most migrations; Identity Platform supports synchronous blocking functions during sign-up and sign-in, but Logto webhooks are asynchronous only, so blocking validation needs application middleware or an API gateway; Identity Platform does not grant end users direct cloud-resource access via IAM roles, so there's no equivalent to migrate away from (a separate Workload Identity Federation setup for backend services is unrelated to end-user auth); Identity Platform's Account Defender has no direct Logto OSS equivalent, so implement rate limiting or WAF rules at the reverse proxy; TOTP secrets and enrolled phone numbers can't be extracted, so users must re-enroll after cutover; Identity Platform ID tokens nest provider and tenant metadata under a firebase claim (sign_in_provider, tenant), while Logto issues standard OIDC claims (sub, email, scope, organization_id); and Identity Platform's tiered per-MAU pricing plus separate SMS/phone-auth charges changes to an infrastructure-based cost model, so calculate total cost of ownership before cutover. Run a phased migration: import users first, validate token flows in a staging tenant, then redirect production traffic to Logto and disable sign-in through the Identity Platform project or tenant.

Next Steps

  • Configure a Custom JWT script to enrich access tokens with the role and organization claims your applications expect.
  • Set up organization-scoped applications for each B2B tenant migrating off Identity Platform Tenants.
  • Add rate limiting or WAF rules at the reverse proxy layer to replace Identity Platform's Account Defender.
  • Run a staging-tenant migration rehearsal before cutting production traffic over from Identity Platform.

For the full guide with additional tips, visit the original article on Vultr Docs.

Top comments (0)