2 min read

Passkey introduction roadmap

Step-by-step conversion strategy required when expanding existing password/OTP-based authentication to Passkey

Passkey introduction roadmap thumbnail

Introduction

Passkey is a means to simultaneously improve UX and security, but it is difficult to immediately replace the existing password/OTP ecosystem. In practice, “gradual transition” is essential due to subscription channels, device diversity, and recovery policies.

This article deals with a roadmap that operates separately between new sign-ups and existing user conversions. The goal is to increase the level of security without losing users.

Passkey 도입 로드맵 커버
Wikimedia Commons 기반 무료 이미지

Problem definition

The most frustrating points in the Passkey conversion project:

  • Registration flow works well, but CS load rapidly increases due to lack of account recovery policy.
  • Login failure inquiries increase as the multi-device synchronization characteristics are not considered.
  • The priority of Passkey and existing OTP policy is ambiguous, creating a security hole.
  • The conversion rate is low as new and existing user experiences are processed through the same screen.

The key is not to add an authentication method, but to redefine the "authentication policy state machine".

Key concepts

stepsGoalPolicy Points
Phase 1Opt-in registrationMaintain existing password path
Phase 2Recommended LoginPasskey priority, OTP fallback
Phase 3security enforcementPasskey required for high-risk operations
Phase 4Toggle defaultNew registration Passkey default

Account recovery is always a separate policy. If a “lost device” scenario is not prepared, operational risks become greater than security.

Code example 1: Creating server registration options (WebAuthn)

import { generateRegistrationOptions } from "@simplewebauthn/server";

export async function createPasskeyRegistrationOptions(user: {
  id: string;
  email: string;
  displayName: string;
}) {
  return generateRegistrationOptions({
    rpName: "8SPACE",
    rpID: "www.8space.dev",
    userID: user.id,
    userName: user.email,
    userDisplayName: user.displayName,
    attestationType: "none",
    authenticatorSelection: {
      residentKey: "preferred",
      userVerification: "preferred",
    },
    timeout: 60_000,
  });
}

Code example 2: Authentication policy state transition example

type AuthState = "PASSWORD_ONLY" | "PASSKEY_ENROLLED" | "PASSKEY_REQUIRED";

export function nextAuthState(params: {
  current: AuthState;
  hasPasskey: boolean;
  riskScore: number;
}): AuthState {
  if (params.current === "PASSWORD_ONLY" && params.hasPasskey) {
    return "PASSKEY_ENROLLED";
  }

  if (params.hasPasskey && params.riskScore >= 70) {
    return "PASSKEY_REQUIRED";
  }

  return params.current;
}

Architecture flow

Mermaid diagram rendering...

Tradeoffs

  • Introduction of Passkey greatly increases phishing resistance, but initial operational complexity increases.
  • A stronger recovery policy improves security, but may cause user friction.
  • If the stage transition criteria are not indexed, sensory decisions such as “it looks good so we expand” occur.

Cleanup

Passkey conversion is not a project to add authentication methods, but a project to redesign authentication policies. By clearly dividing the transition phase and designing recovery policies and risk-based enforcement conditions together, security and UX can be achieved at the same time.

Image source

  • Cover: source link
  • License: Public domain / Author: U.S. government
  • Note: After downloading the free license image from Wikimedia Commons, it was optimized to JPG at 1600px.

Comments