3 min read
Create a Java REST API with Helidon

In this tutorial, I'll show you how to create a secure REST API and native image with Helidon. You'll see how to run a secure, OAuth 2.0-protected, Java REST API that allows JWT authentication. Then, I'll compare its performance with Micronaut, Quarkus, and Spring Boot.
This tutorial is also available as a screencast.
Prerequisites:
- SDKMAN (for Java 17 with GraalVM)
- HTTPie (a better version of cURL)
- An Okta Developer Account (or the Okta CLI)
TIP: The brackets at the end of some steps indicate the IntelliJ Live Templates I used in the video. You can find the template definitions at mraible/idea-live-templates.
Install a JDK with GraalVM
Use SDKMAN to install Java 17 with GraalVM
sdk install java 22.1.0.r17-grl
Generate an OAuth 2.0 access token
Install the Okta CLI and run
okta registerto sign up for a new account. If you already have an account, runokta login.Run
okta apps create spa. Setoidcdebuggeras an app name and press Enter.Use
https://oidcdebugger.com/debugfor the Redirect URI and set the Logout Redirect URI tohttps://oidcdebugger.com.Navigate to the OpenID Connect Debugger website.
Fill in your client ID
Use
https://{yourOktaDomain}/oauth2/default/v1/authorizefor the Authorize URISelect code for the response type and Use PKCE
Click Send Request to continue
Set the access token as a
TOKENenvironment variable in a terminal window.TOKEN=eyJraWQiOiJYa2pXdjMzTDRBYU1ZSzNGM...
Build a Java REST API with Helidon
Create a Helidon app with OAuth 2.0 support:
mvn -U archetype:generate -DinteractiveMode=false \ -DarchetypeGroupId=io.helidon.archetypes \ -DarchetypeArtifactId=helidon-quickstart-mp \ -DarchetypeVersion=2.5.0 \ -DgroupId=com.okta.rest \ -DartifactId=helidon \ -Dpackage=com.okta.restTIP: You can also install Helidon's CLI and run
helidon init.Add MicroProfile JWT support in
pom.xml:<dependency> <groupId>io.helidon.microprofile.jwt</groupId> <artifactId>helidon-microprofile-jwt-auth</artifactId> </dependency>Add a
HelloResourceclass that returns the user's information: [h-hello]package com.okta.rest.controller; import io.helidon.security.Principal; import io.helidon.security.SecurityContext; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import java.util.Optional; import static javax.ws.rs.core.MediaType.TEXT_PLAIN; @Path("/hello") public class HelloResource { @GET @Produces(TEXT_PLAIN) public String hello(@Context SecurityContext context) { Optional<Principal> userPrincipal = context.userPrincipal(); return "Hello, " + userPrincipal.get().getName() + "!"; } }Add a
HelloApplicationclass insrc/main/java/com/okta/restto register your resource and configure JWT authentication: [h-app]package com.okta.rest; import com.okta.rest.controller.HelloResource; import org.eclipse.microprofile.auth.LoginConfig; import javax.enterprise.context.ApplicationScoped; import javax.ws.rs.core.Application; import java.util.Set; @LoginConfig(authMethod = "MP-JWT") @ApplicationScoped public class HelloApplication extends Application { @Override public Set<Class<?>> getClasses() { return Set.of(HelloResource.class); } }Add your Okta endpoints to
src/main/resources/META-INF/microprofile-config.properties.mp.jwt.verify.publickey.location=https://{yourOktaDomain}/oauth2/default/v1/keys mp.jwt.verify.issuer=https://{yourOktaDomain}/oauth2/default
Run and test your Helidon REST API with HTTPie
Start your app from your IDE or using a terminal:
mvn package && java -jar ./target/helidon.jarTest your API with an access token.
http :8080/hello Authorization:"Bearer $TOKEN"
Build a native Helidon app with GraalVM
Compile your Helidon app into a native executable using the
native-imageprofile:mvn package -Pnative-imageStart your Helidon app:
./target/helidonTest your API with an access token.
http :8080/hello Authorization:"Bearer $TOKEN"
Startup time comparison
I compared startup times between frameworks by running each image three times before recording the numbers. Then, I ran each app five more times and averaged the results. I gathered these numbers on a 2019 MacBook Pro with an SSD, 2.4 GHz 8-Core Intel Core i9 processor, and 64 GB of RAM.
Versions used: Quarkus 2.9.0, Micronaut 3.4.3, Helidon 2.5.0, and Spring Boot 2.6.7 with Spring Native 0.11.5.
Memory usage comparison
I tested the memory usage (in megabytes) of each app using the command below. I ran it right after I started the app, after a single authenticated request, and after five authenticated requests.
ps -o pid,rss,command | grep --color <executable> | awk '{$2=int($2/1024)"M";}{ print;}'The chart below shows the memory usage after five requests.
What about the MacBook Pro M1 Max?
My MacBook Pro (16-inch, 2021) with Apple M1 Max builds much faster, apps start up 2x faster, but they use more memory.
Comparing Native Java REST API Frameworks Live Stream
I missed Devoxx France this year, but I'm still doing my presentation! I'll be live-streaming Comparing Native Java REST API Frameworks on June 7, 2022 at 6:00 MDT (14:00 CEST). Join me or watch the recorded version below!
Secure Native Java with Helidon FTW!
⚡️ Create a secure REST API with Helidon: okta start helidon
🚀 Find this example's code on GitHub: @oktadev/native-java-examples/helidon
👀 Related blog post: Build REST APIs and Native Java Apps with Helidon
Okta Developer Blog Comment Policy
We welcome relevant and respectful comments. Off-topic comments may be removed.