spring logo
java logo

Passkeys with Spring Boot on Windows Powershell

Updated on January 29, 2024
Photo of Deepu K Sasidharan
Deepu K SasidharanDeveloper Advocate
Options
Work with macOS/Linux Terminal
Work with Windows Powershell
Work with a User Interface

Introduction

Learning GoalLearn how to build a Spring Boot app that uses OpenID Connect and passkeys for authentication.

You will be using Windows PowerShell (version 5+) for most of the steps.

Why use OpenID Connect and passkeys

OpenID Connect (OIDC) is an identity layer built on top of the OAuth 2.0 framework. It allows third-party applications to verify the identity of the end-user and to obtain basic user profile information.

Passkeys are FIDO credentials that are discoverable by browsers or housed in hardware authenticators like your mobile device, laptop, or security keys for passwordless authentication. Passkeys replace passwords with cryptographic key pairs for phishing-resistant sign-in security and an improved user experience. The cryptographic keys are used from end-user devices (computers, phones, or security keys) for user authentication. Any passwordless FIDO credential is a passkey.

We believe that passkeys offer a viable alternative to passwords for consumer applications, and we are committed to promoting this much-needed industry shift by making it easy for you, developers, and builders to offer that experience to your users.

In this lab, you'll learn how to use Java and Spring Boot to build a simple app that's secured with OIDC and Auth0. You'll also learn how to enable passkeys for authentication.

Lab Setup

Set up a development environment

  • Use your favorite text editor or IDE. We recommend using IntelliJ IDEA.
  • Ensure that you have Java 17+ installed in your system. You can easily install it using SDKMAN!.
  • Windows commands in this lab are written for PowerShell.

Create an Auth0 account

If you already have an Auth0 account, you can continue to the next step.

Otherwise, sign up for a free Auth0 account.

During the sign-up process, you create something called an Auth0 Tenant, where you configure your use of Auth0.

Once you sign in, Auth0 takes you to the Auth0 Dashboard, where you can configure and manage Auth0 assets, such as applications, APIs, connections, and user profiles.

Enable passkeys on your Auth0 tenant

  1. Log in to your Auth0 Dashboard and navigate to Authentication > Database > Username-Password-Authentication.
    1. If the second tab says Authentication Methods, your tenant supports passkeys, proceed to the next step.
    2. If the second tab says Password Policy, your tenant doesn't support passkeys, Create a new tenant and proceed to the next step.
  2. Navigate to Authentication > Authentication Profile and select Identifier First. Save your changes.
  3. Navigate to Authentication > Database > Username-Password-Authentication and select the Authentication Methods tab and enable Passkey.

Set up the Auth0 CLI

Auth0 CLI helps to build, manage, and test your Auth0 integrations from the command line.

Install it using Scoop with the following command:

COMMAND
scoop bucket add auth0 https://github.com/auth0/scoop-auth0-cli
scoop install auth0

If you don't have Scoop, you can install it manually using Invoke-WebRequest:

COMMAND
# Download the binary to the current folder
$version = "1.3.0"
Invoke-WebRequest 'https://github.com/auth0/auth0-cli/releases/download/v${version}/auth0-cli_${version}_Windows_x86_64.zip' -OutFile .\auth0.zip
Expand-Archive .\auth0.zip .\
# To be able to run the binary from any directory, make sure you add it to your $PATH
[System.Environment]::SetEnvironmentVariable('PATH',$Env:PATH + ";${pwd}")

Create a Spring Boot app

Create a Spring Boot application using start.spring.io, run the following command:

GRADLE
MAVEN
Invoke-WebRequest -Uri "https://start.spring.io/starter.tgz?dependencies=web,okta" -OutFile .\passkey-demo.tar.gz
tar -xzvf ./passkey-demo.tar.gz

The application has Spring MVC and Okta Spring Boot starter as dependencies. The Okta Spring Boot starter is a thin wrapper around Spring Security's resource server, OIDC login, and OAuth client support. It secures all endpoints by default.

Unzip and navigate to the application folder:

COMMAND
cd passkey-demo

Secure Spring Boot with OIDC and Auth0

In a terminal, connect the Auth0 CLI to your Auth0 tenant.

COMMAND
auth0 login

Then, run the command below to create an OIDC application:

COMMAND
auth0 apps create `
--name "Spring Boot Passkeys Windows" `
--description "Spring Boot passkeys Demo" `
--type regular `
--callbacks http://localhost:8080/login/oauth2/code/okta `
--logout-urls http://localhost:8080 `
--reveal-secrets

Copy the domain, client ID, and client secret of your app and paste it into the following input boxes:

When you enter a value in the input fields present on this page, any code snippet that uses the value will update to reflect it. Using the input fields makes copying and pasting code as you follow along easy.

For security, these configuration values are stored in memory and only used locally. They are gone as soon as you refresh the page!

Now, create an application.properties file in the root directory to configure the Okta Spring Boot starter:

application.properties
okta.oauth2.issuer=https://AUTH0-DOMAIN/
okta.oauth2.client-id=AUTH0-CLIENT-ID
okta.oauth2.client-secret=AUTH0-CLIENT-SECRET

Add this file to .gitignore so you don't accidentally check it into source control:

.gitignore
application.properties

