CINXE.COM
Allow passkey reuse across your sites with Related Origin Requests | Articles | web.dev
<!doctype html> <html lang="en" dir="ltr"> <head> <meta name="google-signin-client-id" content="157101835696-ooapojlodmuabs2do2vuhhnf90bccmoi.apps.googleusercontent.com"> <meta name="google-signin-scope" content="profile email https://www.googleapis.com/auth/developerprofiles https://www.googleapis.com/auth/developerprofiles.award"> <meta property="og:site_name" content="web.dev"> <meta property="og:type" content="website"><meta name="theme-color" content="#3740ff"><meta charset="utf-8"> <meta content="IE=Edge" http-equiv="X-UA-Compatible"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="manifest" href="/_pwa/web/manifest.json" crossorigin="use-credentials"> <link rel="preconnect" href="//www.gstatic.com" crossorigin> <link rel="preconnect" href="//fonts.gstatic.com" crossorigin> <link rel="preconnect" href="//fonts.googleapis.com" crossorigin> <link rel="preconnect" href="//apis.google.com" crossorigin> <link rel="preconnect" href="//www.google-analytics.com" crossorigin><link rel="stylesheet" href="//fonts.googleapis.com/css?family=Google+Sans:400,500|Roboto:400,400italic,500,500italic,700,700italic|Roboto+Mono:400,500,700&display=swap"> <link rel="stylesheet" href="//fonts.googleapis.com/css2?family=Material+Icons&family=Material+Symbols+Outlined&display=block"><link rel="stylesheet" href="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/web/css/app.css"> <link rel="stylesheet" href="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/web/css/dark-theme.css" disabled> <link rel="shortcut icon" href="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/web/images/favicon.png"> <link rel="apple-touch-icon" href="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/web/images/touchicon-180.png"><link rel="canonical" href="https://web.dev/articles/webauthn-related-origin-requests"><link rel="search" type="application/opensearchdescription+xml" title="web.dev" href="https://web.dev/s/opensearch.xml"> <link rel="alternate" hreflang="en" href="https://web.dev/articles/webauthn-related-origin-requests" /><link rel="alternate" hreflang="x-default" href="https://web.dev/articles/webauthn-related-origin-requests" /><link rel="alternate" hreflang="ar" href="https://web.dev/articles/webauthn-related-origin-requests?hl=ar" /><link rel="alternate" hreflang="bn" href="https://web.dev/articles/webauthn-related-origin-requests?hl=bn" /><link rel="alternate" hreflang="zh-Hans" href="https://web.dev/articles/webauthn-related-origin-requests?hl=zh-cn" /><link rel="alternate" hreflang="zh-Hant" href="https://web.dev/articles/webauthn-related-origin-requests?hl=zh-tw" /><link rel="alternate" hreflang="fa" href="https://web.dev/articles/webauthn-related-origin-requests?hl=fa" /><link rel="alternate" hreflang="fr" href="https://web.dev/articles/webauthn-related-origin-requests?hl=fr" /><link rel="alternate" hreflang="de" href="https://web.dev/articles/webauthn-related-origin-requests?hl=de" /><link rel="alternate" hreflang="he" href="https://web.dev/articles/webauthn-related-origin-requests?hl=he" /><link rel="alternate" hreflang="hi" href="https://web.dev/articles/webauthn-related-origin-requests?hl=hi" /><link rel="alternate" hreflang="id" href="https://web.dev/articles/webauthn-related-origin-requests?hl=id" /><link rel="alternate" hreflang="it" href="https://web.dev/articles/webauthn-related-origin-requests?hl=it" /><link rel="alternate" hreflang="ja" href="https://web.dev/articles/webauthn-related-origin-requests?hl=ja" /><link rel="alternate" hreflang="ko" href="https://web.dev/articles/webauthn-related-origin-requests?hl=ko" /><link rel="alternate" hreflang="pl" href="https://web.dev/articles/webauthn-related-origin-requests?hl=pl" /><link rel="alternate" hreflang="pt-BR" href="https://web.dev/articles/webauthn-related-origin-requests?hl=pt-br" /><link rel="alternate" hreflang="ru" href="https://web.dev/articles/webauthn-related-origin-requests?hl=ru" /><link rel="alternate" hreflang="es-419" href="https://web.dev/articles/webauthn-related-origin-requests?hl=es-419" /><link rel="alternate" hreflang="th" href="https://web.dev/articles/webauthn-related-origin-requests?hl=th" /><link rel="alternate" hreflang="tr" href="https://web.dev/articles/webauthn-related-origin-requests?hl=tr" /><link rel="alternate" hreflang="vi" href="https://web.dev/articles/webauthn-related-origin-requests?hl=vi" /><link rel="alternate" hreflang="en-cn" href="https://web.developers.google.cn/articles/webauthn-related-origin-requests" /><link rel="alternate" hreflang="x-default" href="https://web.developers.google.cn/articles/webauthn-related-origin-requests" /><link rel="alternate" hreflang="ar-cn" href="https://web.developers.google.cn/articles/webauthn-related-origin-requests?hl=ar" /><link rel="alternate" hreflang="bn-cn" href="https://web.developers.google.cn/articles/webauthn-related-origin-requests?hl=bn" /><link rel="alternate" hreflang="zh-Hans-cn" href="https://web.developers.google.cn/articles/webauthn-related-origin-requests?hl=zh-cn" /><link rel="alternate" hreflang="zh-Hant-cn" href="https://web.developers.google.cn/articles/webauthn-related-origin-requests?hl=zh-tw" /><link rel="alternate" hreflang="fa-cn" href="https://web.developers.google.cn/articles/webauthn-related-origin-requests?hl=fa" /><link rel="alternate" hreflang="fr-cn" href="https://web.developers.google.cn/articles/webauthn-related-origin-requests?hl=fr" /><link rel="alternate" hreflang="de-cn" href="https://web.developers.google.cn/articles/webauthn-related-origin-requests?hl=de" /><link rel="alternate" hreflang="he-cn" href="https://web.developers.google.cn/articles/webauthn-related-origin-requests?hl=he" /><link rel="alternate" hreflang="hi-cn" href="https://web.developers.google.cn/articles/webauthn-related-origin-requests?hl=hi" /><link rel="alternate" hreflang="id-cn" href="https://web.developers.google.cn/articles/webauthn-related-origin-requests?hl=id" /><link rel="alternate" hreflang="it-cn" href="https://web.developers.google.cn/articles/webauthn-related-origin-requests?hl=it" /><link rel="alternate" hreflang="ja-cn" href="https://web.developers.google.cn/articles/webauthn-related-origin-requests?hl=ja" /><link rel="alternate" hreflang="ko-cn" href="https://web.developers.google.cn/articles/webauthn-related-origin-requests?hl=ko" /><link rel="alternate" hreflang="pl-cn" href="https://web.developers.google.cn/articles/webauthn-related-origin-requests?hl=pl" /><link rel="alternate" hreflang="pt-BR-cn" href="https://web.developers.google.cn/articles/webauthn-related-origin-requests?hl=pt-br" /><link rel="alternate" hreflang="ru-cn" href="https://web.developers.google.cn/articles/webauthn-related-origin-requests?hl=ru" /><link rel="alternate" hreflang="es-419-cn" href="https://web.developers.google.cn/articles/webauthn-related-origin-requests?hl=es-419" /><link rel="alternate" hreflang="th-cn" href="https://web.developers.google.cn/articles/webauthn-related-origin-requests?hl=th" /><link rel="alternate" hreflang="tr-cn" href="https://web.developers.google.cn/articles/webauthn-related-origin-requests?hl=tr" /><link rel="alternate" hreflang="vi-cn" href="https://web.developers.google.cn/articles/webauthn-related-origin-requests?hl=vi" /><title>Allow passkey reuse across your sites with Related Origin Requests | Articles | web.dev</title> <meta property="og:title" content="Allow passkey reuse across your sites with Related Origin Requests | Articles | web.dev"><meta name="description" content="Learn how to use Related Origin Requests to allow passkey reuse across your sites."> <meta property="og:description" content="Learn how to use Related Origin Requests to allow passkey reuse across your sites."><meta property="og:url" content="https://web.dev/articles/webauthn-related-origin-requests"><meta property="og:image" content="https://web.dev/static/articles/webauthn-related-origin-requests/image/thumbnail.jpg"> <meta property="og:image:width" content="1200"> <meta property="og:image:height" content="675"><meta property="og:locale" content="en"><meta name="twitter:card" content="summary_large_image"><script type="application/ld+json"> { "@context": "https://schema.org", "@type": "Article", "dateModified": "2024-08-22", "headline": "Allow passkey reuse across your sites with Related Origin Requests" } </script><script type="application/ld+json"> { "@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [{ "@type": "ListItem", "position": 1, "name": "Articles", "item": "https://web.dev/articles" },{ "@type": "ListItem", "position": 2, "name": "Allow passkey reuse across your sites with Related Origin Requests", "item": "https://web.dev/articles/webauthn-related-origin-requests" }] } </script> <link rel="stylesheet" href="/extras.css"></head> <body class="" template="page" theme="web-theme" type="article" appearance layout="docs" display-toc pending> <devsite-progress type="indeterminate" id="app-progress"></devsite-progress> <section class="devsite-wrapper"> <devsite-cookie-notification-bar></devsite-cookie-notification-bar><devsite-header role="banner"> <div class="devsite-header--inner nocontent"> <div class="devsite-top-logo-row-wrapper-wrapper"> <div class="devsite-top-logo-row-wrapper"> <div class="devsite-top-logo-row"> <button type="button" id="devsite-hamburger-menu" class="devsite-header-icon-button button-flat material-icons gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Navigation menu button" visually-hidden aria-label="Open menu"> </button> <div class="devsite-product-name-wrapper"> <a href="/" class="devsite-site-logo-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Site logo" track-type="globalNav" track-name="webDev" track-metadata-position="nav" track-metadata-eventDetail="nav"> <picture> <source srcset="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/web/images/lockup-dark-theme.svg" media="(prefers-color-scheme: dark)" class="devsite-dark-theme" alt="web.dev"> <img src="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/web/images/lockup.svg" class="devsite-site-logo" alt="web.dev"> </picture> </a> <span class="devsite-product-name"> <ul class="devsite-breadcrumb-list" > <li class="devsite-breadcrumb-item "> </li> </ul> </span> </div> <div class="devsite-top-logo-row-middle"> <div class="devsite-header-upper-tabs"> <devsite-tabs class="upper-tabs"> <nav class="devsite-tabs-wrapper" aria-label="Upper tabs"> <tab > <a href="https://web.dev/about" track-metadata-eventdetail="https://web.dev/about" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - about" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: About" track-name="about" > About </a> </tab> <tab > <a href="https://web.dev/html" track-metadata-eventdetail="https://web.dev/html" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - html" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: HTML" track-name="html" > HTML </a> </tab> <tab > <a href="https://web.dev/css" track-metadata-eventdetail="https://web.dev/css" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - css" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: CSS" track-name="css" > CSS </a> </tab> <tab > <a href="https://web.dev/javascript" track-metadata-eventdetail="https://web.dev/javascript" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - javascript" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: JavaScript" track-name="javascript" > JavaScript </a> </tab> <tab > <a href="https://web.dev/blog" track-metadata-eventdetail="https://web.dev/blog" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - blog" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Blog" track-name="blog" > Blog </a> </tab> <tab > <a href="https://web.dev/learn" track-metadata-eventdetail="https://web.dev/learn" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - learn" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Learn" track-name="learn" > Learn </a> </tab> <tab class="devsite-active"> <a href="https://web.dev/explore" track-metadata-eventdetail="https://web.dev/explore" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - explore" track-metadata-module="primary nav" aria-label="Explore, selected" data-category="Site-Wide Custom Events" data-label="Tab: Explore" track-name="explore" > Explore </a> </tab> <tab > <a href="https://web.dev/patterns" track-metadata-eventdetail="https://web.dev/patterns" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - patterns" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Patterns" track-name="patterns" > Patterns </a> </tab> <tab > <a href="https://web.dev/case-studies" track-metadata-eventdetail="https://web.dev/case-studies" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - case studies" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Case studies" track-name="case studies" > Case studies </a> </tab> </nav> </devsite-tabs> </div> <devsite-search enable-signin enable-search enable-suggestions enable-query-completion project-name="Articles" tenant-name="web.dev" > <form class="devsite-search-form" action="https://web.dev/s/results" method="GET"> <div class="devsite-search-container"> <button type="button" search-open class="devsite-search-button devsite-header-icon-button button-flat material-icons" aria-label="Open search"></button> <div class="devsite-searchbox"> <input aria-activedescendant="" aria-autocomplete="list" aria-label="Search" aria-expanded="false" aria-haspopup="listbox" autocomplete="off" class="devsite-search-field devsite-search-query" name="q" placeholder="Search" role="combobox" type="text" value="" > <div class="devsite-search-image material-icons" aria-hidden="true"> </div> <div class="devsite-search-shortcut-icon-container" aria-hidden="true"> <kbd class="devsite-search-shortcut-icon">/</kbd> </div> </div> </div> </form> <button type="button" search-close class="devsite-search-button devsite-header-icon-button button-flat material-icons" aria-label="Close search"></button> </devsite-search> </div> <devsite-appearance-selector></devsite-appearance-selector> <devsite-language-selector> <ul role="presentation"> <li role="presentation"> <a role="menuitem" lang="en" >English</a> </li> <li role="presentation"> <a role="menuitem" lang="de" >Deutsch</a> </li> <li role="presentation"> <a role="menuitem" lang="es_419" >Español – América Latina</a> </li> <li role="presentation"> <a role="menuitem" lang="fr" >Français</a> </li> <li role="presentation"> <a role="menuitem" lang="id" >Indonesia</a> </li> <li role="presentation"> <a role="menuitem" lang="it" >Italiano</a> </li> <li role="presentation"> <a role="menuitem" lang="pl" >Polski</a> </li> <li role="presentation"> <a role="menuitem" lang="pt_br" >Português – Brasil</a> </li> <li role="presentation"> <a role="menuitem" lang="vi" >Tiếng Việt</a> </li> <li role="presentation"> <a role="menuitem" lang="tr" >Türkçe</a> </li> <li role="presentation"> <a role="menuitem" lang="ru" >Русский</a> </li> <li role="presentation"> <a role="menuitem" lang="he" >עברית</a> </li> <li role="presentation"> <a role="menuitem" lang="ar" >العربيّة</a> </li> <li role="presentation"> <a role="menuitem" lang="fa" >فارسی</a> </li> <li role="presentation"> <a role="menuitem" lang="hi" >हिंदी</a> </li> <li role="presentation"> <a role="menuitem" lang="bn" >বাংলা</a> </li> <li role="presentation"> <a role="menuitem" lang="th" >ภาษาไทย</a> </li> <li role="presentation"> <a role="menuitem" lang="zh_cn" >中文 – 简体</a> </li> <li role="presentation"> <a role="menuitem" lang="zh_tw" >中文 – 繁體</a> </li> <li role="presentation"> <a role="menuitem" lang="ja" >日本語</a> </li> <li role="presentation"> <a role="menuitem" lang="ko" >한국어</a> </li> </ul> </devsite-language-selector> <devsite-user enable-profiles id="devsite-user"> <span class="button devsite-top-button" aria-hidden="true" visually-hidden>Sign in</span> </devsite-user> </div> </div> </div> <div class="devsite-collapsible-section "> <div class="devsite-header-background"> <div class="devsite-product-id-row" > <div class="devsite-product-description-row"> <ul class="devsite-breadcrumb-list" > <li class="devsite-breadcrumb-item "> <a href="https://web.dev/explore" class="devsite-breadcrumb-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Lower Header" data-value="1" track-type="globalNav" track-name="breadcrumb" track-metadata-position="1" track-metadata-eventdetail="" > Collections </a> </li> </ul> </div> </div> <div class="devsite-doc-set-nav-row"> <devsite-tabs class="lower-tabs"> <nav class="devsite-tabs-wrapper" aria-label="Lower tabs"> <tab > <a href="https://web.dev/explore/learn-core-web-vitals" track-metadata-eventdetail="https://web.dev/explore/learn-core-web-vitals" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - core web vitals" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Core Web Vitals" track-name="core web vitals" > Core Web Vitals </a> </tab> <tab > <a href="https://web.dev/explore/metrics" track-metadata-eventdetail="https://web.dev/explore/metrics" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - metrics" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Metrics" track-name="metrics" > Metrics </a> </tab> <tab > <a href="https://web.dev/explore/fast" track-metadata-eventdetail="https://web.dev/explore/fast" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - fast load times" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Fast load times" track-name="fast load times" > Fast load times </a> </tab> <tab > <a href="https://web.dev/explore/ai" track-metadata-eventdetail="https://web.dev/explore/ai" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - ai" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: AI" track-name="ai" > AI </a> </tab> <tab > <a href="https://web.dev/explore/how-to-optimize-inp" track-metadata-eventdetail="https://web.dev/explore/how-to-optimize-inp" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - optimize interaction to next paint (inp)" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Optimize Interaction to Next Paint (INP)" track-name="optimize interaction to next paint (inp)" > Optimize Interaction to Next Paint (INP) </a> </tab> <tab > <a href="https://web.dev/explore/progressive-web-apps" track-metadata-eventdetail="https://web.dev/explore/progressive-web-apps" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - progressive web apps" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Progressive Web Apps" track-name="progressive web apps" > Progressive Web Apps </a> </tab> <tab > <a href="https://web.dev/accessibility" track-metadata-eventdetail="https://web.dev/accessibility" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - accessible to all" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Accessible to all" track-name="accessible to all" > Accessible to all </a> </tab> <tab > <a href="https://web.dev/explore/reliable" track-metadata-eventdetail="https://web.dev/explore/reliable" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - network reliability" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Network reliability" track-name="network reliability" > Network reliability </a> </tab> <tab > <a href="https://web.dev/explore/secure" track-metadata-eventdetail="https://web.dev/explore/secure" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - safe and secure" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Safe and secure" track-name="safe and secure" > Safe and secure </a> </tab> <tab > <a href="https://web.dev/explore/discoverable" track-metadata-eventdetail="https://web.dev/explore/discoverable" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - easily discoverable" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Easily discoverable" track-name="easily discoverable" > Easily discoverable </a> </tab> <tab > <a href="https://web.dev/explore/payments" track-metadata-eventdetail="https://web.dev/explore/payments" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - web payments" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Web Payments" track-name="web payments" > Web Payments </a> </tab> <tab > <a href="https://web.dev/explore/media" track-metadata-eventdetail="https://web.dev/explore/media" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - media" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Media" track-name="media" > Media </a> </tab> <tab > <a href="https://web.dev/explore/devices" track-metadata-eventdetail="https://web.dev/explore/devices" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - devices" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Devices" track-name="devices" > Devices </a> </tab> <tab > <a href="https://web.dev/explore/animations" track-metadata-eventdetail="https://web.dev/explore/animations" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - animations" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Animations" track-name="animations" > Animations </a> </tab> <tab class="devsite-active"> <a href="https://web.dev/explore/identity" track-metadata-eventdetail="https://web.dev/explore/identity" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - identity" track-metadata-module="primary nav" aria-label="Identity, selected" data-category="Site-Wide Custom Events" data-label="Tab: Identity" track-name="identity" > Identity </a> </tab> <tab > <a href="https://web.dev/explore/webassembly" track-metadata-eventdetail="https://web.dev/explore/webassembly" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - webassembly" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: WebAssembly" track-name="webassembly" > WebAssembly </a> </tab> <tab > <a href="https://web.dev/explore/test-automation" track-metadata-eventdetail="https://web.dev/explore/test-automation" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - test automation" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Test automation" track-name="test automation" > Test automation </a> </tab> <tab > <a href="https://web.dev/explore/react" track-metadata-eventdetail="https://web.dev/explore/react" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - react" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: React" track-name="react" > React </a> </tab> <tab > <a href="https://web.dev/explore/angular" track-metadata-eventdetail="https://web.dev/explore/angular" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - angular" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Angular" track-name="angular" > Angular </a> </tab> <tab > <a href="https://web.dev/explore/mini-apps" track-metadata-eventdetail="https://web.dev/explore/mini-apps" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - mini apps" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Mini apps" track-name="mini apps" > Mini apps </a> </tab> </nav> </devsite-tabs> </div> </div> </div> </div> </devsite-header> <devsite-book-nav scrollbars > <div class="devsite-book-nav-filter" hidden> <span class="filter-list-icon material-icons" aria-hidden="true"></span> <input type="text" placeholder="Filter" aria-label="Type to filter" role="searchbox"> <span class="filter-clear-button hidden" data-title="Clear filter" aria-label="Clear filter" role="button" tabindex="0"></span> </div> <nav class="devsite-book-nav devsite-nav nocontent" aria-label="Side menu"> <div class="devsite-mobile-header"> <button type="button" id="devsite-close-nav" class="devsite-header-icon-button button-flat material-icons gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Close navigation" aria-label="Close navigation"> </button> <div class="devsite-product-name-wrapper"> <a href="/" class="devsite-site-logo-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Site logo" track-type="globalNav" track-name="webDev" track-metadata-position="nav" track-metadata-eventDetail="nav"> <picture> <source srcset="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/web/images/lockup-dark-theme.svg" media="(prefers-color-scheme: dark)" class="devsite-dark-theme" alt="web.dev"> <img src="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/web/images/lockup.svg" class="devsite-site-logo" alt="web.dev"> </picture> </a> <span class="devsite-product-name"> <ul class="devsite-breadcrumb-list" > <li class="devsite-breadcrumb-item "> </li> </ul> </span> </div> </div> <div class="devsite-book-nav-wrapper"> <div class="devsite-mobile-nav-top"> <ul class="devsite-nav-list"> <li class="devsite-nav-item"> <a href="/about" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: About" track-name="about" data-category="Site-Wide Custom Events" data-label="Responsive Tab: About" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > About </span> </a> </li> <li class="devsite-nav-item"> <a href="/html" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: HTML" track-name="html" data-category="Site-Wide Custom Events" data-label="Responsive Tab: HTML" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > HTML </span> </a> </li> <li class="devsite-nav-item"> <a href="/css" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: CSS" track-name="css" data-category="Site-Wide Custom Events" data-label="Responsive Tab: CSS" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > CSS </span> </a> </li> <li class="devsite-nav-item"> <a href="/javascript" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: JavaScript" track-name="javascript" data-category="Site-Wide Custom Events" data-label="Responsive Tab: JavaScript" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > JavaScript </span> </a> </li> <li class="devsite-nav-item"> <a href="/blog" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: Blog" track-name="blog" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Blog" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Blog </span> </a> </li> <li class="devsite-nav-item"> <a href="/learn" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: Learn" track-name="learn" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Learn" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Learn </span> </a> </li> <li class="devsite-nav-item"> <a href="/explore" class="devsite-nav-title gc-analytics-event devsite-nav-active" data-category="Site-Wide Custom Events" data-label="Tab: Explore" track-name="explore" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Explore" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Explore </span> </a> <ul class="devsite-nav-responsive-tabs"> <li class="devsite-nav-item"> <a href="/explore/learn-core-web-vitals" class="devsite-nav-title gc-analytics-event devsite-nav-has-children " data-category="Site-Wide Custom Events" data-label="Tab: Core Web Vitals" track-name="core web vitals" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Core Web Vitals" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Core Web Vitals </span> <span class="devsite-nav-icon material-icons" data-icon="forward" > </span> </a> </li> <li class="devsite-nav-item"> <a href="/explore/metrics" class="devsite-nav-title gc-analytics-event devsite-nav-has-children " data-category="Site-Wide Custom Events" data-label="Tab: Metrics" track-name="metrics" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Metrics" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Metrics </span> <span class="devsite-nav-icon material-icons" data-icon="forward" > </span> </a> </li> <li class="devsite-nav-item"> <a href="/explore/fast" class="devsite-nav-title gc-analytics-event devsite-nav-has-children " data-category="Site-Wide Custom Events" data-label="Tab: Fast load times" track-name="fast load times" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Fast load times" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Fast load times </span> <span class="devsite-nav-icon material-icons" data-icon="forward" > </span> </a> </li> <li class="devsite-nav-item"> <a href="/explore/ai" class="devsite-nav-title gc-analytics-event devsite-nav-has-children " data-category="Site-Wide Custom Events" data-label="Tab: AI" track-name="ai" data-category="Site-Wide Custom Events" data-label="Responsive Tab: AI" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > AI </span> <span class="devsite-nav-icon material-icons" data-icon="forward" > </span> </a> </li> <li class="devsite-nav-item"> <a href="/explore/how-to-optimize-inp" class="devsite-nav-title gc-analytics-event devsite-nav-has-children " data-category="Site-Wide Custom Events" data-label="Tab: Optimize Interaction to Next Paint (INP)" track-name="optimize interaction to next paint (inp)" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Optimize Interaction to Next Paint (INP)" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Optimize Interaction to Next Paint (INP) </span> <span class="devsite-nav-icon material-icons" data-icon="forward" > </span> </a> </li> <li class="devsite-nav-item"> <a href="/explore/progressive-web-apps" class="devsite-nav-title gc-analytics-event devsite-nav-has-children " data-category="Site-Wide Custom Events" data-label="Tab: Progressive Web Apps" track-name="progressive web apps" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Progressive Web Apps" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Progressive Web Apps </span> <span class="devsite-nav-icon material-icons" data-icon="forward" > </span> </a> </li> <li class="devsite-nav-item"> <a href="/accessibility" class="devsite-nav-title gc-analytics-event devsite-nav-has-children " data-category="Site-Wide Custom Events" data-label="Tab: Accessible to all" track-name="accessible to all" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Accessible to all" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Accessible to all </span> <span class="devsite-nav-icon material-icons" data-icon="forward" > </span> </a> </li> <li class="devsite-nav-item"> <a href="/explore/reliable" class="devsite-nav-title gc-analytics-event devsite-nav-has-children " data-category="Site-Wide Custom Events" data-label="Tab: Network reliability" track-name="network reliability" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Network reliability" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Network reliability </span> <span class="devsite-nav-icon material-icons" data-icon="forward" > </span> </a> </li> <li class="devsite-nav-item"> <a href="/explore/secure" class="devsite-nav-title gc-analytics-event devsite-nav-has-children " data-category="Site-Wide Custom Events" data-label="Tab: Safe and secure" track-name="safe and secure" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Safe and secure" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Safe and secure </span> <span class="devsite-nav-icon material-icons" data-icon="forward" > </span> </a> </li> <li class="devsite-nav-item"> <a href="/explore/discoverable" class="devsite-nav-title gc-analytics-event devsite-nav-has-children " data-category="Site-Wide Custom Events" data-label="Tab: Easily discoverable" track-name="easily discoverable" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Easily discoverable" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Easily discoverable </span> <span class="devsite-nav-icon material-icons" data-icon="forward" > </span> </a> </li> <li class="devsite-nav-item"> <a href="/explore/payments" class="devsite-nav-title gc-analytics-event devsite-nav-has-children " data-category="Site-Wide Custom Events" data-label="Tab: Web Payments" track-name="web payments" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Web Payments" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Web Payments </span> <span class="devsite-nav-icon material-icons" data-icon="forward" > </span> </a> </li> <li class="devsite-nav-item"> <a href="/explore/media" class="devsite-nav-title gc-analytics-event devsite-nav-has-children " data-category="Site-Wide Custom Events" data-label="Tab: Media" track-name="media" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Media" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Media </span> <span class="devsite-nav-icon material-icons" data-icon="forward" > </span> </a> </li> <li class="devsite-nav-item"> <a href="/explore/devices" class="devsite-nav-title gc-analytics-event devsite-nav-has-children " data-category="Site-Wide Custom Events" data-label="Tab: Devices" track-name="devices" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Devices" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Devices </span> <span class="devsite-nav-icon material-icons" data-icon="forward" > </span> </a> </li> <li class="devsite-nav-item"> <a href="/explore/animations" class="devsite-nav-title gc-analytics-event devsite-nav-has-children " data-category="Site-Wide Custom Events" data-label="Tab: Animations" track-name="animations" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Animations" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Animations </span> <span class="devsite-nav-icon material-icons" data-icon="forward" > </span> </a> </li> <li class="devsite-nav-item"> <a href="/explore/identity" class="devsite-nav-title gc-analytics-event devsite-nav-has-children devsite-nav-active" data-category="Site-Wide Custom Events" data-label="Tab: Identity" track-name="identity" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Identity" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip menu="_book"> Identity </span> <span class="devsite-nav-icon material-icons" data-icon="forward" menu="_book"> </span> </a> </li> <li class="devsite-nav-item"> <a href="/explore/webassembly" class="devsite-nav-title gc-analytics-event devsite-nav-has-children " data-category="Site-Wide Custom Events" data-label="Tab: WebAssembly" track-name="webassembly" data-category="Site-Wide Custom Events" data-label="Responsive Tab: WebAssembly" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > WebAssembly </span> <span class="devsite-nav-icon material-icons" data-icon="forward" > </span> </a> </li> <li class="devsite-nav-item"> <a href="/explore/test-automation" class="devsite-nav-title gc-analytics-event devsite-nav-has-children " data-category="Site-Wide Custom Events" data-label="Tab: Test automation" track-name="test automation" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Test automation" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Test automation </span> <span class="devsite-nav-icon material-icons" data-icon="forward" > </span> </a> </li> <li class="devsite-nav-item"> <a href="/explore/react" class="devsite-nav-title gc-analytics-event devsite-nav-has-children " data-category="Site-Wide Custom Events" data-label="Tab: React" track-name="react" data-category="Site-Wide Custom Events" data-label="Responsive Tab: React" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > React </span> <span class="devsite-nav-icon material-icons" data-icon="forward" > </span> </a> </li> <li class="devsite-nav-item"> <a href="/explore/angular" class="devsite-nav-title gc-analytics-event devsite-nav-has-children " data-category="Site-Wide Custom Events" data-label="Tab: Angular" track-name="angular" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Angular" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Angular </span> <span class="devsite-nav-icon material-icons" data-icon="forward" > </span> </a> </li> <li class="devsite-nav-item"> <a href="/explore/mini-apps" class="devsite-nav-title gc-analytics-event devsite-nav-has-children " data-category="Site-Wide Custom Events" data-label="Tab: Mini apps" track-name="mini apps" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Mini apps" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Mini apps </span> <span class="devsite-nav-icon material-icons" data-icon="forward" > </span> </a> </li> </ul> </li> <li class="devsite-nav-item"> <a href="/patterns" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: Patterns" track-name="patterns" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Patterns" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Patterns </span> </a> </li> <li class="devsite-nav-item"> <a href="/case-studies" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: Case studies" track-name="case studies" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Case studies" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Case studies </span> </a> </li> </ul> </div> <div class="devsite-mobile-nav-bottom"> <ul class="devsite-nav-list" menu="_book"> <li class="devsite-nav-item devsite-nav-heading"><div class="devsite-nav-title devsite-nav-title-no-path"> <span class="devsite-nav-text" tooltip>Understand authentication basics</span> </div></li> <li class="devsite-nav-item"><a href="/articles/sign-in-form-best-practices" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: /articles/sign-in-form-best-practices" track-type="bookNav" track-name="click" track-metadata-eventdetail="/articles/sign-in-form-best-practices" ><span class="devsite-nav-text" tooltip>Sign-in form best practices</span></a></li> <li class="devsite-nav-item devsite-nav-external"><a href="https://web.dev/codelab-sign-in-form-best-practices/" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: https://web.dev/codelab-sign-in-form-best-practices/" track-type="bookNav" track-name="click" track-metadata-eventdetail="https://web.dev/codelab-sign-in-form-best-practices/" ><span class="devsite-nav-text" tooltip>[Codelab] Use cross-platform browser features to build a sign-in form</span><span class="devsite-nav-icon material-icons" data-icon="external" data-title="External" aria-hidden="true"></span></a></li> <li class="devsite-nav-item"><a href="/articles/sign-up-form-best-practices" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: /articles/sign-up-form-best-practices" track-type="bookNav" track-name="click" track-metadata-eventdetail="/articles/sign-up-form-best-practices" ><span class="devsite-nav-text" tooltip>Sign-up form best practices</span></a></li> <li class="devsite-nav-item devsite-nav-external"><a href="https://web.dev/codelab-sign-up-form-best-practices/" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: https://web.dev/codelab-sign-up-form-best-practices/" track-type="bookNav" track-name="click" track-metadata-eventdetail="https://web.dev/codelab-sign-up-form-best-practices/" ><span class="devsite-nav-text" tooltip>[Codelab] Sign-up form best practices codelab</span><span class="devsite-nav-icon material-icons" data-icon="external" data-title="External" aria-hidden="true"></span></a></li> <li class="devsite-nav-item"><a href="/articles/sign-out-best-practices" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: /articles/sign-out-best-practices" track-type="bookNav" track-name="click" track-metadata-eventdetail="/articles/sign-out-best-practices" ><span class="devsite-nav-text" tooltip>What makes for a good sign-out experience?</span></a></li> <li class="devsite-nav-item devsite-nav-heading"><div class="devsite-nav-title devsite-nav-title-no-path"> <span class="devsite-nav-text" tooltip>Build authentication systems with modern APIs</span> </div></li> <li class="devsite-nav-item devsite-nav-external"><a href="https://developer.chrome.com/docs/identity/web-apis/web-otp" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: https://developer.chrome.com/docs/identity/web-apis/web-otp" track-type="bookNav" track-name="click" track-metadata-eventdetail="https://developer.chrome.com/docs/identity/web-apis/web-otp" ><span class="devsite-nav-text" tooltip>Verify phone numbers on the web with the WebOTP API</span><span class="devsite-nav-icon material-icons" data-icon="external" data-title="External" aria-hidden="true"></span></a></li> <li class="devsite-nav-item"><a href="/articles/change-password-url" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: /articles/change-password-url" track-type="bookNav" track-name="click" track-metadata-eventdetail="/articles/change-password-url" ><span class="devsite-nav-text" tooltip>Help users change passwords easily by adding a well-known URL for changing passwords</span></a></li> <li class="devsite-nav-item devsite-nav-heading"><div class="devsite-nav-title devsite-nav-title-no-path"> <span class="devsite-nav-text" tooltip>Strengthen security with two-factor authentication</span> </div></li> <li class="devsite-nav-item"><a href="/sms-otp-form" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: /sms-otp-form" track-type="bookNav" track-name="click" track-metadata-eventdetail="/sms-otp-form" ><span class="devsite-nav-text" tooltip>SMS OTP form for two-step verification</span></a></li> <li class="devsite-nav-item devsite-nav-external"><a href="https://developers.google.com/codelabs/webauthn-2fa-key/" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: https://developers.google.com/codelabs/webauthn-2fa-key/" track-type="bookNav" track-name="click" track-metadata-eventdetail="https://developers.google.com/codelabs/webauthn-2fa-key/" ><span class="devsite-nav-text" tooltip>[Codelab] Enable two-factor authentication with WebAuthn</span><span class="devsite-nav-icon material-icons" data-icon="external" data-title="External" aria-hidden="true"></span></a></li> <li class="devsite-nav-item devsite-nav-heading"><div class="devsite-nav-title devsite-nav-title-no-path"> <span class="devsite-nav-text" tooltip>Build advanced authentication systems</span> </div></li> <li class="devsite-nav-item devsite-nav-external"><a href="https://developers.google.com/identity/passkeys/" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: https://developers.google.com/identity/passkeys/" track-type="bookNav" track-name="click" track-metadata-eventdetail="https://developers.google.com/identity/passkeys/" ><span class="devsite-nav-text" tooltip>Passwordless login with passkeys</span><span class="devsite-nav-icon material-icons" data-icon="external" data-title="External" aria-hidden="true"></span></a></li> <li class="devsite-nav-item"><a href="/articles/passkey-registration" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: /articles/passkey-registration" track-type="bookNav" track-name="click" track-metadata-eventdetail="/articles/passkey-registration" ><span class="devsite-nav-text" tooltip>Create a passkey for passwordless logins</span></a></li> <li class="devsite-nav-item"><a href="/articles/passkey-form-autofill" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: /articles/passkey-form-autofill" track-type="bookNav" track-name="click" track-metadata-eventdetail="/articles/passkey-form-autofill" ><span class="devsite-nav-text" tooltip>Sign in with a passkey through form autofill</span></a></li> <li class="devsite-nav-item devsite-nav-external"><a href="https://developers.google.com/identity/passkeys/developer-guides/server-introduction" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: https://developers.google.com/identity/passkeys/developer-guides/server-introduction" track-type="bookNav" track-name="click" track-metadata-eventdetail="https://developers.google.com/identity/passkeys/developer-guides/server-introduction" ><span class="devsite-nav-text" tooltip>Passkey server-side introduction</span><span class="devsite-nav-icon material-icons" data-icon="external" data-title="External" aria-hidden="true"></span></a></li> <li class="devsite-nav-item devsite-nav-external"><a href="https://developers.google.com/identity/passkeys/developer-guides/server-registration" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: https://developers.google.com/identity/passkeys/developer-guides/server-registration" track-type="bookNav" track-name="click" track-metadata-eventdetail="https://developers.google.com/identity/passkeys/developer-guides/server-registration" ><span class="devsite-nav-text" tooltip>Passkey registration server-side </span><span class="devsite-nav-icon material-icons" data-icon="external" data-title="External" aria-hidden="true"></span></a></li> <li class="devsite-nav-item devsite-nav-external"><a href="https://developers.google.com/identity/passkeys/developer-guides/server-authentication" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: https://developers.google.com/identity/passkeys/developer-guides/server-authentication" track-type="bookNav" track-name="click" track-metadata-eventdetail="https://developers.google.com/identity/passkeys/developer-guides/server-authentication" ><span class="devsite-nav-text" tooltip>Passkey authentication server-side</span><span class="devsite-nav-icon material-icons" data-icon="external" data-title="External" aria-hidden="true"></span></a></li> <li class="devsite-nav-item"><a href="/articles/webauthn-user-verification" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: /articles/webauthn-user-verification" track-type="bookNav" track-name="click" track-metadata-eventdetail="/articles/webauthn-user-verification" ><span class="devsite-nav-text" tooltip>User verification deep dive</span></a></li> <li class="devsite-nav-item"><a href="/articles/webauthn-discoverable-credentials" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: /articles/webauthn-discoverable-credentials" track-type="bookNav" track-name="click" track-metadata-eventdetail="/articles/webauthn-discoverable-credentials" ><span class="devsite-nav-text" tooltip>Discoverable credentials deep dive</span></a></li> <li class="devsite-nav-item"><a href="/articles/webauthn-exclude-credentials" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: /articles/webauthn-exclude-credentials" track-type="bookNav" track-name="click" track-metadata-eventdetail="/articles/webauthn-exclude-credentials" ><span class="devsite-nav-text" tooltip>Prevent duplicate credentials</span></a></li> <li class="devsite-nav-item"><a href="/articles/webauthn-aaguid" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: /articles/webauthn-aaguid" track-type="bookNav" track-name="click" track-metadata-eventdetail="/articles/webauthn-aaguid" ><span class="devsite-nav-text" tooltip>Determine the passkey provider</span></a></li> <li class="devsite-nav-item"><a href="/articles/webauthn-related-origin-requests" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: /articles/webauthn-related-origin-requests" track-type="bookNav" track-name="click" track-metadata-eventdetail="/articles/webauthn-related-origin-requests" ><span class="devsite-nav-text" tooltip>Associate related origins</span></a></li> <li class="devsite-nav-item devsite-nav-external"><a href="https://developer.chrome.com/docs/identity/webauthn-signal-api" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: https://developer.chrome.com/docs/identity/webauthn-signal-api" track-type="bookNav" track-name="click" track-metadata-eventdetail="https://developer.chrome.com/docs/identity/webauthn-signal-api" ><span class="devsite-nav-text" tooltip>Keep passkeys consistent with the server</span><span class="devsite-nav-icon material-icons" data-icon="external" data-title="External" aria-hidden="true"></span></a></li> <li class="devsite-nav-item devsite-nav-external"><a href="https://developers.google.com/identity/passkeys/developer-guides/upgrades" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: https://developers.google.com/identity/passkeys/developer-guides/upgrades" track-type="bookNav" track-name="click" track-metadata-eventdetail="https://developers.google.com/identity/passkeys/developer-guides/upgrades" ><span class="devsite-nav-text" tooltip>Passkey upgrades</span><span class="devsite-nav-icon material-icons" data-icon="external" data-title="External" aria-hidden="true"></span></a></li> <li class="devsite-nav-item devsite-nav-external"><a href="https://developers.google.com/codelabs/passkey-form-autofill/" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: https://developers.google.com/codelabs/passkey-form-autofill/" track-type="bookNav" track-name="click" track-metadata-eventdetail="https://developers.google.com/codelabs/passkey-form-autofill/" ><span class="devsite-nav-text" tooltip>[Codelab] Implement passkeys with form autofill</span><span class="devsite-nav-icon material-icons" data-icon="external" data-title="External" aria-hidden="true"></span></a></li> <li class="devsite-nav-item devsite-nav-external"><a href="https://developers.google.com/codelabs/webauthn-reauth/" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: https://developers.google.com/codelabs/webauthn-reauth/" track-type="bookNav" track-name="click" track-metadata-eventdetail="https://developers.google.com/codelabs/webauthn-reauth/" ><span class="devsite-nav-text" tooltip>[Codelab] Set up a re-authentication functionality with WebAuthn</span><span class="devsite-nav-icon material-icons" data-icon="external" data-title="External" aria-hidden="true"></span></a></li> <li class="devsite-nav-item devsite-nav-heading"><div class="devsite-nav-title devsite-nav-title-no-path"> <span class="devsite-nav-text" tooltip>Build authentication with identity federation</span> </div></li> <li class="devsite-nav-item devsite-nav-external"><a href="https://developers.google.com/identity/protocols/oauth2" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: https://developers.google.com/identity/protocols/oauth2" track-type="bookNav" track-name="click" track-metadata-eventdetail="https://developers.google.com/identity/protocols/oauth2" ><span class="devsite-nav-text" tooltip>Use OAuth 2.0 to access Google APIs</span><span class="devsite-nav-icon material-icons" data-icon="external" data-title="External" aria-hidden="true"></span></a></li> <li class="devsite-nav-item devsite-nav-external"><a href="https://developers.google.com/identity/protocols/oauth2/openid-connect" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: https://developers.google.com/identity/protocols/oauth2/openid-connect" track-type="bookNav" track-name="click" track-metadata-eventdetail="https://developers.google.com/identity/protocols/oauth2/openid-connect" ><span class="devsite-nav-text" tooltip>Set up OpenID Connect compliant OAuth 2.0</span><span class="devsite-nav-icon material-icons" data-icon="external" data-title="External" aria-hidden="true"></span></a></li> <li class="devsite-nav-item devsite-nav-heading"><div class="devsite-nav-title devsite-nav-title-no-path"> <span class="devsite-nav-text" tooltip>Case studies</span> </div></li> <li class="devsite-nav-item"><a href="/articles/yahoo-japan-identity-case-study" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: /articles/yahoo-japan-identity-case-study" track-type="bookNav" track-name="click" track-metadata-eventdetail="/articles/yahoo-japan-identity-case-study" ><span class="devsite-nav-text" tooltip>Yahoo! JAPAN's password-free authentication reduced inquiries by 25%, sped up sign-in time by 2.6x</span></a></li> <li class="devsite-nav-item"><a href="/goibibo#web-otp" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: /goibibo#web-otp" track-type="bookNav" track-name="click" track-metadata-eventdetail="/goibibo#web-otp" ><span class="devsite-nav-text" tooltip>Goibibo dropped OTP retry on sign-up by 25% with WebOTP</span></a></li> </ul> </div> </div> </nav> </devsite-book-nav> <section id="gc-wrapper"> <main role="main" class="devsite-main-content" has-book-nav has-sidebar > <div class="devsite-sidebar"> <div class="devsite-sidebar-content"> <devsite-toc class="devsite-nav" role="navigation" aria-label="On this page" depth="2" scrollbars ></devsite-toc> <devsite-recommendations-sidebar class="nocontent devsite-nav"> </devsite-recommendations-sidebar> </div> </div> <devsite-content> <article class="devsite-article"> <div class="devsite-article-meta nocontent" role="navigation"> <ul class="devsite-breadcrumb-list" aria-label="Breadcrumb"> <li class="devsite-breadcrumb-item "> <a href="https://web.dev/" class="devsite-breadcrumb-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Breadcrumbs" data-value="1" track-type="globalNav" track-name="breadcrumb" track-metadata-position="1" track-metadata-eventdetail="" > Home </a> </li> <li class="devsite-breadcrumb-item "> <div class="devsite-breadcrumb-guillemet material-icons" aria-hidden="true"></div> <a href="https://web.dev/articles" class="devsite-breadcrumb-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Breadcrumbs" data-value="2" track-type="globalNav" track-name="breadcrumb" track-metadata-position="2" track-metadata-eventdetail="Articles" > Articles </a> </li> <li class="devsite-breadcrumb-item "> <div class="devsite-breadcrumb-guillemet material-icons" aria-hidden="true"></div> <a href="https://web.dev/explore" class="devsite-breadcrumb-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Breadcrumbs" data-value="3" track-type="globalNav" track-name="breadcrumb" track-metadata-position="3" track-metadata-eventdetail="" > Explore </a> </li> <li class="devsite-breadcrumb-item "> <div class="devsite-breadcrumb-guillemet material-icons" aria-hidden="true"></div> <a href="https://web.dev/explore/identity" class="devsite-breadcrumb-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Breadcrumbs" data-value="4" track-type="globalNav" track-name="breadcrumb" track-metadata-position="4" track-metadata-eventdetail="" > Identity </a> </li> </ul> <devsite-thumb-rating position="header"> </devsite-thumb-rating> </div> <h1 class="devsite-page-title" tabindex="-1"> Allow passkey reuse across your sites with Related Origin Requests </h1> <devsite-feature-tooltip ack-key="AckCollectionsBookmarkTooltipDismiss" analytics-category="Site-Wide Custom Events" analytics-action-show="Callout Profile displayed" analytics-action-close="Callout Profile dismissed" analytics-label="Create Collection Callout" class="devsite-page-bookmark-tooltip nocontent" dismiss-button="true" id="devsite-collections-dropdown" dismiss-button-text="Dismiss" close-button-text="Got it"> <devsite-bookmark></devsite-bookmark> <span slot="popout-heading"> Stay organized with collections </span> <span slot="popout-contents"> Save and categorize content based on your preferences. </span> </devsite-feature-tooltip> <div class="devsite-page-title-meta"><devsite-view-release-notes></devsite-view-release-notes></div> <devsite-toc class="devsite-nav" depth="2" devsite-toc-embedded > </devsite-toc> <div class="devsite-article-body clearfix "> <p> <div class="wd-authors" translate="no"> <div class="wd-author"> <img class="devsite-landing-row-item-icon" alt="Maud Nalpas" src="https://web.dev/images/authors/maudn.jpg" decoding="async" height="64" loading="lazy" width="64"> <div> <span> Maud Nalpas </span> <div class="wd-author__links"> <a href="https://twitter.com/maudnals" aria-label="Maud Nalpas on X" rel="me"> <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 300 271"> <title>X</title> <path fill="currentColor" d="m236 0h46l-101 115 118 156h-92.6l-72.5-94.8-83 94.8h-46l107-123-113-148h94.9l65.5 86.6zm-16.1 244h25.5l-165-218h-27.4z"></path> </svg></a> <a href="https://github.com/maudnals" aria-label="Maud Nalpas on GitHub" rel="me"> <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 32.6 31.8"> <title>GitHub</title> <path d="M16.3 0C7.3 0 0 7.3 0 16.3c0 7.2 4.7 13.3 11.1 15.5.8.1 1.1-.4 1.1-.8v-2.8c-4.5 1-5.5-2.2-5.5-2.2-.7-1.9-1.8-2.4-1.8-2.4-1.5-1 .1-1 .1-1 1.6.1 2.5 1.7 2.5 1.7 1.5 2.5 3.8 1.8 4.7 1.4.1-1.1.6-1.8 1-2.2-3.6-.4-7.4-1.8-7.4-8.1 0-1.8.6-3.2 1.7-4.4-.1-.3-.7-2 .2-4.2 0 0 1.4-.4 4.5 1.7 1.3-.4 2.7-.5 4.1-.5 1.4 0 2.8.2 4.1.5 3.1-2.1 4.5-1.7 4.5-1.7.9 2.2.3 3.9.2 4.3 1 1.1 1.7 2.6 1.7 4.4 0 6.3-3.8 7.6-7.4 8 .6.5 1.1 1.5 1.1 3V31c0 .4.3.9 1.1.8 6.5-2.2 11.1-8.3 11.1-15.5C32.6 7.3 25.3 0 16.3 0z" fill-rule="evenodd" clip-rule="evenodd" fill="currentColor" /> </svg></a> </div> </div> </div> </div></p> <h2 id="the_problem_related_origin_requests_solve" data-text="The problem Related Origin Requests solve" tabindex="-1">The problem Related Origin Requests solve</h2> <p><a href="https://developer.chrome.com/docs/identity/passkeys">Passkeys</a> are tied to a specific website and can only be used for signing in on the website they were created for.</p> <p>This is specified in the <a href="https://www.w3.org/TR/webauthn-2/#rp-id">relying party ID</a> (RP ID), which for passkeys created for the example.com domain could be <code translate="no" dir="ltr">www.example.com</code> or <code translate="no" dir="ltr">example.com</code>.</p> <p>While RP IDs prevent passkeys from being used as a single credential for authenticating everywhere, they create issues for:</p> <ul> <li><strong>Sites with multiple domains</strong>: Users can't use the same passkey to sign in across different country-specific domains (for example <code translate="no" dir="ltr">example.com</code>, and <code translate="no" dir="ltr">example.co.uk</code>) managed by the same company.</li> <li><strong>Branded domains</strong>: Users can't use the same credential across different domains used by a single brand (for example <code translate="no" dir="ltr">acme.com</code> and <code translate="no" dir="ltr">acmerewards.com</code>).</li> <li><strong>Mobile apps</strong>: Mobile apps often don't have their own domain, making credential management challenging.</li> </ul> <p>There are workarounds based on identity federation, and others based on iframes, but they are inconvenient in some cases. Related Origin Requests offer a solution.</p> <aside class="note"><strong>Note:</strong><span> RP IDs do separate credentials between different websites—but phishing protection actually comes from verifying the website's origin in the <a href="https://www.w3.org/TR/webauthn-3/#dictionary-client-data"><code translate="no" dir="ltr">CollectedClientData</code></a> field.</span></aside> <h3 id="solution" data-text="Solution" tabindex="-1">Solution</h3> <p>With <a href="https://w3c.github.io/webauthn/#sctn-related-origins">Related Origin Requests</a>, a website can specify origins allowed to use its RP ID.</p> <p>This unlocks the possibility for users to reuse the same passkey across multiple sites you operate.</p> <p>To use Related Origin Requests, you need to serve a special JSON file at a specific URL <code translate="no" dir="ltr">https://{RP ID}/.well-known/webauthn</code>. If <code translate="no" dir="ltr">example.com</code> wants to allow the additional origins to use it as an RP ID, it should serve the following file at <code translate="no" dir="ltr">https://example.com/.well-known/webauthn:</code></p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="JSON"><code translate="no" dir="ltr"><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-nt">"origins"</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-s2">"https://example.co.uk"</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-s2">"https://example.de"</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-s2">"https://example-rewards.com"</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">]</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> <p>Next time any of these sites makes a call for passkey creation (<code translate="no" dir="ltr">navigator.credentials.create</code>) or authentication (<code translate="no" dir="ltr">navigator.credentials.get</code>) that uses <code translate="no" dir="ltr">example.com</code> as an RP ID, the browser will notice an RP ID that mismatches the requesting origin. If the browser supports Related Origin Requests, it first looks for a <code translate="no" dir="ltr">webauthn</code> file at <code translate="no" dir="ltr">https://{RP ID}/.well-known/webauthn</code>. If the file exists, the browser checks whether the origin making the request is allowlisted in that file. If so, it proceeds to passkey creation or authentication steps. If the browser doesn't support Related Origin Requests, it throws a <code translate="no" dir="ltr">SecurityError</code>.</p> <h2 id="browser_support" data-text="Browser support" tabindex="-1">Browser support</h2> <ul> <li>Chrome: Supported starting from <a href="https://chromiumdash.appspot.com/schedule">Chrome 128</a>.</li> <li>Safari: Supported starting from macOS 15 beta 3, and on mobile iOS 18 beta 3.</li> <li>Firefox: <a href="https://github.com/mozilla/standards-positions/issues/1052">Awaiting position</a>.</li> </ul> <aside class="warning"><strong>Warning:</strong><span> As of August 2024, Related Origin Requests aren't supported in Firefox, and <a href="https://w3c.github.io/webauthn/#sctn-getClientCapabilities"><code translate="no" dir="ltr">getClientCapabilities</code></a> isn't available yet for you to detect the missing feature and implement a fallback. If you implement Related Origin Requests, Firefox users won't be able to create a passkey (or sign in with it) on the domains intending to use another site as an RP ID and a <code translate="no" dir="ltr">SecurityError</code> will be thrown.</span></aside> <h2 id="how_to_set_up_related_origin_requests" data-text="How to set up Related Origin Requests" tabindex="-1">How to set up Related Origin Requests</h2> <p>The following demo uses the example of two sites, <code translate="no" dir="ltr">https://ror-1.glitch.me</code> and <code translate="no" dir="ltr">https://ror-2.glitch.me</code>.<br> To enable users to sign in with the same passkey across both of those sites, it uses Related Origin Requests to allow <code translate="no" dir="ltr">ror-2.glitch.me</code> to use <code translate="no" dir="ltr">ror-1.glitch.me</code> as its RP ID. </p> <h3 id="demo" data-text="Demo" tabindex="-1">Demo</h3> <aside class="note"><strong>Note:</strong><span> Open the demo in one of the <a href="/articles/passkey-related-origin-requests#browser_support">supported browsers</a>.</span></aside> <p><a href="https://ror-2.glitch.me/">https://ror-2.glitch.me</a> implements Related Origin Requests to use ror-1.glitch.me as an RP ID, so both <code translate="no" dir="ltr">ror-1</code> and <code translate="no" dir="ltr">ror-2</code> use <code translate="no" dir="ltr">ror-1.glitch.me</code> as an RP ID upon creating a passkey or authenticating with it.<br> We've also implemented a shared passkey database across these sites.</p> <p>Observe the following user experience:</p> <ul> <li>You can successfully create a passkey, and authenticate with it, on <code translate="no" dir="ltr">ror-2</code>—even though its RP ID is <code translate="no" dir="ltr">ror-1</code> (and not <code translate="no" dir="ltr">ror-2</code>). </li> <li>Once you create a passkey on either <code translate="no" dir="ltr">ror-1</code> or <code translate="no" dir="ltr">ror-2</code>, you can authenticate with it on both <code translate="no" dir="ltr">ror-1</code> and <code translate="no" dir="ltr">ror-2</code>. Because <code translate="no" dir="ltr">ror-2</code> specifies <code translate="no" dir="ltr">ror-1</code> as an RP ID, making a passkey creation or authentication request from any of these sites is the same as making the request on ror-1. The RP ID is the only thing that ties a request to an origin. </li> <li>Once you create a passkey on either <code translate="no" dir="ltr">ror-1</code> or <code translate="no" dir="ltr">ror-2</code>, it can be autofilled by Chrome on both <code translate="no" dir="ltr">ror-1</code> and <code translate="no" dir="ltr">ror-2</code>. </li> <li>A credential created on any of these sites will have an RP ID of <code translate="no" dir="ltr">ror-1</code>.</li> </ul> <figure> <img src="/static/articles/webauthn-related-origin-requests/image/chrome-autofill.jpg" alt="Chrome autofills on both sites." srcset="https://web.dev/static/articles/webauthn-related-origin-requests/image/chrome-autofill_36.jpg 36w,https://web.dev/static/articles/webauthn-related-origin-requests/image/chrome-autofill_48.jpg 48w,https://web.dev/static/articles/webauthn-related-origin-requests/image/chrome-autofill_72.jpg 72w,https://web.dev/static/articles/webauthn-related-origin-requests/image/chrome-autofill_96.jpg 96w,https://web.dev/static/articles/webauthn-related-origin-requests/image/chrome-autofill_480.jpg 480w,https://web.dev/static/articles/webauthn-related-origin-requests/image/chrome-autofill_720.jpg 720w,https://web.dev/static/articles/webauthn-related-origin-requests/image/chrome-autofill_856.jpg 856w,https://web.dev/static/articles/webauthn-related-origin-requests/image/chrome-autofill_960.jpg 960w,https://web.dev/static/articles/webauthn-related-origin-requests/image/chrome-autofill_1440.jpg 1440w,https://web.dev/static/articles/webauthn-related-origin-requests/image/chrome-autofill_1920.jpg 1920w,https://web.dev/static/articles/webauthn-related-origin-requests/image/chrome-autofill_2880.jpg 2880w" sizes="(max-width: 840px) 100vw, 856px"> <figcaption> Thanks to Related Origin Requests, users can use the same passkey credential across ror-1 and ror-2. Chrome will also autofill the credentials. </figcaption> </figure> <p>See code:</p> <ul> <li>See the <code translate="no" dir="ltr">./well-known/webauthn</code> file set up in the <a href="https://glitch.com/edit/#!/ror-1?path=server.mjs%3A142%3A11">ror-1 codebase</a>.</li> <li>See <code translate="no" dir="ltr">RP_ID_ROR</code> occurrences in the <a href="https://glitch.com/edit/#!/ror-2?path=libs%2Fauth.mjs%3A216%3A35">ror-2 codebase</a>.</li> </ul> <aside class="note"><strong>Note:</strong><span> In this demo, for simplicity, no password check actually happens under the hood. The demo focuses on passkeys.</span></aside> <h3 id="step_1_implement_a_shared_account_database" data-text="Step 1: Implement a shared account database" tabindex="-1">Step 1: Implement a shared account database</h3> <p>If you want your users to be able to sign in with the same passkey across <code translate="no" dir="ltr">site-1</code> and <code translate="no" dir="ltr">site-2</code>, implement an account database that is shared across these two sites.</p> <h3 id="step_2_set_up_your_well-knownwebauthn_json_file_in_site-1" data-text="Step 2: Set up your .well-known/webauthn JSON file in site-1" tabindex="-1">Step 2: Set up your .well-known/webauthn JSON file in site-1</h3> <p>First, configure <code translate="no" dir="ltr">site-1.com</code> such that it allows <code translate="no" dir="ltr">site-2.com</code> to use it as an RP ID. To do so, create your webauthn JSON file:</p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="JSON"><code translate="no" dir="ltr"><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-nt">"origins"</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-s2">"https://site-2.com"</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">]</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> <p>The JSON object must contain key named origins whose value is an array of one or more strings containing web origins.</p> <h4 id="important_limitation_maximum_5_labels" data-text="Important limitation: Maximum 5 labels" tabindex="-1">Important limitation: Maximum 5 labels</h4> <p>Each element of this list will be processed to extract the eTLD + 1 <em>label</em>. For example, the eTLD + 1 labels of <code translate="no" dir="ltr">example.co.uk</code> and <code translate="no" dir="ltr">example.de</code> are both <code translate="no" dir="ltr">example</code>. But the eTLD + 1 label of <code translate="no" dir="ltr">example-rewards.com</code> is <code translate="no" dir="ltr">example-rewards</code>. In Chrome, the maximum number of labels is 5.</p> <aside class="warning"><strong>Warning:</strong><span> If your list includes too many labels (more than 5), the excessive element(s) will be ignored.</span></aside> <h3 id="step_3_serve_your_well-knownwebauthn_json_in_site-1" data-text="Step 3: Serve your .well-known/webauthn JSON in site-1" tabindex="-1">Step 3: Serve your .well-known/webauthn JSON in site-1</h3> <p>Then, serve your JSON file under <code translate="no" dir="ltr">site-1.com/.well-known/webauthn</code>.</p> <aside class="caution"><strong>Caution:</strong><span> The file must be served with a content-type of <code translate="no" dir="ltr">application/json</code> and contain a single <a href="https://datatracker.ietf.org/doc/html/rfc8259">JSON</a> object listing allowed origins. The correct format for the file is: <code translate="no" dir="ltr">/.well-known/webauthn</code> (do not include the <code translate="no" dir="ltr">.json</code> extension).</span></aside> <p>For example, in express:</p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="JavaScript"><code translate="no" dir="ltr"><span class="devsite-syntax-nx">app</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">get</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s2">"/.well-known/webauthn"</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">req</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">res</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-kd">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">origins</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">origins</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span><span class="devsite-syntax-s2">"https://site-2.com"</span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">};</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">res</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">json</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">origins</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-p">});</span> </code></pre></devsite-code> <p>Here, we're using express <a href="https://expressjs.com/en/api.html#res.json"><code translate="no" dir="ltr">res.json</code></a>, which already sets the correct <code translate="no" dir="ltr">content-type</code> (<code translate="no" dir="ltr">'application/json'</code>);</p> <h3 id="step_4_specify_the_desired_rp_id_in_site-2" data-text="Step 4: Specify the desired RP ID in site-2" tabindex="-1">Step 4: Specify the desired RP ID in site-2</h3> <p>In your <code translate="no" dir="ltr">site-2</code> codebase, set <code translate="no" dir="ltr">site-1.com</code>as the RP ID everywhere needed:</p> <ul> <li>Upon credential creation: <ul> <li>Set <code translate="no" dir="ltr">site-1.com</code> as the RP ID in the credential creation <code translate="no" dir="ltr">options</code> that are passed to the <code translate="no" dir="ltr">navigator.credentials.create</code> frontend call, and typically generated server-side.</li> <li>Set <code translate="no" dir="ltr">site-1.com</code>as the expected RP ID, as you run credential verifications before saving it to your database.</li> </ul></li> <li>Upon authentication: <ul> <li>Set <code translate="no" dir="ltr">site-1.com</code> as the RP ID in the authentication <code translate="no" dir="ltr">options</code> that are passed to the <code translate="no" dir="ltr">navigator.credentials.get</code> frontend call, and typically generated server-side.</li> <li>Set <code translate="no" dir="ltr">site-1.com</code>as the expected RP ID to be verified on the server, as you run credential verifications before authenticating the user.</li> </ul></li> </ul> <aside class="note"><strong>Note:</strong><span> What about the <code translate="no" dir="ltr">origin</code>? And the RP <code translate="no" dir="ltr">name</code>? In your site-2 codebase, the expected <code translate="no" dir="ltr">origin</code> should remain unchanged (<code translate="no" dir="ltr">https://site-2.com</code>), because it designates where the request is expected to come from. As per the RP name (<code translate="no" dir="ltr">rp.name</code>), it's unused in practice. You can leave it empty.</span></aside> <h3 id="troubleshooting" data-text="Troubleshooting" tabindex="-1">Troubleshooting</h3> <figure> <img src="/static/articles/webauthn-related-origin-requests/image/error-file-not-found.jpg" alt="Error message popup in Chrome." srcset="https://web.dev/static/articles/webauthn-related-origin-requests/image/error-file-not-found_36.jpg 36w,https://web.dev/static/articles/webauthn-related-origin-requests/image/error-file-not-found_48.jpg 48w,https://web.dev/static/articles/webauthn-related-origin-requests/image/error-file-not-found_72.jpg 72w,https://web.dev/static/articles/webauthn-related-origin-requests/image/error-file-not-found_96.jpg 96w,https://web.dev/static/articles/webauthn-related-origin-requests/image/error-file-not-found_480.jpg 480w,https://web.dev/static/articles/webauthn-related-origin-requests/image/error-file-not-found_720.jpg 720w,https://web.dev/static/articles/webauthn-related-origin-requests/image/error-file-not-found_856.jpg 856w,https://web.dev/static/articles/webauthn-related-origin-requests/image/error-file-not-found_960.jpg 960w,https://web.dev/static/articles/webauthn-related-origin-requests/image/error-file-not-found_1440.jpg 1440w,https://web.dev/static/articles/webauthn-related-origin-requests/image/error-file-not-found_1920.jpg 1920w,https://web.dev/static/articles/webauthn-related-origin-requests/image/error-file-not-found_2880.jpg 2880w" sizes="(max-width: 840px) 100vw, 856px"> <figcaption> Error message in Chrome upon credential creation. This error is thrown if your `.well-known/webauthn` file can't be found at `https://{RP ID}/.well-known/webauthn`. </figcaption> </figure> <figure> <img src="/static/articles/webauthn-related-origin-requests/image/error-file-incorrect.jpg" alt="Error message popup in Chrome." srcset="https://web.dev/static/articles/webauthn-related-origin-requests/image/error-file-incorrect_36.jpg 36w,https://web.dev/static/articles/webauthn-related-origin-requests/image/error-file-incorrect_48.jpg 48w,https://web.dev/static/articles/webauthn-related-origin-requests/image/error-file-incorrect_72.jpg 72w,https://web.dev/static/articles/webauthn-related-origin-requests/image/error-file-incorrect_96.jpg 96w,https://web.dev/static/articles/webauthn-related-origin-requests/image/error-file-incorrect_480.jpg 480w,https://web.dev/static/articles/webauthn-related-origin-requests/image/error-file-incorrect_720.jpg 720w,https://web.dev/static/articles/webauthn-related-origin-requests/image/error-file-incorrect_856.jpg 856w,https://web.dev/static/articles/webauthn-related-origin-requests/image/error-file-incorrect_960.jpg 960w,https://web.dev/static/articles/webauthn-related-origin-requests/image/error-file-incorrect_1440.jpg 1440w,https://web.dev/static/articles/webauthn-related-origin-requests/image/error-file-incorrect_1920.jpg 1920w,https://web.dev/static/articles/webauthn-related-origin-requests/image/error-file-incorrect_2880.jpg 2880w" sizes="(max-width: 840px) 100vw, 856px"> <figcaption> Error message in Chrome upon credential creation. This error is thrown if your `.well-known/webauthn` file can be found, but doesn't list the origin you're trying to create a credential from. </figcaption> </figure> <h2 id="other_considerations" data-text="Other considerations" tabindex="-1">Other considerations</h2> <h3 id="share_passkeys_across_sites_and_mobile_apps" data-text="Share passkeys across sites and mobile apps" tabindex="-1">Share passkeys across sites and mobile apps</h3> <p>Related Origin Requests allow your users to reuse a passkey across <em>multiple sites</em>. To allow your users to reuse a passkey across a <em>website</em> and a <em>mobile app</em>, use the following techniques:</p> <ul> <li>In Chrome: <a href="https://developers.google.com/digital-asset-links">Digital Asset Links</a>. Learn more at <a href="https://developer.android.com/identity/sign-in/credential-manager#add-support-dal">Add support for Digital Asset Links</a>.</li> <li>In Safari: <a href="https://developer.apple.com/documentation/xcode/supporting-associated-domains">Associated domains</a>.</li> </ul> <h3 id="share_passwords_across_sites" data-text="Share passwords across sites" tabindex="-1">Share passwords across sites</h3> <p>Related Origin Requests allow your users to reuse a <em>passkey</em> across sites. Solutions for sharing <em>passwords</em> across sites vary between password managers. For Google Password Manager, use <a href="https://developer.chrome.com/docs/identity/site-affiliation">Digital Asset Links </a>. Safari has <a href="https://github.com/apple/password-manager-resources#shared-credentials">a different system</a>.</p> <h3 id="role_of_credential_managers_and_user_agents" data-text="Role of credential managers and user agents" tabindex="-1">Role of credential managers and user agents</h3> <p>This goes beyond your scope as a site developer, but note that in the longer term, the RP ID shouldn't be a user-visible concept in the user agent or the credential manager your users are using. Instead, user agents and credential managers should show users <em>where</em> their credentials have been used. This change will take time to implement. A temporary solution would be to display both the current website and the original registration site.</p> </div> <devsite-thumb-rating position="footer"> </devsite-thumb-rating> <div class="devsite-floating-action-buttons"> </div> </article> <devsite-content-footer class="nocontent"> <p>Except as otherwise noted, the content of this page is licensed under the <a href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 License</a>, and code samples are licensed under the <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache 2.0 License</a>. For details, see the <a href="https://developers.google.com/site-policies">Google Developers Site Policies</a>. Java is a registered trademark of Oracle and/or its affiliates.</p> <p>Last updated 2024-08-22 UTC.</p> </devsite-content-footer> <devsite-notification > </devsite-notification> <div class="devsite-content-data"> <template class="devsite-content-data-template"> [[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2024-08-22 UTC."],[],[]] </template> </div> </devsite-content> </main> <devsite-footer-promos class="devsite-footer"> </devsite-footer-promos> <devsite-footer-linkboxes class="devsite-footer"> <nav class="devsite-footer-linkboxes nocontent" aria-label="Footer links"> <ul class="devsite-footer-linkboxes-list"> <li class="devsite-footer-linkbox wd-footer-promo"> <h3 class="devsite-footer-linkbox-heading no-link">web.dev</h3> <ul class="devsite-footer-linkbox-list"> <li class="devsite-footer-linkbox-item"> <h3 class="devsite-footer-linkbox-heading no-link"> web.dev </h3> <div class="devsite-footer-linkbox-description">We want to help you build beautiful, accessible, fast, and secure websites that work cross-browser, and for all of your users. This site is our home for content to help you on that journey, written by members of the Chrome team, and external experts.</div> </li> </ul> </li> <li class="devsite-footer-linkbox "> <h3 class="devsite-footer-linkbox-heading no-link">Contribute</h3> <ul class="devsite-footer-linkbox-list"> <li class="devsite-footer-linkbox-item"> <a href="https://issuetracker.google.com/issues/new?component=1400680&template=1857359" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 1)" > File a bug </a> </li> <li class="devsite-footer-linkbox-item"> <a href="https://issuetracker.google.com/issues?q=status:open%20componentid:1400680&s=created_time:desc" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 2)" > See open issues </a> </li> </ul> </li> <li class="devsite-footer-linkbox "> <h3 class="devsite-footer-linkbox-heading no-link">Related Content</h3> <ul class="devsite-footer-linkbox-list"> <li class="devsite-footer-linkbox-item"> <a href="https://developer.chrome.com/" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 1)" > Chrome for Developers </a> </li> <li class="devsite-footer-linkbox-item"> <a href="https://blog.chromium.org/" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 2)" > Chromium updates </a> </li> <li class="devsite-footer-linkbox-item"> <a href="/case-studies" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 3)" > Case studies </a> </li> <li class="devsite-footer-linkbox-item"> <a href="/shows" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 4)" > Podcasts & shows </a> </li> </ul> </li> <li class="devsite-footer-linkbox "> <h3 class="devsite-footer-linkbox-heading no-link">Follow</h3> <ul class="devsite-footer-linkbox-list"> <li class="devsite-footer-linkbox-item"> <a href="https://twitter.com/ChromiumDev" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 1)" > @ChromiumDev on X </a> </li> <li class="devsite-footer-linkbox-item"> <a href="https://www.youtube.com/user/ChromeDevelopers" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 2)" > YouTube </a> </li> <li class="devsite-footer-linkbox-item"> <a href="https://www.linkedin.com/showcase/chrome-for-developers" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 3)" > Chrome for Developers on LinkedIn </a> </li> <li class="devsite-footer-linkbox-item"> <a href="/static/blog/feed.xml" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 4)" > RSS </a> </li> </ul> </li> </ul> </nav> </devsite-footer-linkboxes> <devsite-footer-utility class="devsite-footer"> <div class="devsite-footer-utility nocontent"> <nav class="devsite-footer-utility-links" aria-label="Utility links"> <ul class="devsite-footer-utility-list"> <li class="devsite-footer-utility-item "> <a class="devsite-footer-utility-link gc-analytics-event" href="//policies.google.com/terms" data-category="Site-Wide Custom Events" data-label="Footer Terms link" > Terms </a> </li> <li class="devsite-footer-utility-item "> <a class="devsite-footer-utility-link gc-analytics-event" href="//policies.google.com/privacy" data-category="Site-Wide Custom Events" data-label="Footer Privacy link" > Privacy </a> </li> <li class="devsite-footer-utility-item glue-cookie-notification-bar-control"> <a class="devsite-footer-utility-link gc-analytics-event" href="#" data-category="Site-Wide Custom Events" data-label="Footer Manage cookies link" aria-hidden="true" > Manage cookies </a> </li> </ul> <devsite-language-selector> <ul role="presentation"> <li role="presentation"> <a role="menuitem" lang="en" >English</a> </li> <li role="presentation"> <a role="menuitem" lang="de" >Deutsch</a> </li> <li role="presentation"> <a role="menuitem" lang="es_419" >Español – América Latina</a> </li> <li role="presentation"> <a role="menuitem" lang="fr" >Français</a> </li> <li role="presentation"> <a role="menuitem" lang="id" >Indonesia</a> </li> <li role="presentation"> <a role="menuitem" lang="it" >Italiano</a> </li> <li role="presentation"> <a role="menuitem" lang="pl" >Polski</a> </li> <li role="presentation"> <a role="menuitem" lang="pt_br" >Português – Brasil</a> </li> <li role="presentation"> <a role="menuitem" lang="vi" >Tiếng Việt</a> </li> <li role="presentation"> <a role="menuitem" lang="tr" >Türkçe</a> </li> <li role="presentation"> <a role="menuitem" lang="ru" >Русский</a> </li> <li role="presentation"> <a role="menuitem" lang="he" >עברית</a> </li> <li role="presentation"> <a role="menuitem" lang="ar" >العربيّة</a> </li> <li role="presentation"> <a role="menuitem" lang="fa" >فارسی</a> </li> <li role="presentation"> <a role="menuitem" lang="hi" >हिंदी</a> </li> <li role="presentation"> <a role="menuitem" lang="bn" >বাংলা</a> </li> <li role="presentation"> <a role="menuitem" lang="th" >ภาษาไทย</a> </li> <li role="presentation"> <a role="menuitem" lang="zh_cn" >中文 – 简体</a> </li> <li role="presentation"> <a role="menuitem" lang="zh_tw" >中文 – 繁體</a> </li> <li role="presentation"> <a role="menuitem" lang="ja" >日本語</a> </li> <li role="presentation"> <a role="menuitem" lang="ko" >한국어</a> </li> </ul> </devsite-language-selector> </nav> </div> </devsite-footer-utility> <devsite-panel></devsite-panel> </section></section> <devsite-sitemask></devsite-sitemask> <devsite-snackbar></devsite-snackbar> <devsite-tooltip ></devsite-tooltip> <devsite-heading-link></devsite-heading-link> <devsite-analytics> <script type="application/json" analytics>[]</script> <script type="application/json" tag-management>{"at": "True", "ga4": [], "ga4p": [], "gtm": [{"id": "GTM-MZWCJPP", "purpose": 0}], "parameters": {"internalUser": "False", "language": {"machineTranslated": "False", "requested": "en", "served": "en"}, "pageType": "article", "projectName": "Articles", "signedIn": "False", "tenant": "web", "recommendations": {"sourcePage": "", "sourceType": 0, "sourceRank": 0, "sourceIdenticalDescriptions": 0, "sourceTitleWords": 0, "sourceDescriptionWords": 0, "experiment": ""}, "experiment": {"ids": ""}}}</script> </devsite-analytics> <devsite-badger></devsite-badger> <script nonce="ocQpITuX3qa2V5nSunYYdnYjR1cp5+"> (function(d,e,v,s,i,t,E){d['GoogleDevelopersObject']=i; t=e.createElement(v);t.async=1;t.src=s;E=e.getElementsByTagName(v)[0]; E.parentNode.insertBefore(t,E);})(window, document, 'script', 'https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/web/js/app_loader.js', '[27,"en",null,"/js/devsite_app_module.js","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/web","https://web-dot-devsite-v2-prod-3p.appspot.com",1,null,["/_pwa/web/manifest.json","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/images/video-placeholder.svg","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/web/images/favicon.png","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/web/images/lockup.svg","https://fonts.googleapis.com/css?family=Google+Sans:400,500|Roboto:400,400italic,500,500italic,700,700italic|Roboto+Mono:400,500,700&display=swap"],1,null,[1,6,8,12,14,17,21,25,50,52,63,70,75,76,80,87,91,92,93,97,98,100,101,102,103,104,105,107,108,109,110,112,113,116,117,118,120,122,124,125,126,127,129,130,131,132,133,134,135,136,138,140,141,147,148,149,151,152,156,157,158,159,161,163,164,168,169,170,179,180,182,183,186,191,193,196],"AIzaSyCNm9YxQumEXwGJgTDjxoxXK6m1F-9720Q","AIzaSyCc76DZePGtoyUjqKrLdsMGk_ry7sljLbY","web.dev","AIzaSyB9bqgQ2t11WJsOX8qNsCQ6U-w91mmqF-I","AIzaSyAdYnStPdzjcJJtQ0mvIaeaMKj7_t6J_Fg",null,null,null,["Analytics__enable_clearcut_logging","DevPro__enable_cloud_innovators_plus","Cloud__enable_cloud_dlp_service","Cloud__enable_cloud_shell","Profiles__enable_page_saving","TpcFeatures__enable_mirror_tenant_redirects","Profiles__enable_release_notes_notifications","MiscFeatureFlags__enable_explain_this_code","Profiles__enable_dashboard_curated_recommendations","Profiles__enable_awarding_url","MiscFeatureFlags__enable_variable_operator","Profiles__enable_developer_profiles_callout","Profiles__require_profile_eligibility_for_signin","Cloud__enable_cloudx_experiment_ids","Experiments__reqs_query_experiments","MiscFeatureFlags__developers_footer_dark_image","MiscFeatureFlags__enable_firebase_utm","Cloud__enable_cloudx_ping","Profiles__enable_completecodelab_endpoint","Cloud__enable_legacy_calculator_redirect","TpcFeatures__enable_required_headers","Profiles__enable_recognition_badges","Profiles__enable_profile_collections","Search__enable_ai_eligibility_checks","Cloud__enable_cloud_facet_chat","Search__enable_suggestions_from_borg","OnSwitch__enable","EngEduTelemetry__enable_engedu_telemetry","Search__enable_page_map","Cloud__enable_llm_concierge_chat","CloudShell__cloud_code_overflow_menu","BookNav__enable_tenant_cache_key","MiscFeatureFlags__enable_view_transitions","CloudShell__cloud_shell_button","DevPro__enable_developer_subscriptions","MiscFeatureFlags__enable_project_variables","Search__enable_dynamic_content_confidential_banner","Cloud__enable_cloud_shell_fte_user_flow","Cloud__enable_free_trial_server_call","Concierge__enable_pushui","Profiles__enable_public_developer_profiles","MiscFeatureFlags__emergency_css","MiscFeatureFlags__developers_footer_image","Profiles__enable_complete_playlist_endpoint"],null,null,"AIzaSyA58TaKli1DculwmAmbpzLVGuWc8eCQgQc","https://developerscontentserving-pa.googleapis.com","AIzaSyDWBU60w0P9hEkr29kkksYs8Z7gvZ8u_wc","https://developerscontentsearch-pa.googleapis.com",2,4,null,"https://developerprofiles-pa.googleapis.com",[27,"web","web.dev","web.dev",null,"web-dot-devsite-v2-prod-3p.appspot.com",null,null,[null,null,null,null,null,null,null,null,null,null,null,[1],null,null,null,null,null,null,[1],null,null,null,null,[1,null,1],[1,1,null,1,1]],null,[38,null,null,null,null,null,"/images/lockup.svg","/images/touchicon-180.png",null,null,null,1,1,null,null,null,null,null,null,null,null,2,null,null,null,"/images/lockup-dark-theme.svg",[]],[],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[[],[1,1]],[[null,null,null,null,null,["GTM-MZWCJPP"],null,null,null,null,null,[["GTM-MZWCJPP",1]],1]],null,4]]') </script> <devsite-a11y-announce></devsite-a11y-announce> </body> </html>