<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="369831" data-post-id="369831">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="jswanner" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jswanner/120/24585_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  jswanner
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>It’s part of the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API" rel="noopener nofollow ugc">“Web authentication API” (webauthn)</a> and uses the <a href="https://developer.mozilla.org/en-US/docs/Web/API/PublicKeyCredential" rel="noopener nofollow ugc">PublicKeyCredential</a> interface available in the browser. Those APIs can be used for various things and support a number of options, none of which are called “passkeys,” making it confusing if you are just getting started in trying to implement passkeys, <code>residentKey</code> is what you’ll actually see in code and the documentation will also refer to them as “discoverable keys.” How tou use those browser APIs also depends on how you want your authentication process to flow: do you want the device to potentially trigger the passkey UI before you know who they are (this is what is meant by discoverable), or do you want the user to first provide a username/email and then trigger the passkey UI once you know your system has their public key.</p>
<p>The gist is that passkeys are private/public key pairs generated on the user’s device (or in something like 1password) via the JavaScript API, the private key is used to sign a challenge (random bytes previously generated on the server) on the device and the public key is used to verify the signature on the server.</p>
<p>There are two flows: creating a passkey and authenticating with a passkey. In both flows the server first generates and stores the challenge, sends the challenge to the client, which is included in the webauthn API call. The result of the creation API includes public key which needs to be stored by the server for future authentication flows. The result of the authentication API includes a signature of the challenge which the server needs to verify using the previously stored public key.</p>
<p>I recently spiked adding passkeys to what’s generated by <code>phx.gen.auth</code> in Phoenix 1.8 RC: <a href="https://github.com/jswanner/phx-passkey-spike/commit/dd88cf94bb70e15795a6e9dcb1f067bb8de0fb09" class="inline-onebox" rel="noopener nofollow ugc">First pass as passkeys · jswanner/phx-passkey-spike@dd88cf9 · GitHub</a></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="369831" data-batch-url="/posts/batch_likers">
                        7
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/feature-request-for-passwordless-implementation-in-mix-gen-auth-make-it-a-magic-code-and-not-a-link/71772/12">Post #11</a>
	                </div>
	            </div>
              <div id="likers-container-369831" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="369831"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-last-post cat-last-post" title="Last post!"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <span class="all-loaded">— All posts loaded —</span>
</div></template></turbo-stream>