NOTE: You can also put these values in src/main/resources/application.properties. However, we recommend you DO NOT include the client secret in this file for security reasons.

Create a HomeController.java class next to DemoApplication.java:

COMMAND
New-Item src/main/java/com/example/demo/HomeController.java

Populate it with the following code:

src/main/java/com/example/demo/HomeController.java
package com.example.demo;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
class HomeController {
@GetMapping("/")
public String home(@AuthenticationPrincipal OidcUser user) {
return "Hello, " + user.getFullName() + "!";
}
}

This controller is protected by Spring Security because the Okta Spring Boot starter auto-configures everything to be protected by default.

Start the app and register with passkeys

Start the app:

GRADLE
MAVEN
.\gradlew bootRun

Open a browser and navigate to http://localhost:8080. Click on Sign Up and create a new user. You will be prompted to sign up with a passkey.

Once you sign up, you will be redirected to the home page. You should see your username displayed.

You have successfully completed the challenge by creating a Spring Boot app that uses OIDC and passkeys for authentication.

[Optional] Implement a home page and logout feature

To implement a Logout feature, add dependencies for Thymeleaf and its Spring Security extension.

If you're using Gradle, modify the build.gradle file:

build.gradle
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'

If you're using Maven, update your pom.xml:

pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity6</artifactId>
</dependency>

Add a template to render the homepage at src/main/resources/templates/home.html:

COMMAND
New-Item src/main/resources/templates/home.html

Paste in the following code:

src/main/resources/templates/home.html
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Spring Boot ❤️ Auth0</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body>
<div class="container">
<h2>Spring Boot Example</h2>
<div th:unless="${#authorization.expression('isAuthenticated()')}">
<p>Hello!</p>
<p>If you're viewing this page then you have successfully configured and started this application.</p>
<p>This example shows you how to use the <a href="https://github.com/okta/okta-spring-boot">Okta Spring Boot
Starter</a> to add passkeys to your application.</p>
<p>When you click the login button below, you will be redirected to login. After you
authenticate, you will be returned to this application.</p>
</div>
<div th:if="${#authorization.expression('isAuthenticated()')}">
<p>Welcome home, <span th:text="${#authentication.principal.attributes['name']}">Mary Coder</span>!</p>
<p>You have successfully authenticated with Auth0, and have been redirected back to this application.</p>
<p>Here are your user's attributes:</p>
<table class="table table-striped">
<thead>
<tr>
<th>Claim</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr th:each="item : ${claims}">
<td th:text="${item.key}">Key</td>
<td th:id="${'claim-' + item.key}" th:text="${item.value}">Value</td>
</tr>
</tbody>
</table>
</div>
<form method="get" th:action="@{/oauth2/authorization/okta}"
th:unless="${#authorization.expression('isAuthenticated()')}">
<button id="login" class="btn btn-primary" type="submit">Login</button>
</form>
<form method="post" th:action="@{/logout}" th:if="${#authorization.expression('isAuthenticated()')}">
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
<button id="logout" class="btn btn-danger" type="submit">Logout</button>
</form>
</div>
</body>
</html>

Update the HomeController#home() method to return the user's claims:

src/main/java/com/example/demo/HomeController.java
@GetMapping("/")
public ModelAndView home(@AuthenticationPrincipal OidcUser user) {
return new ModelAndView("home", Collections.singletonMap("claims", user.getClaims()));
}

NOTE: These will be the claims in the ID token, not the access token.

Create a SecurityConfiguration.java class to configure logout:

COMMAND
New-Item src/main/java/com/example/demo/SecurityConfiguration.java

Paste in the following code:

src/main/java/com/example/demo/SecurityConfiguration.java
package com.example.demo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.client.oidc.web.logout.OidcClientInitiatedLogoutSuccessHandler;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import static org.springframework.security.config.Customizer.withDefaults;
@Configuration
public class SecurityConfiguration {
private final ClientRegistrationRepository clientRegistrationRepository;
public SecurityConfiguration(ClientRegistrationRepository clientRegistrationRepository) {
this.clientRegistrationRepository = clientRegistrationRepository;
}
private LogoutSuccessHandler logoutSuccessHandler() {
OidcClientInitiatedLogoutSuccessHandler logoutSuccessHandler =
new OidcClientInitiatedLogoutSuccessHandler(this.clientRegistrationRepository);
// Sets the location that the End-User's User Agent will be redirected to
// after the logout has been performed at the Provider
logoutSuccessHandler.setPostLogoutRedirectUri("{baseUrl}");
return logoutSuccessHandler;
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated())
.oauth2Login(withDefaults())
.logout(logout -> logout.logoutSuccessHandler(logoutSuccessHandler()));
return http.build();
}
}

Restart your application and now you will be able to log in and log out. Huzzah!

When you log out, you'll be prompted to log in again with Auth0. That's because all routes are protected.

Recap

In this lab, you learned how to build a Spring Boot app with Java, secure it with OIDC and Auth0, and configure the logout feature. It's pretty sweet how you can create and configure a Spring Boot app with passkeys support using Auth0 so fast!

Be sure to visit the Okta Spring Boot Starter's GitHub repository to stay informed on the latest developments and join the growing community of Spring Boot users who use Okta.