{"id":82443,"date":"2018-10-08T10:39:48","date_gmt":"2018-10-08T07:39:48","guid":{"rendered":"http:\/\/www.javacodegeeks.com\/?p=82443"},"modified":"2018-10-15T09:32:30","modified_gmt":"2018-10-15T06:32:30","slug":"build-java-rest-api-java-ee-oidc","status":"publish","type":"post","link":"https:\/\/www.javacodegeeks.com\/2018\/10\/build-java-rest-api-java-ee-oidc.html","title":{"rendered":"Build a Java REST API with Java EE and OIDC"},"content":{"rendered":"<p><span style=\"font-size: 20px;\"><b>\u201cI love writing authentication and authorization code.\u201d ~ No Java Developer Ever.<\/b> Tired of building the same login screens over and over? <a href=\"https:\/\/developer.okta.com\/signup?utm_source=java%20Code%20Geeks&#038;utm_medium=Content%20Syndication&#038;utm_campaign=secure%20java%20ee%20api\">Try the Okta API for hosted authentication, authorization, and multi-factor auth.<\/a><\/span><\/p>\n<p>Java EE allows you to build Java REST API s quickly and easily with JAX-RS and JPA. Java EE is an umbrella standards specification that describes a number of Java technologies, including EJB, JPA, JAX-RS, and many others. It was originally designed to allow portability between Java application servers, and flourished in the early 2000s. Back then, application servers were all the rage and provided by many well-known companies such as IBM, BEA, and Sun. JBoss was a startup that disrupted the status quo and showed it was possible to develop a Java EE application server as an open source project, and give it away for free. JBoss was bought by RedHat in 2006.<\/p>\n<p>In the early 2000s, Java developers used servlets and EJBs to develop their server applications. Hibernate and Spring came along in 2002 and 2004, respectively. Both technologies had a huge impact on Java developers everywhere, showing them it was possible to write distributed, robust applications without EJBs. Hibernate\u2019s POJO model was eventually adopted as the JPA standard and heavily influenced EJB as well.<\/p>\n<p>Fast forward to 2018, and Java EE certainly doesn\u2019t look like it used to! Now, it\u2019s mostly POJOs and annotations and far simpler to use.<\/p>\n<h2 id=\"why-build-a-java-rest-api-with-java-ee-and-not-spring-boot\">Why Build a Java REST API with Java EE and Not Spring Boot?<\/h2>\n<p>Spring Boot is one of my favorite technologies in the Java ecosystem. It\u2019s drastically reduced the configuration necessary in a Spring application and made it possible to whip up REST APIs in just a few lines of code. However, I\u2019ve had a lot of API security questions lately from developers that\u00a0<em>aren\u2019t<\/em>\u00a0using Spring Boot. Some of them aren\u2019t even using Spring!<\/p>\n<p>For this reason, I thought it\u2019d be fun to build a Java REST API (using Java EE) that\u2019s the same as a Spring Boot REST API I developed in the past. Namely, the \u201cgood-beers\u201d API from my\u00a0<a href=\"https:\/\/developer.okta.com\/blog\/2017\/04\/26\/bootiful-development-with-spring-boot-and-angular?utm_source=java%20Code%20Geeks&amp;utm_medium=Content%20Syndication&amp;utm_campaign=secure%20java%20ee%20api\">Bootiful Angular<\/a>\u00a0and\u00a0<a href=\"https:\/\/developer.okta.com\/blog\/2017\/12\/06\/bootiful-development-with-spring-boot-and-react?utm_source=java%20Code%20Geeks&amp;utm_medium=Content%20Syndication&amp;utm_campaign=secure%20java%20ee%20api\">Bootiful React<\/a>\u00a0posts.<\/p>\n<h2 id=\"use-java-ee-to-build-your-java-rest-api\">Use Java EE to Build Your Java REST API<\/h2>\n<p>To begin, I\u00a0<a href=\"https:\/\/twitter.com\/mraible\/status\/1032688466025435137\">asked my network on Twitter<\/a>\u00a0if any quickstarts existed for Java EE like start.spring.io. I received a few suggestions and started doing some research.\u00a0<a href=\"https:\/\/twitter.com\/dblevins\">David Blevins<\/a>\u00a0recommended I look at\u00a0<a href=\"https:\/\/github.com\/tomitribe\/tomee-jaxrs-starter-project\">tomee-jaxrs-starter-project<\/a>, so I started there. I also looked into the\u00a0<a href=\"http:\/\/tomee.apache.org\/tomee-mp-getting-started.html\">TomEE Maven Archetype<\/a>, as recommended by\u00a0<a href=\"http:\/\/twitter.com\/radcortez\">Roberto Cortez<\/a>.<\/p>\n<p>I liked the jaxrs-starter project because it showed how to create a REST API with JAX-RS. The TomEE Maven archetype was helpful too, especially since it showed how to use JPA, H2, and JSF. I combined the two to create my own minimal starter that you can use to implement secure Java EE APIs on TomEE. You don\u2019t have to use TomEE for these examples, but I haven\u2019t tested them on other implementations.<\/p>\n<p><em>If you get these examples working on other app servers, please let me know and I\u2019ll update this blog post.<\/em><\/p>\n<p>In these examples, I\u2019ll be using Java 8 and Java EE 7.0 with TomEE 7.1.0. TomEE 7.x is the EE 7 compatible version; a TomEE 8.x branch exists for EE8 compatibility work, but there are no releases yet. I expect you to have\u00a0<a href=\"https:\/\/maven.apache.org\/\">Apache Maven<\/a>\u00a0installed too.<\/p>\n<p>To begin, clone our Java EE REST API repository to your hard drive, and run it:<\/p>\n<pre class=\"gutter: false;brush:java\">git clone https:\/\/github.com\/oktadeveloper\/okta-java-ee-rest-api-example.git javaee-rest-api\r\ncd javaee-rest-api\r\nmvn package tomee:run<\/pre>\n<p>Navigate to http:\/\/localhost:8080 and add a new beer.<\/p>\n<p><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/add-beer.png\"><img decoding=\"async\" class=\"aligncenter wp-image-82444\" style=\"border: none;\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/add-beer-1024x393.png\" alt=\"Java REST API\" width=\"820\" height=\"315\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/add-beer-1024x393.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/add-beer-300x115.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/add-beer-768x295.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/add-beer.png 1600w\" sizes=\"(max-width: 820px) 100vw, 820px\" \/><\/a><\/p>\n<p>Click\u00a0<strong>Add<\/strong>\u00a0and you should see a success message.<\/p>\n<p><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/add-success.png\"><img decoding=\"async\" class=\"aligncenter wp-image-82445\" style=\"border: none;\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/add-success-1024x393.png\" alt=\"Java REST API\" width=\"820\" height=\"315\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/add-success-1024x393.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/add-success-300x115.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/add-success-768x295.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/add-success.png 1600w\" sizes=\"(max-width: 820px) 100vw, 820px\" \/><\/a><\/p>\n<p>Click\u00a0<strong>View beers present<\/strong>\u00a0to see the full list of beers.<\/p>\n<p><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/beers-present.png\"><img decoding=\"async\" class=\"aligncenter wp-image-82446\" style=\"border: none;\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/beers-present-1024x455.png\" alt=\"Java REST API\" width=\"820\" height=\"364\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/beers-present-1024x455.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/beers-present-300x133.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/beers-present-768x341.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/beers-present.png 1600w\" sizes=\"(max-width: 820px) 100vw, 820px\" \/><\/a><br \/>\nYou can also view the list of good beers in the system at\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">http:\/\/localhost:8080\/good-beers<\/code>. Below is the output when using\u00a0<a href=\"https:\/\/httpie.org\/\">HTTPie<\/a>.<\/p>\n<pre class=\"gutter: false;brush:bash\">$ http :8080\/good-beers\r\nHTTP\/1.1 200\r\nContent-Type: application\/json\r\nDate: Wed, 29 Aug 2018 21:58:23 GMT\r\nServer: Apache TomEE\r\nTransfer-Encoding: chunked<\/pre>\n<pre class=\"gutter: false;brush:js\">[\r\n    {\r\n        \"id\": 101,\r\n        \"name\": \"Kentucky Brunch Brand Stout\"\r\n    },\r\n    {\r\n        \"id\": 102,\r\n        \"name\": \"Marshmallow Handjee\"\r\n    },\r\n    {\r\n        \"id\": 103,\r\n        \"name\": \"Barrel-Aged Abraxas\"\r\n    },\r\n    {\r\n        \"id\": 104,\r\n        \"name\": \"Heady Topper\"\r\n    },\r\n    {\r\n        \"id\": 108,\r\n        \"name\": \"White Rascal\"\r\n    }\r\n]<\/pre>\n<h2>Build a REST API with Java EE<\/h2>\n<p>I showed you what this application can do, but I haven\u2019t talked about how it\u2019s built. It has a few XML configuration files, but I\u2019m going to skip over most of those. Here\u2019s what the directory structure looks like:<\/p>\n<pre class=\"gutter: false;brush:bash\">$ tree .\r\n.\r\n\u251c\u2500\u2500 LICENSE\r\n\u251c\u2500\u2500 README.md\r\n\u251c\u2500\u2500 pom.xml\r\n\u2514\u2500\u2500 src\r\n    \u251c\u2500\u2500 main\r\n    \u2502   \u251c\u2500\u2500 java\r\n    \u2502   \u2502   \u2514\u2500\u2500 com\r\n    \u2502   \u2502       \u2514\u2500\u2500 okta\r\n    \u2502   \u2502           \u2514\u2500\u2500 developer\r\n    \u2502   \u2502               \u251c\u2500\u2500 Beer.java\r\n    \u2502   \u2502               \u251c\u2500\u2500 BeerBean.java\r\n    \u2502   \u2502               \u251c\u2500\u2500 BeerResource.java\r\n    \u2502   \u2502               \u251c\u2500\u2500 BeerService.java\r\n    \u2502   \u2502               \u2514\u2500\u2500 StartupBean.java\r\n    \u2502   \u251c\u2500\u2500 resources\r\n    \u2502   \u2502   \u2514\u2500\u2500 META-INF\r\n    \u2502   \u2502       \u2514\u2500\u2500 persistence.xml\r\n    \u2502   \u2514\u2500\u2500 webapp\r\n    \u2502       \u251c\u2500\u2500 WEB-INF\r\n    \u2502       \u2502   \u251c\u2500\u2500 beans.xml\r\n    \u2502       \u2502   \u2514\u2500\u2500 faces-config.xml\r\n    \u2502       \u251c\u2500\u2500 beer.xhtml\r\n    \u2502       \u251c\u2500\u2500 index.jsp\r\n    \u2502       \u2514\u2500\u2500 result.xhtml\r\n    \u2514\u2500\u2500 test\r\n        \u2514\u2500\u2500 resources\r\n            \u2514\u2500\u2500 arquillian.xml\r\n\r\n12 directories, 16 files<\/pre>\n<p>The most important XML files is the\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">pom.xml<\/code>\u00a0that defines dependencies and allows you to run the TomEE Maven Plugin. It\u2019s pretty short and sweet, with only one dependency and one plugin.<\/p>\n<pre class=\"gutter: false;brush:xml; wrap-lines:false\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\r\n&lt;project xmlns=\"http:\/\/maven.apache.org\/POM\/4.0.0\" xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"\r\n         xsi:schemaLocation=\"http:\/\/maven.apache.org\/POM\/4.0.0 http:\/\/maven.apache.org\/maven-v4_0_0.xsd\"&gt;\r\n    &lt;modelVersion&gt;4.0.0&lt;\/modelVersion&gt;\r\n\r\n    &lt;groupId&gt;com.okta.developer&lt;\/groupId&gt;\r\n    &lt;artifactId&gt;java-ee-rest-api&lt;\/artifactId&gt;\r\n    &lt;version&gt;1.0-SNAPSHOT&lt;\/version&gt;\r\n    &lt;packaging&gt;war&lt;\/packaging&gt;\r\n    &lt;name&gt;Java EE Webapp with JAX-RS API&lt;\/name&gt;\r\n    &lt;url&gt;http:\/\/developer.okta.com&lt;\/url&gt;\r\n\r\n    &lt;properties&gt;\r\n        &lt;project.build.sourceEncoding&gt;UTF-8&lt;\/project.build.sourceEncoding&gt;\r\n        &lt;project.reporting.outputEncoding&gt;UTF-8&lt;\/project.reporting.outputEncoding&gt;\r\n        &lt;maven.compiler.target&gt;1.8&lt;\/maven.compiler.target&gt;\r\n        &lt;maven.compiler.source&gt;1.8&lt;\/maven.compiler.source&gt;\r\n        &lt;failOnMissingWebXml&gt;false&lt;\/failOnMissingWebXml&gt;\r\n        &lt;javaee-api.version&gt;7.0&lt;\/javaee-api.version&gt;\r\n        &lt;tomee.version&gt;7.1.0&lt;\/tomee.version&gt;\r\n    &lt;\/properties&gt;\r\n\r\n    &lt;dependencies&gt;\r\n        &lt;dependency&gt;\r\n            &lt;groupId&gt;javax&lt;\/groupId&gt;\r\n            &lt;artifactId&gt;javaee-api&lt;\/artifactId&gt;\r\n            &lt;version&gt;${javaee-api.version}&lt;\/version&gt;\r\n            &lt;scope&gt;provided&lt;\/scope&gt;\r\n        &lt;\/dependency&gt;\r\n    &lt;\/dependencies&gt;\r\n\r\n    &lt;build&gt;\r\n        &lt;plugins&gt;\r\n            &lt;plugin&gt;\r\n                &lt;groupId&gt;org.apache.tomee.maven&lt;\/groupId&gt;\r\n                &lt;artifactId&gt;tomee-maven-plugin&lt;\/artifactId&gt;\r\n                &lt;version&gt;${tomee.version}&lt;\/version&gt;\r\n                &lt;configuration&gt;\r\n                    &lt;context&gt;ROOT&lt;\/context&gt;\r\n                &lt;\/configuration&gt;\r\n            &lt;\/plugin&gt;\r\n        &lt;\/plugins&gt;\r\n    &lt;\/build&gt;\r\n&lt;\/project&gt;<\/pre>\n<p>The main entity is\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">Beer.java<\/code>.<\/p>\n<pre class=\"gutter: false;brush:java\">package com.okta.developer;\r\n\r\nimport javax.persistence.Entity;\r\nimport javax.persistence.GeneratedValue;\r\nimport javax.persistence.GenerationType;\r\nimport javax.persistence.Id;\r\n\r\n@Entity\r\npublic class Beer {\r\n    @Id\r\n    @GeneratedValue(strategy = GenerationType.AUTO)\r\n    private int id;\r\n    private String name;\r\n\r\n    public Beer() {}\r\n\r\n    public Beer(String name) {\r\n        this.name = name;\r\n    }\r\n\r\n    public int getId() {\r\n        return id;\r\n    }\r\n\r\n    public void setId(int id) {\r\n        this.id = id;\r\n    }\r\n\r\n    public String getName() {\r\n        return name;\r\n    }\r\n\r\n    public void setName(String beerName) {\r\n        this.name = beerName;\r\n    }\r\n\r\n    @Override\r\n    public String toString() {\r\n        return \"Beer{\" +\r\n                \"id=\" + id +\r\n                \", name='\" + name + '\\'' +\r\n                '}';\r\n    }\r\n}<\/pre>\n<p>The database (a.k.a., datasource) is configured in\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">src\/main\/resources\/META-INF\/persistence.xml<\/code>.<\/p>\n<pre class=\"gutter: false;brush:xml; wrap-lines:false\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\r\n&lt;persistence version=\"2.0\" xmlns=\"http:\/\/java.sun.com\/xml\/ns\/persistence\"\r\n             xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"\r\n             xsi:schemaLocation=\"http:\/\/java.sun.com\/xml\/ns\/persistence http:\/\/java.sun.com\/xml\/ns\/persistence\/persistence_2_0.xsd\"&gt;\r\n    &lt;persistence-unit name=\"beer-pu\" transaction-type=\"JTA\"&gt;\r\n        &lt;jta-data-source&gt;beerDatabase&lt;\/jta-data-source&gt;\r\n        &lt;class&gt;com.okta.developer.Beer&lt;\/class&gt;\r\n        &lt;properties&gt;\r\n            &lt;property name=\"openjpa.jdbc.SynchronizeMappings\" value=\"buildSchema(ForeignKeys=true)\"\/&gt;\r\n        &lt;\/properties&gt;\r\n    &lt;\/persistence-unit&gt;\r\n&lt;\/persistence&gt;<\/pre>\n<p>The\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">BeerService.java<\/code>\u00a0class handles reading and saving this entity to the database using JPA\u2019s\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">EntityManager<\/code>.<\/p>\n<pre class=\"gutter: false;brush:java\">package com.okta.developer;\r\n\r\nimport javax.ejb.Stateless;\r\nimport javax.persistence.EntityManager;\r\nimport javax.persistence.PersistenceContext;\r\nimport javax.persistence.Query;\r\nimport javax.persistence.criteria.CriteriaQuery;\r\nimport java.util.List;\r\n\r\n@Stateless\r\npublic class BeerService {\r\n\r\n    @PersistenceContext(unitName = \"beer-pu\")\r\n    private EntityManager entityManager;\r\n\r\n    public void addBeer(Beer beer) {\r\n        entityManager.persist(beer);\r\n    }\r\n\r\n    public List&lt;Beer&gt; getAllBeers() {\r\n        CriteriaQuery&lt;Beer&gt; cq = entityManager.getCriteriaBuilder().createQuery(Beer.class);\r\n        cq.select(cq.from(Beer.class));\r\n        return entityManager.createQuery(cq).getResultList();\r\n    }\r\n\r\n    public void clear() {\r\n        Query removeAll = entityManager.createQuery(\"delete from Beer\");\r\n        removeAll.executeUpdate();\r\n    }\r\n}<\/pre>\n<p>There\u2019s a\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">StartupBean.java<\/code>\u00a0that handles populating the database on startup, and clearing it on shutdown.<\/p>\n<pre class=\"gutter: false;brush:java\">package com.okta.developer;\r\n\r\nimport javax.annotation.PostConstruct;\r\nimport javax.annotation.PreDestroy;\r\nimport javax.ejb.Singleton;\r\nimport javax.ejb.Startup;\r\nimport javax.inject.Inject;\r\nimport java.util.stream.Stream;\r\n\r\n@Singleton\r\n@Startup\r\npublic class StartupBean {\r\n    private final BeerService beerService;\r\n\r\n    @Inject\r\n    public StartupBean(BeerService beerService) {\r\n        this.beerService = beerService;\r\n    }\r\n\r\n    @PostConstruct\r\n    private void startup() {\r\n        \/\/ Top beers from https:\/\/www.beeradvocate.com\/lists\/top\/\r\n        Stream.of(\"Kentucky Brunch Brand Stout\", \"Marshmallow Handjee\", \r\n                \"Barrel-Aged Abraxas\", \"Heady Topper\",\r\n                \"Budweiser\", \"Coors Light\", \"PBR\").forEach(name -&gt;\r\n                beerService.addBeer(new Beer(name))\r\n        );\r\n        beerService.getAllBeers().forEach(System.out::println);\r\n    }\r\n\r\n    @PreDestroy\r\n    private void shutdown() {\r\n        beerService.clear();\r\n    }\r\n}<\/pre>\n<p>These three classes make up the foundation of the app, plus there\u2019s a\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">BeerResource.java<\/code>\u00a0class that uses JAX-RS to expose the\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">\/good-beers<\/code>\u00a0endpoint.<\/p>\n<pre class=\"gutter: false;brush:java\">package com.okta.developer;\r\n\r\nimport javax.ejb.Lock;\r\nimport javax.ejb.Singleton;\r\nimport javax.inject.Inject;\r\nimport javax.ws.rs.GET;\r\nimport javax.ws.rs.Path;\r\nimport javax.ws.rs.Produces;\r\nimport java.util.List;\r\nimport java.util.stream.Collectors;\r\n\r\nimport static javax.ejb.LockType.READ;\r\nimport static javax.ws.rs.core.MediaType.APPLICATION_JSON;\r\n\r\n@Lock(READ)\r\n@Singleton\r\n@Path(\"\/good-beers\")\r\npublic class BeerResource {\r\n    private final BeerService beerService;\r\n\r\n    @Inject\r\n    public BeerResource(BeerService beerService) {\r\n        this.beerService = beerService;\r\n    }\r\n\r\n    @GET\r\n    @Produces({APPLICATION_JSON})\r\n    public List&lt;Beer&gt; getGoodBeers() {\r\n        return beerService.getAllBeers().stream()\r\n                .filter(this::isGreat)\r\n                .collect(Collectors.toList());\r\n    }\r\n\r\n    private boolean isGreat(Beer beer) {\r\n        return !beer.getName().equals(\"Budweiser\") &amp;&amp;\r\n                !beer.getName().equals(\"Coors Light\") &amp;&amp;\r\n                !beer.getName().equals(\"PBR\");\r\n    }\r\n}<\/pre>\n<p>Lastly, there\u2019s a\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">BeerBean.java<\/code>\u00a0class is used as a managed bean for JSF.<\/p>\n<pre class=\"gutter: false;brush:java\">package com.okta.developer;\r\n\r\nimport javax.enterprise.context.RequestScoped;\r\nimport javax.inject.Inject;\r\nimport javax.inject.Named;\r\nimport java.util.List;\r\n\r\n@Named\r\n@RequestScoped\r\npublic class BeerBean {\r\n\r\n    @Inject\r\n    private BeerService beerService;\r\n    private List&lt;Beer&gt; beersAvailable;\r\n    private String name;\r\n\r\n    public String getName() {\r\n        return name;\r\n    }\r\n\r\n    public void setName(String name) {\r\n        this.name = name;\r\n    }\r\n\r\n    public List&lt;Beer&gt; getBeersAvailable() {\r\n        return beersAvailable;\r\n    }\r\n\r\n    public void setBeersAvailable(List&lt;Beer&gt; beersAvailable) {\r\n        this.beersAvailable = beersAvailable;\r\n    }\r\n\r\n    public String fetchBeers() {\r\n        beersAvailable = beerService.getAllBeers();\r\n        return \"success\";\r\n    }\r\n\r\n    public String add() {\r\n        Beer beer = new Beer();\r\n        beer.setName(name);\r\n        beerService.addBeer(beer);\r\n        return \"success\";\r\n    }\r\n}<\/pre>\n<p>You now have a REST API built with Java EE! However, it\u2019s not secure. In the following sections, I\u2019ll show you how to secure it using Okta\u2019s JWT Verifier for Java, Spring Security, and Pac4j.<\/p>\n<h2>Add OIDC Security with Okta to Your Java REST API<\/h2>\n<p>You will need to create an OIDC Application in Okta to verify the security configurations you\u2019re about to implement work. To make this effortless, you can use Okta\u2019s API for OIDC. At Okta, our goal is to make\u00a0<a href=\"https:\/\/developer.okta.com\/product\/user-management\/?utm_source=java%20Code%20Geeks&amp;utm_medium=Content%20Syndication&amp;utm_campaign=secure%20java%20ee%20api\">identity management<\/a>\u00a0a lot easier, more secure, and more scalable than what you\u2019re used to. Okta is a cloud service that allows developers to create, edit, and securely store user accounts and user account data, and connect them with one or multiple applications. Our API enables you to:<\/p>\n<ul>\n<li><a href=\"https:\/\/developer.okta.com\/product\/authentication\/?utm_source=java%20Code%20Geeks&amp;utm_medium=Content%20Syndication&amp;utm_campaign=secure%20java%20ee%20api\">Authenticate<\/a>\u00a0and\u00a0<a href=\"https:\/\/developer.okta.com\/product\/authorization\/?utm_source=java%20Code%20Geeks&amp;utm_medium=Content%20Syndication&amp;utm_campaign=secure%20java%20ee%20api\">authorize<\/a>\u00a0your users<\/li>\n<li>Store data about your users<\/li>\n<li>Perform password-based and\u00a0<a href=\"https:\/\/developer.okta.com\/authentication-guide\/social-login\/?utm_source=java%20Code%20Geeks&amp;utm_medium=Content%20Syndication&amp;utm_campaign=secure%20java%20ee%20api\">social login<\/a><\/li>\n<li>Secure your application with\u00a0<a href=\"https:\/\/developer.okta.com\/use_cases\/mfa\/?utm_source=java%20Code%20Geeks&amp;utm_medium=Content%20Syndication&amp;utm_campaign=secure%20java%20ee%20api\">multi-factor authentication<\/a><\/li>\n<li>And much more! Check out our\u00a0<a href=\"https:\/\/developer.okta.com\/documentation\/?utm_source=java%20Code%20Geeks&amp;utm_medium=Content%20Syndication&amp;utm_campaign=secure%20java%20ee%20api\">product documentation<\/a><\/li>\n<\/ul>\n<p>Are you sold?\u00a0<a href=\"https:\/\/developer.okta.com\/signup\/?utm_source=java%20Code%20Geeks&amp;utm_medium=Content%20Syndication&amp;utm_campaign=secure%20java%20ee%20api\">Register for a forever-free developer account<\/a>\u00a0today! When you\u2019re finished, complete the steps below to create an OIDC app.<\/p>\n<ol>\n<li>Log in to your developer account on\u00a0<a href=\"https:\/\/developer.okta.com\/?utm_source=java%20Code%20Geeks&amp;utm_medium=Content%20Syndication&amp;utm_campaign=secure%20java%20ee%20api\">developer.okta.com<\/a>.<\/li>\n<li>Navigate to\u00a0<strong>Applications<\/strong>\u00a0and click on\u00a0<strong>Add Application<\/strong>.<\/li>\n<li>Select\u00a0<strong>Web<\/strong>\u00a0and click\u00a0<strong>Next<\/strong>.<\/li>\n<li>Give the application a name (.e.g.,\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">Java EE Secure API<\/code>) and add the following as Login redirect URIs:\n<ul>\n<li><code class=\"highlighter-rouge\" style=\"font-size: 13px;\">http:\/\/localhost:3000\/implicit\/callback<\/code><\/li>\n<li><code class=\"highlighter-rouge\" style=\"font-size: 13px;\">http:\/\/localhost:8080\/login\/oauth2\/code\/okta<\/code><\/li>\n<li><code class=\"highlighter-rouge\" style=\"font-size: 13px;\">http:\/\/localhost:8080\/callback?client_name=OidcClient<\/code><\/li>\n<\/ul>\n<\/li>\n<li>Click\u00a0<strong>Done<\/strong>, then edit the project and enable \u201cImplicit (Hybrid)\u201d as a grant type (allow ID and access tokens) and click\u00a0<strong>Save<\/strong>.<\/li>\n<\/ol>\n<h2>Protect Your Java REST API with JWT Verifier<\/h2>\n<p>To validate JWTs from Okta, you\u2019ll need to add\u00a0<a href=\"https:\/\/github.com\/okta\/okta-jwt-verifier-java\">Okta JWT Verifier for Java<\/a>\u00a0to your\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">pom.xml<\/code>.<\/p>\n<pre class=\"gutter: false;brush:xml\">&lt;properties&gt;\r\n    ...\r\n    &lt;okta-jwt.version&gt;0.3.0&lt;\/okta-jwt.version&gt;\r\n&lt;\/properties&gt;\r\n\r\n&lt;dependencies&gt;\r\n    ...\r\n    &lt;dependency&gt;\r\n        &lt;groupId&gt;com.okta.jwt&lt;\/groupId&gt;\r\n        &lt;artifactId&gt;okta-jwt-verifier&lt;\/artifactId&gt;\r\n        &lt;version&gt;${okta-jwt.version}&lt;\/version&gt;\r\n    &lt;\/dependency&gt;\r\n&lt;\/dependencies&gt;<\/pre>\n<p>Then create a\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">JwtFilter.java<\/code>\u00a0(in the\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">src\/main\/java\/com\/okta\/developer<\/code>\u00a0directory). This filter looks for an\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">authorization<\/code>\u00a0header with an access token in it. If it exists, it validates it and prints out the user\u2019s\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">sub<\/code>, a.k.a. their email address. If it doesn\u2019t exist, or is in valid, an access denied status is returned.<div style=\"display:inline-block; margin: 15px 0;\"> <div id=\"adngin-JavaCodeGeeks_incontent_video-0\" style=\"display:inline-block;\"><\/div> <\/div><\/p>\n<p>Make sure to replace\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">{yourOktaDomain}<\/code>\u00a0and\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">{clientId}<\/code>\u00a0with the settings from the app you created.<\/p>\n<pre class=\"gutter: false;brush:java\">package com.okta.developer;\r\n\r\nimport com.nimbusds.oauth2.sdk.ParseException;\r\nimport com.okta.jwt.JoseException;\r\nimport com.okta.jwt.Jwt;\r\nimport com.okta.jwt.JwtHelper;\r\nimport com.okta.jwt.JwtVerifier;\r\n\r\nimport javax.servlet.*;\r\nimport javax.servlet.annotation.WebFilter;\r\nimport javax.servlet.http.HttpServletRequest;\r\nimport javax.servlet.http.HttpServletResponse;\r\nimport java.io.IOException;\r\n\r\n@WebFilter(filterName = \"jwtFilter\", urlPatterns = \"\/*\")\r\npublic class JwtFilter implements Filter {\r\n    private JwtVerifier jwtVerifier;\r\n\r\n    @Override\r\n    public void init(FilterConfig filterConfig) {\r\n        try {\r\n            jwtVerifier = new JwtHelper()\r\n                    .setIssuerUrl(\"https:\/\/{yourOktaDomain}\/oauth2\/default\")\r\n                    .setClientId(\"{yourClientId}\")\r\n                    .build();\r\n        } catch (IOException | ParseException e) {\r\n            System.err.print(\"Configuring JWT Verifier failed!\");\r\n            e.printStackTrace();\r\n        }\r\n    }\r\n\r\n    @Override\r\n    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,\r\n                         FilterChain chain) throws IOException, ServletException {\r\n        HttpServletRequest request = (HttpServletRequest) servletRequest;\r\n        HttpServletResponse response = (HttpServletResponse) servletResponse;\r\n        System.out.println(\"In JwtFilter, path: \" + request.getRequestURI());\r\n\r\n        \/\/ Get access token from authorization header\r\n        String authHeader = request.getHeader(\"authorization\");\r\n        if (authHeader == null) {\r\n            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, \"Access denied.\");\r\n            return;\r\n        } else {\r\n            String accessToken = authHeader.substring(authHeader.indexOf(\"Bearer \") + 7);\r\n            try {\r\n                Jwt jwt = jwtVerifier.decodeAccessToken(accessToken);\r\n                System.out.println(\"Hello, \" + jwt.getClaims().get(\"sub\"));\r\n            } catch (JoseException e) {\r\n                e.printStackTrace();\r\n                response.sendError(HttpServletResponse.SC_UNAUTHORIZED, \"Access denied.\");\r\n                return;\r\n            }\r\n        }\r\n\r\n        chain.doFilter(request, response);\r\n    }\r\n\r\n    @Override\r\n    public void destroy() {\r\n    }\r\n}<\/pre>\n<p>To ensure this filter is working, restart your app and run:<\/p>\n<pre class=\"gutter: false;brush:bash\">mvn package tomee:run<\/pre>\n<p>If you navigate to\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">http:\/\/localhost:8080\/good-beers<\/code>\u00a0in your browser, you\u2019ll see an access denied error.<\/p>\n<p><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/tomee-401-.png\"><img decoding=\"async\" class=\"aligncenter wp-image-82449\" style=\"border: none;\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/tomee-401--1024x448.png\" alt=\"Java REST API\" width=\"820\" height=\"359\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/tomee-401--1024x448.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/tomee-401--300x131.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/tomee-401--768x336.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/tomee-401-.png 1600w\" sizes=\"(max-width: 820px) 100vw, 820px\" \/><\/a><\/p>\n<p>To prove it works with a valid JWT, you can clone my Bootiful React project, and run its UI:<\/p>\n<pre class=\"gutter: false;brush:bash\">git clone -b okta https:\/\/github.com\/oktadeveloper\/spring-boot-react-example.git bootiful-react\r\ncd bootiful-react\/client\r\nnpm install<\/pre>\n<p>Edit this project\u2019s\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">client\/src\/App.tsx<\/code>\u00a0file and change the\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">issuer<\/code>\u00a0and\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">clientId<\/code>\u00a0to match your application.<\/p>\n<pre class=\"gutter: false;brush:java\">const config = {\r\n  issuer: 'https:\/\/{yourOktaDomain}\/oauth2\/default',\r\n  redirectUri: window.location.origin + '\/implicit\/callback',\r\n  clientId: '{yourClientId}'\r\n};<\/pre>\n<p>Then start it:<\/p>\n<pre class=\"gutter: false;brush:java\">npm start<\/pre>\n<p>You should then be able to login at\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">http:\/\/localhost:3000<\/code>\u00a0with the credentials you created your account with. However, you won\u2019t be able to load any beers from the API because of a CORS error (in your browser\u2019s developer console).<\/p>\n<pre class=\"gutter: false;brush:bash\">Failed to load http:\/\/localhost:8080\/good-beers: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http:\/\/localhost:3000' is therefore not allowed access.<\/pre>\n<p><strong>TIP:<\/strong>\u00a0If you see a 401 and no CORS error, it likely means your client IDs don\u2019t match.<\/p>\n<p>To fix this CORS error, add a\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">CorsFilter.java<\/code>\u00a0alongside your\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">JwtFilter.java<\/code>\u00a0class. The filter below will allow an\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">OPTIONS<\/code>\u00a0request, and send access-control headers back that allow any origin, GET methods, and any headers. I recommend you to make these settings a bit more specific in production.<\/p>\n<pre class=\"gutter: false;brush:java; wrap-lines:false\">package com.okta.developer;\r\n\r\nimport javax.servlet.*;\r\nimport javax.servlet.annotation.WebFilter;\r\nimport javax.servlet.http.HttpServletRequest;\r\nimport javax.servlet.http.HttpServletResponse;\r\nimport java.io.IOException;\r\n\r\n@WebFilter(filterName = \"corsFilter\")\r\npublic class CorsFilter implements Filter {\r\n\r\n    @Override\r\n    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)\r\n            throws IOException, ServletException {\r\n        HttpServletRequest request = (HttpServletRequest) servletRequest;\r\n        HttpServletResponse response = (HttpServletResponse) servletResponse;\r\n        System.out.println(\"In CorsFilter, method: \" + request.getMethod());\r\n\r\n        \/\/ Authorize (allow) all domains to consume the content\r\n        response.addHeader(\"Access-Control-Allow-Origin\", \"http:\/\/localhost:3000\");\r\n        response.addHeader(\"Access-Control-Allow-Methods\", \"GET\");\r\n        response.addHeader(\"Access-Control-Allow-Headers\", \"*\");\r\n\r\n        \/\/ For HTTP OPTIONS verb\/method reply with ACCEPTED status code -- per CORS handshake\r\n        if (request.getMethod().equals(\"OPTIONS\")) {\r\n            response.setStatus(HttpServletResponse.SC_ACCEPTED);\r\n            return;\r\n        }\r\n\r\n        \/\/ pass the request along the filter chain\r\n        chain.doFilter(request, response);\r\n    }\r\n\r\n    @Override\r\n    public void init(FilterConfig config) {\r\n    }\r\n\r\n    @Override\r\n    public void destroy() {\r\n    }\r\n}<\/pre>\n<p>Both of the filters you\u2019ve added use\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">@WebFilter<\/code>\u00a0to register themselves. This is a convenient annotation, but it doesn\u2019t provide any filter ordering capabilities. To workaround this missing feature, modify\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">JwtFilter<\/code>\u00a0so it doesn\u2019t have a\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">urlPattern<\/code>\u00a0in its\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">@WebFilter<\/code>.<\/p>\n<pre class=\"gutter: false;brush:java\">@WebFilter(filterName = \"jwtFilter\")<\/pre>\n<p>Then create a\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">src\/main\/webapp\/WEB-INF\/web.xml<\/code>\u00a0file and populate it with the following XML. These filter mappings ensure the\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">CorsFilter<\/code>\u00a0is processed first.<\/p>\n<pre class=\"gutter: false;brush:xml; wrap-lines:false\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\r\n&lt;web-app version=\"3.1\"\r\n         xmlns=\"http:\/\/xmlns.jcp.org\/xml\/ns\/javaee\"\r\n         xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"\r\n         xsi:schemaLocation=\"http:\/\/xmlns.jcp.org\/xml\/ns\/javaee http:\/\/xmlns.jcp.org\/xml\/ns\/javaee\/web-app_3_1.xsd\"&gt;\r\n\r\n    &lt;filter-mapping&gt;\r\n        &lt;filter-name&gt;corsFilter&lt;\/filter-name&gt;\r\n        &lt;url-pattern&gt;\/*&lt;\/url-pattern&gt;\r\n    &lt;\/filter-mapping&gt;\r\n\r\n    &lt;filter-mapping&gt;\r\n        &lt;filter-name&gt;jwtFilter&lt;\/filter-name&gt;\r\n        &lt;url-pattern&gt;\/*&lt;\/url-pattern&gt;\r\n    &lt;\/filter-mapping&gt;\r\n&lt;\/web-app&gt;<\/pre>\n<p>Restart your Java API and now everything should work!<\/p>\n<p><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/react-ui-beer-list.png\"><img decoding=\"async\" class=\"aligncenter wp-image-82450 size-large\" style=\"border: none;\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/react-ui-beer-list-742x1024.png\" alt=\"Java REST API\" width=\"620\" height=\"856\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/react-ui-beer-list-742x1024.png 742w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/react-ui-beer-list-217x300.png 217w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/react-ui-beer-list-768x1060.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/react-ui-beer-list.png 1600w\" sizes=\"(max-width: 620px) 100vw, 620px\" \/><\/a><\/p>\n<p>In your console, you should see messages similar to mine:<\/p>\n<pre class=\"gutter: false;brush:bash\">In CorsFilter, method: OPTIONS\r\nIn CorsFilter, method: GET\r\nIn JwtFilter, path: \/good-beers\r\nHello, demo@okta.com<\/pre>\n<p>Using a filter with Okta\u2019s JWT Verifier is an easy way to implement a resource server (in OAuth 2.0 nomenclature). However, it doesn\u2019t provide you with any information about the user. The\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">JwtVerifier<\/code>\u00a0interface does have a\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">decodeIdToken(String idToken, String nonce)<\/code>\u00a0method, but you\u2019d have to pass the ID token in from your client to use it.<\/p>\n<p>In the next two sections, I\u2019ll show you how you can use Spring Security and Pac4j to implement similar security. As a bonus, I\u2019ll show you how to prompt the user to login (when they try to access the API directly) and get the user\u2019s information.<\/p>\n<h2>Secure Your Java REST API with Spring Security<\/h2>\n<p>Spring Security is one of my favorite frameworks in Javaland. Most of the examples on this blog use Spring Boot when showing how to use Spring Security. I\u2019m going to use the latest version \u2013 5.1.0.RC2 \u2013 so this tutorial stays up to date for a few months.<\/p>\n<p>Revert your changes to add JWT Verifier, or simply delete\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">web.xml<\/code>\u00a0to continue.<\/p>\n<p>Modify your\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">pom.xml<\/code>\u00a0to have the necessary dependencies for Spring Security. You\u2019ll also need to add Spring\u2019s snapshot repositories to get the release candidate.<\/p>\n<pre class=\"gutter: false;brush:xml\">&lt;properties&gt;\r\n    ...\r\n    &lt;spring-security.version&gt;5.1.0.RC2&lt;\/spring-security.version&gt;\r\n    &lt;spring.version&gt;5.1.0.RC3&lt;\/spring.version&gt;\r\n    &lt;jackson.version&gt;2.9.6&lt;\/jackson.version&gt;\r\n&lt;\/properties&gt;\r\n\r\n&lt;dependencyManagement&gt;\r\n    &lt;dependencies&gt;\r\n        &lt;dependency&gt;\r\n            &lt;groupId&gt;org.springframework&lt;\/groupId&gt;\r\n            &lt;artifactId&gt;spring-framework-bom&lt;\/artifactId&gt;\r\n            &lt;version&gt;${spring.version}&lt;\/version&gt;\r\n            &lt;scope&gt;import&lt;\/scope&gt;\r\n            &lt;type&gt;pom&lt;\/type&gt;\r\n        &lt;\/dependency&gt;\r\n        &lt;dependency&gt;\r\n            &lt;groupId&gt;org.springframework.security&lt;\/groupId&gt;\r\n            &lt;artifactId&gt;spring-security-bom&lt;\/artifactId&gt;\r\n            &lt;version&gt;${spring-security.version}&lt;\/version&gt;\r\n            &lt;scope&gt;import&lt;\/scope&gt;\r\n            &lt;type&gt;pom&lt;\/type&gt;\r\n        &lt;\/dependency&gt;\r\n    &lt;\/dependencies&gt;\r\n&lt;\/dependencyManagement&gt;\r\n\r\n&lt;dependencies&gt;\r\n    ...\r\n    &lt;dependency&gt;\r\n        &lt;groupId&gt;org.springframework&lt;\/groupId&gt;\r\n        &lt;artifactId&gt;spring-webmvc&lt;\/artifactId&gt;\r\n    &lt;\/dependency&gt;\r\n    &lt;dependency&gt;\r\n        &lt;groupId&gt;org.springframework.security&lt;\/groupId&gt;\r\n        &lt;artifactId&gt;spring-security-web&lt;\/artifactId&gt;\r\n    &lt;\/dependency&gt;\r\n    &lt;dependency&gt;\r\n        &lt;groupId&gt;org.springframework.security&lt;\/groupId&gt;\r\n        &lt;artifactId&gt;spring-security-config&lt;\/artifactId&gt;\r\n    &lt;\/dependency&gt;\r\n    &lt;dependency&gt;\r\n        &lt;groupId&gt;org.springframework.security&lt;\/groupId&gt;\r\n        &lt;artifactId&gt;spring-security-oauth2-client&lt;\/artifactId&gt;\r\n    &lt;\/dependency&gt;\r\n    &lt;dependency&gt;\r\n        &lt;groupId&gt;org.springframework.security&lt;\/groupId&gt;\r\n        &lt;artifactId&gt;spring-security-oauth2-resource-server&lt;\/artifactId&gt;\r\n    &lt;\/dependency&gt;\r\n    &lt;dependency&gt;\r\n        &lt;groupId&gt;org.springframework.security&lt;\/groupId&gt;\r\n        &lt;artifactId&gt;spring-security-oauth2-jose&lt;\/artifactId&gt;\r\n    &lt;\/dependency&gt;\r\n    &lt;dependency&gt;\r\n        &lt;groupId&gt;com.fasterxml.jackson.core&lt;\/groupId&gt;\r\n        &lt;artifactId&gt;jackson-core&lt;\/artifactId&gt;\r\n        &lt;version&gt;${jackson.version}&lt;\/version&gt;\r\n    &lt;\/dependency&gt;\r\n    &lt;dependency&gt;\r\n        &lt;groupId&gt;com.fasterxml.jackson.core&lt;\/groupId&gt;\r\n        &lt;artifactId&gt;jackson-databind&lt;\/artifactId&gt;\r\n        &lt;version&gt;${jackson.version}&lt;\/version&gt;\r\n    &lt;\/dependency&gt;\r\n&lt;\/dependencies&gt;\r\n\r\n&lt;pluginRepositories&gt;\r\n    &lt;pluginRepository&gt;\r\n        &lt;id&gt;spring-snapshots&lt;\/id&gt;\r\n        &lt;name&gt;Spring Snapshots&lt;\/name&gt;\r\n        &lt;url&gt;https:\/\/repo.spring.io\/libs-snapshot&lt;\/url&gt;\r\n        &lt;snapshots&gt;\r\n            &lt;enabled&gt;true&lt;\/enabled&gt;\r\n        &lt;\/snapshots&gt;\r\n    &lt;\/pluginRepository&gt;\r\n&lt;\/pluginRepositories&gt;\r\n&lt;repositories&gt;\r\n    &lt;repository&gt;\r\n        &lt;id&gt;spring-snapshots&lt;\/id&gt;\r\n        &lt;name&gt;Spring Snapshot&lt;\/name&gt;\r\n        &lt;url&gt;https:\/\/repo.spring.io\/libs-snapshot&lt;\/url&gt;\r\n    &lt;\/repository&gt;\r\n&lt;\/repositories&gt;<\/pre>\n<p>Create a\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">SecurityWebApplicationInitializer.java<\/code>\u00a0class in\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">src\/main\/java\/com\/okta\/developer<\/code>:<\/p>\n<pre class=\"gutter: false;brush:java\">package com.okta.developer;\r\n\r\nimport org.springframework.security.web.context.*;\r\n\r\npublic class SecurityWebApplicationInitializer\r\n   extends AbstractSecurityWebApplicationInitializer {\r\n\r\n   public SecurityWebApplicationInitializer() {\r\n       super(SecurityConfiguration.class);\r\n   }\r\n}<\/pre>\n<p>Create a\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">SecurityConfiguration.java<\/code>\u00a0class in the same directory. This class uses Spring Security 5\u2019s\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">oauth2Login()<\/code>\u00a0and registers your Okta app with Spring Security.<\/p>\n<pre class=\"gutter: false;brush:java; wrap-lines:false\">package com.okta.developer;\r\n\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.beans.factory.annotation.Value;\r\nimport org.springframework.context.annotation.Bean;\r\nimport org.springframework.context.annotation.Configuration;\r\nimport org.springframework.context.annotation.PropertySource;\r\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\r\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\r\nimport org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;\r\nimport org.springframework.security.config.http.SessionCreationPolicy;\r\nimport org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService;\r\nimport org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;\r\nimport org.springframework.security.oauth2.client.registration.ClientRegistration;\r\nimport org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;\r\nimport org.springframework.security.oauth2.client.registration.ClientRegistrations;\r\nimport org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;\r\nimport org.springframework.security.web.csrf.CookieCsrfTokenRepository;\r\n\r\n@Configuration\r\n@EnableWebSecurity\r\n@PropertySource(\"classpath:application.properties\")\r\npublic class SecurityConfiguration extends WebSecurityConfigurerAdapter {\r\n    private final String clientSecret;\r\n    private final String clientId;\r\n    private final String issuerUri;\r\n\r\n    @Autowired\r\n    public SecurityConfiguration(@Value(\"${okta.issuer-uri}\") String issuerUri,\r\n            @Value(\"${okta.client-id}\") String clientId,\r\n            @Value(\"${okta.client-secret}\") String clientSecret) {\r\n        this.issuerUri = issuerUri;\r\n        this.clientId = clientId;\r\n        this.clientSecret = clientSecret;\r\n    }\r\n\r\n@Override\r\n   protected void configure(HttpSecurity http) throws Exception {\r\n      http\r\n            .sessionManagement()\r\n                .sessionCreationPolicy(SessionCreationPolicy.ALWAYS)\r\n                .and()\r\n           .csrf()\r\n               .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())\r\n               .and()\r\n           .authorizeRequests()\r\n               .anyRequest().authenticated()\r\n               .and()\r\n           .oauth2Login();\r\n   }\r\n\r\n   @Bean\r\n   public OAuth2AuthorizedClientService authorizedClientService() {\r\n       return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository());\r\n   }\r\n\r\n   @Bean\r\n   public ClientRegistrationRepository clientRegistrationRepository() {\r\n       List&lt;ClientRegistration&gt; registrations = clients.stream()\r\n               .map(this::getRegistration)\r\n               .filter(Objects::nonNull)\r\n               .collect(Collectors.toList());\r\n\r\n       return new InMemoryClientRegistrationRepository(registrations);\r\n   }\r\n\r\n   @Bean\r\n    public ClientRegistrationRepository clientRegistrationRepository() {\r\n        ClientRegistration okta = getRegistration();\r\n        return new InMemoryClientRegistrationRepository(okta);\r\n    }\r\n\r\n    ClientRegistrations.fromOidcIssuerLocation(Objects.requireNonNull(issuerUri))\r\n            .registrationId(\"okta\")\r\n            .clientId(clientId)\r\n            .clientSecret(clientSecret)\r\n            .build();\r\n}<\/pre>\n<p>Create\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">src\/main\/resources\/application.properties<\/code>\u00a0and fill it with your Okta OIDC app settings.<\/p>\n<pre class=\"gutter: false;brush:bash\">okta.client-id={clientId}\r\nokta.client-secret={clientSecret}\r\nokta.issuer-uri=https:\/\/{yourOktaDomain}\/oauth2\/default<\/pre>\n<p><em>Thanks to\u00a0<a href=\"https:\/\/www.baeldung.com\/\">Baeldung<\/a>\u00a0for the\u00a0<a href=\"https:\/\/www.baeldung.com\/spring-security-5-oauth2-login\">excellent documentation on Spring Security 5 OAuth<\/a>.<\/em><\/p>\n<p>Because you enabled CSRF, you have to add the following hidden field for CSRF protection inside any\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">&lt;h:form&gt;<\/code>\u00a0tags. I added the following to\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">src\/main\/webapp\/beer.xhtml<\/code>\u00a0and\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">result.xhtml<\/code>.<\/p>\n<pre class=\"gutter: false;brush:xml\">&lt;input type=\"hidden\" value=\"${_csrf.token}\" name=\"${_csrf.parameterName}\"\/&gt;<\/pre>\n<p>Restart your API (<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">mvn clean package tomee:run<\/code>) and navigate to\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">http:\/\/localhost:8080\/good-beers<\/code>. You should be redirected to Okta to log in.<\/p>\n<p><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/okta-login-.png\"><img decoding=\"async\" class=\"aligncenter wp-image-82451\" style=\"border: none;\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/okta-login--1024x750.png\" alt=\"Java REST API\" width=\"820\" height=\"601\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/okta-login--1024x750.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/okta-login--300x220.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/okta-login--768x563.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/okta-login-.png 1600w\" sizes=\"(max-width: 820px) 100vw, 820px\" \/><\/a><\/p>\n<p>Enter valid credentials and you should see JSON in your browser. Nice looking JSON is provided by the\u00a0<a href=\"https:\/\/chrome.google.com\/webstore\/detail\/json-viewer\/gbmdgpbipfallnflgajpaliibnhdgobh?hl=en-US\">JSON Viewer Chrome Plugin<\/a>.<\/p>\n<p><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/good-beers-json.png\"><img decoding=\"async\" class=\"aligncenter wp-image-82452\" style=\"border: none;\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/good-beers-json-1024x718.png\" alt=\"Java REST API\" width=\"820\" height=\"575\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/good-beers-json-1024x718.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/good-beers-json-300x210.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/good-beers-json-768x539.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/good-beers-json.png 1600w\" sizes=\"(max-width: 820px) 100vw, 820px\" \/><\/a><\/p>\n<p>Requiring users to login to view your API data is handy, but it\u2019s better to make it a resource server for the React UI example. OAuth 2.0 Resource Server support is new in\u00a0<a href=\"https:\/\/spring.io\/blog\/2018\/08\/21\/spring-security-5-1-0-rc1-released\">Spring Security 5.1.0 RC1<\/a>, so I\u2019ll show you how to use it.<\/p>\n<p>Replace the\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">configure()<\/code>\u00a0method in\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">SecurityConfiguration.java<\/code>\u00a0with the following code that enables CORS and sets up a resource server.<\/p>\n<pre class=\"gutter: false;brush:java\">@Override\r\nprotected void configure(HttpSecurity http) throws Exception {\r\n    http\r\n        .sessionManagement()\r\n            .sessionCreationPolicy(SessionCreationPolicy.ALWAYS)\r\n            .and()\r\n        .csrf()\r\n            .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())\r\n            .and()\r\n        .cors()\r\n            .and()\r\n        .authorizeRequests()\r\n            .anyRequest().authenticated()\r\n            .and()\r\n        .oauth2Login()\r\n            .and()\r\n        .oauth2ResourceServer()\r\n            .jwt();\r\n}\r\n\r\n@Bean\r\nJwtDecoder jwtDecoder() {\r\n    return JwtDecoders.fromOidcIssuerLocation(this.issuerUri);\r\n}\r\n\r\n@Bean\r\nCorsConfigurationSource corsConfigurationSource() {\r\n    CorsConfiguration configuration = new CorsConfiguration();\r\n    configuration.setAllowCredentials(true);\r\n    configuration.setAllowedOrigins(Collections.singletonList(\"http:\/\/localhost:3000\"));\r\n    configuration.setAllowedMethods(Collections.singletonList(\"GET\"));\r\n    configuration.setAllowedHeaders(Collections.singletonList(\"*\"));\r\n    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();\r\n    source.registerCorsConfiguration(\"\/**\", configuration);\r\n    return source;\r\n}<\/pre>\n<p>After making these changes, restart your API and verify your React UI can talk to it. Pretty slick, eh?<\/p>\n<h3>User Information with Spring Security<\/h3>\n<p>Spring Security integrates with the Servlet API, so you can use the following methods to get the current user\u2019s information.<\/p>\n<ul>\n<li><code class=\"highlighter-rouge\" style=\"font-size: 13px;\">HttpServletRequest.getRemoteUser()<\/code><\/li>\n<li><code class=\"highlighter-rouge\" style=\"font-size: 13px;\">HttpServletRequest.getUserPrincipal()<\/code><\/li>\n<\/ul>\n<p>Once you have the\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">Principal<\/code>, you can get details about the user, including their roles (a.k.a., authorities).<\/p>\n<pre class=\"gutter: false;brush:xml; wrap-lines:false\">OAuth2Authentication authentication = (OAuth2Authentication) principal;\r\nMap&lt;String, Object&gt; user = (Map&lt;String, Object&gt;) authentication.getUserAuthentication().getDetails();<\/pre>\n<p>Please see\u00a0<a href=\"https:\/\/docs.spring.io\/spring-security\/site\/docs\/current\/reference\/htmlsingle\/#servletapi\">Spring Security\u2019s Servlet API integration documentation<\/a>\u00a0for more information.<\/p>\n<h2>Use Pac4j to Lock Down Your Java REST API<\/h2>\n<p>The last technique I\u2019d like to show you for securing your Java REST API is using Pac4j, specifically\u00a0<a href=\"https:\/\/github.com\/pac4j\/j2e-pac4j\">j2e-pac4j<\/a>.<\/p>\n<p>Revert your changes to add Spring Security.<\/p>\n<pre class=\"gutter: false;brush:bash\">git reset --hard HEAD<\/pre>\n<p>Edit\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">pom.xml<\/code>\u00a0to add the Pac4j libraries you\u2019ll need to complete this section.<\/p>\n<pre class=\"gutter: false;brush:xml\">&lt;properties&gt;\r\n    ...\r\n    &lt;pac4j-j2e.version&gt;4.0.0&lt;\/pac4j-j2e.version&gt;\r\n    &lt;pac4j.version&gt;3.0.0&lt;\/pac4j.version&gt;\r\n&lt;\/properties&gt;\r\n\r\n&lt;dependencies&gt;\r\n    ...\r\n    &lt;dependency&gt;\r\n        &lt;groupId&gt;org.pac4j&lt;\/groupId&gt;\r\n        &lt;artifactId&gt;j2e-pac4j&lt;\/artifactId&gt;\r\n        &lt;version&gt;${pac4j-j2e.version}&lt;\/version&gt;\r\n    &lt;\/dependency&gt;\r\n    &lt;dependency&gt;\r\n        &lt;groupId&gt;org.pac4j&lt;\/groupId&gt;\r\n        &lt;artifactId&gt;pac4j-oidc&lt;\/artifactId&gt;\r\n        &lt;version&gt;${pac4j.version}&lt;\/version&gt;\r\n    &lt;\/dependency&gt;\r\n    &lt;dependency&gt;\r\n        &lt;groupId&gt;org.pac4j&lt;\/groupId&gt;\r\n        &lt;artifactId&gt;pac4j-http&lt;\/artifactId&gt;\r\n        &lt;version&gt;${pac4j.version}&lt;\/version&gt;\r\n    &lt;\/dependency&gt;\r\n    &lt;dependency&gt;\r\n        &lt;groupId&gt;org.pac4j&lt;\/groupId&gt;\r\n        &lt;artifactId&gt;pac4j-jwt&lt;\/artifactId&gt;\r\n        &lt;version&gt;${pac4j.version}&lt;\/version&gt;\r\n    &lt;\/dependency&gt;\r\n&lt;\/dependencies&gt;<\/pre>\n<p>Create a\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">src\/main\/java\/com\/okta\/developer\/CorsFilter.java<\/code>\u00a0just like you did for JWT Verifier.<\/p>\n<pre class=\"gutter: false;brush:java; wrap-lines:false\">package com.okta.developer;\r\n\r\nimport javax.servlet.*;\r\nimport javax.servlet.annotation.WebFilter;\r\nimport javax.servlet.http.HttpServletRequest;\r\nimport javax.servlet.http.HttpServletResponse;\r\nimport java.io.IOException;\r\n\r\n@WebFilter(filterName = \"corsFilter\")\r\npublic class CorsFilter implements Filter {\r\n\r\n    @Override\r\n    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)\r\n            throws IOException, ServletException {\r\n        HttpServletRequest request = (HttpServletRequest) servletRequest;\r\n        HttpServletResponse response = (HttpServletResponse) servletResponse;\r\n        System.out.println(\"In CorsFilter, method: \" + request.getMethod());\r\n\r\n        \/\/ Authorize (allow) all domains to consume the content\r\n        response.addHeader(\"Access-Control-Allow-Origin\", \"http:\/\/localhost:3000\");\r\n        response.addHeader(\"Access-Control-Allow-Methods\", \"GET\");\r\n        response.addHeader(\"Access-Control-Allow-Headers\", \"*\");\r\n\r\n        \/\/ For HTTP OPTIONS verb\/method reply with ACCEPTED status code -- per CORS handshake\r\n        if (request.getMethod().equals(\"OPTIONS\")) {\r\n            response.setStatus(HttpServletResponse.SC_ACCEPTED);\r\n            return;\r\n        }\r\n\r\n        \/\/ pass the request along the filter chain\r\n        chain.doFilter(request, response);\r\n    }\r\n\r\n    @Override\r\n    public void init(FilterConfig config) {\r\n    }\r\n\r\n    @Override\r\n    public void destroy() {\r\n    }\r\n}<\/pre>\n<p>Create a\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">SecurityConfigFactory.java<\/code>\u00a0in the same package. Replace the client ID, secret, and domain placeholders with ones that match your OIDC app.<\/p>\n<pre class=\"gutter: false;brush:java; wrap-lines:false\">package com.okta.developer;\r\n\r\nimport com.fasterxml.jackson.databind.ObjectMapper;\r\nimport org.pac4j.core.client.Clients;\r\nimport org.pac4j.core.client.direct.AnonymousClient;\r\nimport org.pac4j.core.config.Config;\r\nimport org.pac4j.core.config.ConfigFactory;\r\nimport org.pac4j.core.credentials.TokenCredentials;\r\nimport org.pac4j.core.profile.CommonProfile;\r\nimport org.pac4j.http.client.direct.HeaderClient;\r\nimport org.pac4j.jwt.config.signature.RSASignatureConfiguration;\r\nimport org.pac4j.jwt.credentials.authenticator.JwtAuthenticator;\r\nimport org.pac4j.jwt.util.JWKHelper;\r\nimport org.pac4j.oidc.client.OidcClient;\r\nimport org.pac4j.oidc.config.OidcConfiguration;\r\nimport org.pac4j.oidc.profile.OidcProfile;\r\n\r\nimport java.io.IOException;\r\nimport java.net.URL;\r\nimport java.security.KeyPair;\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\nimport java.util.Map;\r\n\r\npublic class SecurityConfigFactory implements ConfigFactory {\r\n    private final JwtAuthenticator jwtAuthenticator = new JwtAuthenticator();\r\n    private final ObjectMapper mapper = new ObjectMapper();\r\n\r\n    @Override\r\n    public Config build(final Object... parameters) {\r\n        System.out.print(\"Building Security configuration...\\n\");\r\n\r\n        final OidcConfiguration oidcConfiguration = new OidcConfiguration();\r\n        oidcConfiguration.setClientId(\"{yourClientId}\");\r\n        oidcConfiguration.setSecret(\"{yourClientSecret}\");\r\n        oidcConfiguration.setDiscoveryURI(\"https:\/\/{yourOktaDomain}\/oauth2\/default\/.well-known\/openid-configuration\");\r\n        oidcConfiguration.setUseNonce(true);\r\n        final OidcClient&lt;OidcProfile, OidcConfiguration&gt; oidcClient = new OidcClient&lt;&gt;(oidcConfiguration);\r\n        oidcClient.setAuthorizationGenerator((ctx, profile) -&gt; {\r\n            profile.addRole(\"ROLE_USER\");\r\n            return profile;\r\n        });\r\n\r\n        HeaderClient headerClient = new HeaderClient(\"Authorization\", \"Bearer \", (credentials, ctx) -&gt; {\r\n            String token = ((TokenCredentials) credentials).getToken();\r\n            if (token != null) {\r\n                try {\r\n                    \/\/ Get JWK\r\n                    URL keysUrl = new URL(\"https:\/\/{yourOktaDomain}\/oauth2\/default\/v1\/keys\");\r\n                    Map map = mapper.readValue(keysUrl, Map.class);\r\n                    List keys = (ArrayList) map.get(\"keys\");\r\n                    String json = mapper.writeValueAsString(keys.get(0));\r\n\r\n                    \/\/ Build key pair and validate token\r\n                    KeyPair rsaKeyPair = JWKHelper.buildRSAKeyPairFromJwk(json);\r\n                    jwtAuthenticator.addSignatureConfiguration(new RSASignatureConfiguration(rsaKeyPair));\r\n                    CommonProfile profile = jwtAuthenticator.validateToken(token);\r\n                    credentials.setUserProfile(profile);\r\n                    System.out.println(\"Hello, \" + profile.getId());\r\n                } catch (IOException e) {\r\n                    System.err.println(\"Failed to validate Bearer token: \" + e.getMessage());\r\n                    e.printStackTrace();\r\n                }\r\n            }\r\n        });\r\n\r\n        final Clients clients = new Clients(\"http:\/\/localhost:8080\/callback\",\r\n                oidcClient, headerClient, new AnonymousClient());\r\n        return new Config(clients);\r\n    }\r\n}\r\n<\/pre>\n<p>The\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">oidcClient<\/code>\u00a0in the code above will make users log in to Okta if they try to directly access your API. The\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">headerClient<\/code>sets up a resource server that authorizes the user based on their access token.<\/p>\n<p>Create\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">src\/main\/webapp\/WEB-INF\/web.xml<\/code>\u00a0to map the\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">CorsFilter<\/code>, as well as Pac4j\u2019s\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">CallbackFilter<\/code>\u00a0and\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">SecurityFilter<\/code>. You can see the\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">SecurityFilter<\/code>\u00a0is linked to the\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">SecurityConfigFactory<\/code>\u00a0class with its\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">configFactory<\/code>\u00a0init-param.<\/p>\n<pre class=\"gutter: false;brush:xml; wrap-lines:false\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\r\n&lt;web-app xmlns=\"http:\/\/xmlns.jcp.org\/xml\/ns\/javaee\"\r\n         xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"\r\n         xsi:schemaLocation=\"http:\/\/xmlns.jcp.org\/xml\/ns\/javaee http:\/\/xmlns.jcp.org\/xml\/ns\/javaee\/web-app_3_1.xsd\"\r\n         version=\"3.1\"&gt;\r\n    &lt;display-name&gt;javaee-pac4j-demo&lt;\/display-name&gt;\r\n\r\n    &lt;absolute-ordering\/&gt;\r\n\r\n    &lt;filter-mapping&gt;\r\n        &lt;filter-name&gt;corsFilter&lt;\/filter-name&gt;\r\n        &lt;url-pattern&gt;\/*&lt;\/url-pattern&gt;\r\n    &lt;\/filter-mapping&gt;\r\n    &lt;filter&gt;\r\n        &lt;filter-name&gt;callbackFilter&lt;\/filter-name&gt;\r\n        &lt;filter-class&gt;org.pac4j.j2e.filter.CallbackFilter&lt;\/filter-class&gt;\r\n        &lt;init-param&gt;\r\n            &lt;param-name&gt;defaultUrl&lt;\/param-name&gt;\r\n            &lt;param-value&gt;\/&lt;\/param-value&gt;\r\n        &lt;\/init-param&gt;\r\n        &lt;init-param&gt;\r\n            &lt;param-name&gt;renewSession&lt;\/param-name&gt;\r\n            &lt;param-value&gt;true&lt;\/param-value&gt;\r\n        &lt;\/init-param&gt;\r\n        &lt;init-param&gt;\r\n            &lt;param-name&gt;multiProfile&lt;\/param-name&gt;\r\n            &lt;param-value&gt;true&lt;\/param-value&gt;\r\n        &lt;\/init-param&gt;\r\n    &lt;\/filter&gt;\r\n    &lt;filter-mapping&gt;\r\n        &lt;filter-name&gt;callbackFilter&lt;\/filter-name&gt;\r\n        &lt;url-pattern&gt;\/callback&lt;\/url-pattern&gt;\r\n        &lt;dispatcher&gt;REQUEST&lt;\/dispatcher&gt;\r\n    &lt;\/filter-mapping&gt;\r\n\r\n    &lt;filter&gt;\r\n        &lt;filter-name&gt;OidcFilter&lt;\/filter-name&gt;\r\n        &lt;filter-class&gt;org.pac4j.j2e.filter.SecurityFilter&lt;\/filter-class&gt;\r\n        &lt;init-param&gt;\r\n            &lt;param-name&gt;configFactory&lt;\/param-name&gt;\r\n            &lt;param-value&gt;com.okta.developer.SecurityConfigFactory&lt;\/param-value&gt;\r\n        &lt;\/init-param&gt;\r\n        &lt;init-param&gt;\r\n            &lt;param-name&gt;clients&lt;\/param-name&gt;\r\n            &lt;param-value&gt;oidcClient,headerClient&lt;\/param-value&gt;\r\n        &lt;\/init-param&gt;\r\n        &lt;init-param&gt;\r\n            &lt;param-name&gt;authorizers&lt;\/param-name&gt;\r\n            &lt;param-value&gt;securityHeaders&lt;\/param-value&gt;\r\n        &lt;\/init-param&gt;\r\n    &lt;\/filter&gt;\r\n    &lt;filter-mapping&gt;\r\n        &lt;filter-name&gt;OidcFilter&lt;\/filter-name&gt;\r\n        &lt;url-pattern&gt;\/*&lt;\/url-pattern&gt;\r\n        &lt;dispatcher&gt;REQUEST&lt;\/dispatcher&gt;\r\n        &lt;dispatcher&gt;FORWARD&lt;\/dispatcher&gt;\r\n    &lt;\/filter-mapping&gt;\r\n&lt;\/web-app&gt;<\/pre>\n<p>To visualize the user\u2019s information a bit better, you\u2019ll need to create a few more files. These JSF-related files are copied from\u00a0<a href=\"https:\/\/github.com\/pac4j\/j2e-pac4j-cdi-demo\">j2e-pac4j-cdi-demo<\/a>.<\/p>\n<p><strong>NOTE:<\/strong>\u00a0I tried to get\u00a0<a href=\"https:\/\/github.com\/pac4j\/j2e-pac4j-cdi-demo\">j2e-pac4j-cdi-demo<\/a>\u00a0(with no\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">web.xml<\/code>) running on TomEE, but it fails with an error:\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">Filters cannot be added to context [] as the context has been initialised<\/code>. It does work when using the\u00a0<a href=\"https:\/\/github.com\/pac4j\/j2e-pac4j-cdi-demo\/blob\/master\/pom.xml#L144\">Payara Maven plugins<\/a>.<\/p>\n<p>Create\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">src\/main\/java\/com\/okta\/developer\/ProfileView.java<\/code>, a JSF managed bean that gathers the user\u2019s information.<\/p>\n<pre class=\"gutter: false;brush:java; wrap-lines:false\">package com.okta.developer;\r\n\r\nimport org.pac4j.core.context.WebContext;\r\nimport org.pac4j.core.profile.ProfileManager;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\nimport javax.annotation.PostConstruct;\r\nimport javax.enterprise.context.RequestScoped;\r\nimport javax.inject.Inject;\r\nimport javax.inject.Named;\r\nimport java.util.List;\r\n\r\n\/**\r\n * Managed bean which exposes the pac4j profile manager.\r\n *\r\n * JSF views such as facelets can reference this to view the contents of profiles.\r\n *\r\n * @author Phillip Ross\r\n *\/\r\n@Named\r\n@RequestScoped\r\npublic class ProfileView {\r\n\r\n    \/** The static logger instance. *\/\r\n    private static final Logger logger = LoggerFactory.getLogger(ProfileView.class);\r\n\r\n    \/** The pac4j web context. *\/\r\n    @Inject\r\n    private WebContext webContext;\r\n\r\n    \/** The pac4j profile manager. *\/\r\n    @Inject\r\n    private ProfileManager profileManager;\r\n\r\n    \/** Simple no-args constructor. *\/\r\n    public ProfileView() {\r\n    }\r\n\r\n    \/**\r\n     * Gets the first profile (if it exists) contained in the profile manager.\r\n     *\r\n     * @return a list of pac4j profiles\r\n     *\/\r\n    public Object getProfile() {\r\n        return profileManager.get(true).orElse(null); \/\/ It's fine to return a null reference if there is no value present.\r\n    }\r\n\r\n    \/**\r\n     * Gets the profiles contained in the profile manager.\r\n     *\r\n     * @return a list of pac4j profiles\r\n     *\/\r\n    public List getProfiles() {\r\n        return profileManager.getAll(true);\r\n    }\r\n\r\n    \/** Simply prints some debugging information post-construction. *\/\r\n    @PostConstruct\r\n    public void init() {\r\n        logger.debug(\"webContext is null? {}\", (webContext == null));\r\n        logger.debug(\"profileManager is null? {}\", (profileManager == null));\r\n    }\r\n}<\/pre>\n<p>Add\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">src\/main\/webapp\/oidc\/index.xhtml<\/code>\u00a0as a JSF template.<\/p>\n<pre class=\"gutter: false;brush:xml\">&lt;ui:composition xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\"\r\n                xmlns:h=\"http:\/\/java.sun.com\/jsf\/html\"\r\n                xmlns:f=\"http:\/\/java.sun.com\/jsf\/core\"\r\n                xmlns:ui=\"http:\/\/java.sun.com\/jsf\/facelets\"\r\n                template=\"\/WEB-INF\/template.xhtml\"&gt;\r\n    &lt;ui:define name=\"title\"&gt;Pac4J Java EE Demo - Protected Area&lt;\/ui:define&gt;\r\n    &lt;ui:define name=\"content\"&gt;\r\n        &lt;div class=\"ui-g\"&gt;\r\n            &lt;div class=\"ui-g-12\"&gt;\r\n                &lt;div class=\"ui-container\"&gt;\r\n                    &lt;h1&gt;Protected Area&lt;\/h1&gt;\r\n                    &lt;p&gt;&lt;h:link value=\"Back\" outcome=\"\/index\"\/&gt;&lt;\/p&gt;\r\n                &lt;\/div&gt;\r\n                &lt;ui:include src=\"\/WEB-INF\/facelets\/includes\/pac4j-profiles-list.xhtml\"\/&gt;\r\n            &lt;\/div&gt;\r\n        &lt;\/div&gt;\r\n    &lt;\/ui:define&gt;\r\n&lt;\/ui:composition&gt;<\/pre>\n<p>Create the\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">pac4j-profiles-list.xhtml<\/code>\u00a0file it includes in\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">WEB-INF\/facelets\/includes<\/code>.<\/p>\n<pre class=\"gutter: false;brush:xml; wrap-lines:false\">&lt;ui:composition xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\"\r\n                xmlns:h=\"http:\/\/java.sun.com\/jsf\/html\"\r\n                xmlns:f=\"http:\/\/java.sun.com\/jsf\/core\"\r\n                xmlns:ui=\"http:\/\/java.sun.com\/jsf\/facelets\"&gt;\r\n    &lt;div class=\"ui-container\"&gt;\r\n        &lt;p&gt;Found  &lt;h:outputText value=\"#{profileView.profiles.size()}\"\/&gt; profiles.&lt;\/p&gt;\r\n        &lt;h:panelGroup layout=\"block\" rendered=\"#{profileView.profiles.size() &gt; 0}\"&gt;\r\n            &lt;p&gt;First profile:  &lt;h:outputText value=\"#{profileView.profile}\"\/&gt;&lt;\/p&gt;\r\n        &lt;\/h:panelGroup&gt;\r\n    &lt;\/div&gt;\r\n\r\n    &lt;h:panelGroup layout=\"block\" rendered=\"#{not empty profileView.profile}\"&gt;\r\n        &lt;h2&gt;Profile Details&lt;\/h2&gt;\r\n        &lt;p&gt;&lt;h:outputText value=\"Id: #{profileView.profile.id}\"\/&gt;&lt;\/p&gt;\r\n        &lt;p&gt;&lt;h:outputText value=\"Type Id: #{profileView.profile.typedId}\"\/&gt;&lt;\/p&gt;\r\n        &lt;p&gt;&lt;h:outputText value=\"Remembered: #{profileView.profile.remembered}\"\/&gt;&lt;\/p&gt;\r\n        &lt;h3&gt;Attributes (&lt;h:outputText value=\"#{profileView.profile.attributes.size()}\"\/&gt;)&lt;\/h3&gt;\r\n        &lt;h:panelGroup layout=\"block\" rendered=\"#{profileView.profile.attributes.size() &gt; 0}\"&gt;\r\n            &lt;ul&gt;\r\n                &lt;ui:repeat value=\"#{profileView.profile.attributes.keySet().toArray()}\" var=\"attributeName\"&gt;\r\n                    &lt;li&gt;&lt;h:outputText value=\"#{attributeName}\"\/&gt;: &lt;h:outputText value=\"#{profileView.profile.attributes.get(attributeName)}\"\/&gt; &lt;\/li&gt;\r\n                &lt;\/ui:repeat&gt;\r\n            &lt;\/ul&gt;\r\n        &lt;\/h:panelGroup&gt;\r\n        &lt;h3&gt;Roles (&lt;h:outputText value=\"#{profileView.profile.roles.size()}\"\/&gt;)&lt;\/h3&gt;\r\n        &lt;h:panelGroup layout=\"block\" rendered=\"#{profileView.profile.roles.size() &gt; 0}\"&gt;\r\n            &lt;ul&gt;\r\n                &lt;ui:repeat value=\"#{profileView.profile.roles.toArray()}\" var=\"role\"&gt;\r\n                    &lt;li&gt;&lt;h:outputText value=\"#{role}\"\/&gt;&lt;\/li&gt;\r\n                &lt;\/ui:repeat&gt;\r\n            &lt;\/ul&gt;\r\n        &lt;\/h:panelGroup&gt;\r\n        &lt;h3&gt;Permissions (&lt;h:outputText value=\"#{profileView.profile.permissions.size()}\"\/&gt;)&lt;\/h3&gt;\r\n        &lt;h:panelGroup layout=\"block\" rendered=\"#{profileView.profile.permissions.size() &gt; 0}\"&gt;\r\n            &lt;ul&gt;\r\n                &lt;ui:repeat value=\"#{profileView.profile.permissions.toArray()}\" var=\"permission\"&gt;\r\n                    &lt;li&gt;&lt;h:outputText value=\"#{permission}\"\/&gt;&lt;\/li&gt;\r\n                &lt;\/ui:repeat&gt;\r\n            &lt;\/ul&gt;\r\n        &lt;\/h:panelGroup&gt;\r\n    &lt;\/h:panelGroup&gt;\r\n&lt;\/ui:composition&gt;<\/pre>\n<p>The\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">oidc\/index.xhtml<\/code>\u00a0template uses\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">WEB-INF\/template.xhtml<\/code>, so you\u2019ll need to create that too.<\/p>\n<pre class=\"gutter: false;brush:xml; wrap-lines:false\">&lt;!DOCTYPE html&gt;\r\n&lt;html xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\"\r\n      xmlns:h=\"http:\/\/java.sun.com\/jsf\/html\"\r\n      xmlns:f=\"http:\/\/java.sun.com\/jsf\/core\"\r\n      xmlns:ui=\"http:\/\/java.sun.com\/jsf\/facelets\"&gt;\r\n\r\n    &lt;h:head&gt;\r\n        &lt;f:facet name=\"first\"&gt;\r\n            &lt;meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" \/&gt;\r\n            &lt;meta http-equiv=\"Content-Type\" content=\"text\/html; charset=UTF-8\" \/&gt;\r\n            &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0\"\/&gt;\r\n            &lt;meta name=\"apple-mobile-web-app-capable\" content=\"yes\" \/&gt;\r\n        &lt;\/f:facet&gt;\r\n        &lt;title&gt;&lt;ui:insert name=\"title\"&gt;Pac4J Java EE Demo&lt;\/ui:insert&gt;&lt;\/title&gt;\r\n        &lt;ui:insert name=\"head\"\/&gt;\r\n    &lt;\/h:head&gt;\r\n\r\n    &lt;h:body styleClass=\"main-body\"&gt;\r\n        &lt;div class=\"layout-wrapper\"&gt;\r\n            &lt;div class=\"layout-main\"&gt;\r\n                &lt;ui:insert name=\"content\"\/&gt;\r\n            &lt;\/div&gt;\r\n        &lt;\/div&gt;\r\n    &lt;\/h:body&gt;\r\n&lt;\/html&gt;<\/pre>\n<p>After adding these files, rebuild your project and restart TomEE.<\/p>\n<pre class=\"gutter: false;brush:bash\">mvn clean package tomee:run<\/pre>\n<p>Navigate to\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">http:\/\/localhost:8080\/oidc\/index.jsf<\/code>\u00a0and you\u2019ll be redirected to Okta to login. If it doesn\u2019t work on your first try, restart your browser and use an incognito window. You should see your user\u2019s profile information.<\/p>\n<p><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/pac4j-profile.png\"><img decoding=\"async\" class=\"aligncenter wp-image-82453\" style=\"border: none;\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/pac4j-profile-1024x656.png\" alt=\"Java REST API\" width=\"820\" height=\"525\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/pac4j-profile-1024x656.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/pac4j-profile-300x192.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/pac4j-profile-768x492.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/pac4j-profile.png 1600w\" sizes=\"(max-width: 820px) 100vw, 820px\" \/><\/a><\/p>\n<p>Try your React client at\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">http:\/\/localhost:3000<\/code>; it should work too!<\/p>\n<p><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/beer-list-horizontal.png\"><img decoding=\"async\" class=\"aligncenter wp-image-82454\" style=\"border: none;\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/beer-list-horizontal-1024x592.png\" alt=\"Java REST API\" width=\"820\" height=\"474\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/beer-list-horizontal-1024x592.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/beer-list-horizontal-300x173.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/beer-list-horizontal-768x444.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/beer-list-horizontal.png 1600w\" sizes=\"(max-width: 820px) 100vw, 820px\" \/><\/a><\/p>\n<p>If you\u2019re wondering why the images aren\u2019t stacked, it\u2019s because I changed the beer list\u2019s JSX in the React app\u2019s\u00a0<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">BeerList.tsx<\/code>to be inline.<\/p>\n<pre class=\"gutter: false;brush:xml\">&lt;h2&gt;Beer List&lt;\/h2&gt;\r\n{beers.map((beer: Beer) =&gt;\r\n  &lt;span key={beer.id} style={{float: 'left', marginRight: '10px', marginLeft: '10px'}}&gt;\r\n    {beer.name}&lt;br\/&gt;\r\n    &lt;GiphyImage name={beer.name}\/&gt;\r\n  &lt;\/span&gt;\r\n)}<\/pre>\n<h2>What About Jakarta EE?<\/h2>\n<p>You might\u2019ve heard that Java EE has become open source (much like\u00a0<a href=\"http:\/\/openjdk.java.net\/\">OpenJDK<\/a>\u00a0for Java SE) and its new name is\u00a0<a href=\"https:\/\/jakarta.ee\/\">Jakarta EE<\/a>. David Blevins is a good friend and heavily involved in Java EE \/ Jakarta EE. For proof, see his\u00a0<a href=\"https:\/\/twitter.com\/dblevins\">Twitter bio<\/a>: A founder of the Apache TomEE, OpenEJB and Geronimo projects. Member of Apache, JCP EC, EE4J PMC, Jakarta EE WG, MicroProfile, Eclipse Board. CEO\u00a0<a href=\"https:\/\/twitter.com\/Tomitribe\">@Tomitribe<\/a>.<\/p>\n<p>I asked David when there would be a usable release of Jakarta EE.<\/p>\n<blockquote>\n<p><strong>David:<\/strong>\u00a0The main focus right now is to create a version of Jakarta EE that is compatible with Java EE 8. We hope to have that out by the end of the year. After that\u2019s released, we\u2019ll start working on Jakarta EE 9 and iterating as needed.<\/p>\n<\/blockquote>\n<p>Jakarta EE has a\u00a0<a href=\"https:\/\/www.infoq.com\/news\/2018\/04\/jakarta-ee-working-group\">working group<\/a>\u00a0that decides the direction of the platform.<\/p>\n<h2>Learn More about Secure REST APIs, Java EE, Jakarta EE, and OIDC<\/h2>\n<p>I hope you\u2019ve enjoyed this tour that showed you how to build and secure a Java EE REST API with JWT and OIDC. If you\u2019d like to see the source code for each completed section, I\u2019ve put them in branches in the\u00a0<a href=\"https:\/\/github.com\/oktadeveloper\/okta-java-ee-rest-api-example\">GitHub repo<\/a>. You can clone the different implementations with the commands below:<\/p>\n<pre class=\"gutter: false;brush:bash\">git clone -b jwt-verifier https:\/\/github.com\/oktadeveloper\/okta-java-ee-rest-api-example.git\r\ngit clone -b spring-security https:\/\/github.com\/oktadeveloper\/okta-java-ee-rest-api-example.git\r\ngit clone -b pac4j https:\/\/github.com\/oktadeveloper\/okta-java-ee-rest-api-example.git<\/pre>\n<p>As I mentioned previously, most of the Java tutorials we have on this blog show how to use Spring Boot. In case you\u2019re interested in learning Spring Boot, here are some tutorials I\u2019ve written that will show you the gist of things.<\/p>\n<ul>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2017\/03\/21\/spring-boot-oauth?utm_source=java%20Code%20Geeks&amp;utm_medium=Content%20Syndication&amp;utm_campaign=secure%20java%20ee%20api\">Get Started with Spring Boot, OAuth 2.0, and Okta<\/a><\/li>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2018\/07\/19\/simple-crud-react-and-spring-boot?utm_source=java%20Code%20Geeks&amp;utm_medium=Content%20Syndication&amp;utm_campaign=secure%20java%20ee%20api\">Use React and Spring Boot to Build a Simple CRUD App<\/a><\/li>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2018\/08\/22\/basic-crud-angular-7-and-spring-boot-2?utm_source=java%20Code%20Geeks&amp;utm_medium=Content%20Syndication&amp;utm_campaign=secure%20java%20ee%20api\">Build a Basic CRUD App with Angular 7.0 and Spring Boot 2.1<\/a><\/li>\n<\/ul>\n<p>If you\u2019re new to OIDC, I\u2019d recommend you check out the following posts:<\/p>\n<ul>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2017\/12\/18\/spring-security-5-oidc?utm_source=java%20Code%20Geeks&amp;utm_medium=Content%20Syndication&amp;utm_campaign=secure%20java%20ee%20api\">Get Started with Spring Security 5.0 and OIDC<\/a><\/li>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2017\/07\/25\/oidc-primer-part-1?utm_source=java%20Code%20Geeks&amp;utm_medium=Content%20Syndication&amp;utm_campaign=secure%20java%20ee%20api\">Identity, Claims, &amp; Tokens \u2013 An OpenID Connect Primer, Part 1 of 3<\/a><\/li>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2017\/07\/25\/oidc-primer-part-2?utm_source=java%20Code%20Geeks&amp;utm_medium=Content%20Syndication&amp;utm_campaign=secure%20java%20ee%20api\">OIDC in Action \u2013 An OpenID Connect Primer, Part 2 of 3<\/a><\/li>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2017\/08\/01\/oidc-primer-part-3?utm_source=java%20Code%20Geeks&amp;utm_medium=Content%20Syndication&amp;utm_campaign=secure%20java%20ee%20api\">What\u2019s in a Token? \u2013 An OpenID Connect Primer, Part 3 of 3<\/a><\/li>\n<\/ul>\n<p>For more about Java REST APIs and TomEE, I recommend these sources:<\/p>\n<ul>\n<li><a href=\"https:\/\/www.youtube.com\/watch?v=XuhKdy7UIoY\">David Blevins \u2013 Deconstructing REST Security, Iterate 2018<\/a><\/li>\n<li><a href=\"https:\/\/antoniogoncalves.org\/2016\/10\/03\/securing-jax-rs-endpoints-with-jwt\/\">Antonio Goncalves \u2013 Securing JAX-RS Endpoints with JWT<\/a><\/li>\n<li><a href=\"https:\/\/www.tomitribe.com\/blog\/2018\/08\/tomee-running-with-systemd\/\">TomEE: Running with Systemd<\/a><\/li>\n<\/ul>\n<p>If you\u2019ve made it this far, I suspect you might be interested in seeing future blog posts.\u00a0<a href=\"https:\/\/twitter.com\/mraible\">Follow me<\/a>\u00a0and my\u00a0<a href=\"https:\/\/twitter.com\/oktadev\">whole team<\/a>\u00a0on Twitter, like us\u00a0<a href=\"https:\/\/www.facebook.com\/oktadevelopers\">on Facebook<\/a>, or check out\u00a0<a href=\"https:\/\/www.youtube.com\/channel\/UC5AMiWqFVFxF1q9Ya1FuZ_Q\">our YouTube channel<\/a>. For questions, please leave a comment below, or post it to our\u00a0<a href=\"https:\/\/devforum.okta.com\/\">Developer Forums<\/a>.<\/p>\n<p><span style=\"font-size: 20px;\"><b>\u201cI love writing authentication and authorization code.\u201d ~ No Java Developer Ever.<\/b> Tired of building the same login screens over and over? <a href=\"https:\/\/developer.okta.com\/signup?utm_source=java%20Code%20Geeks&#038;utm_medium=Content%20Syndication&#038;utm_campaign=secure%20java%20ee%20api\">Try the Okta API for hosted authentication, authorization, and multi-factor auth.<\/a><\/span><\/p>\n<p><a href=\"https:\/\/developer.okta.com\/blog\/2018\/09\/12\/secure-java-ee-rest-api\" target=\"_blank\" rel=\"noopener\" data-saferedirecturl=\"https:\/\/www.google.com\/url?q=https:\/\/developer.okta.com\/blog\/2018\/09\/12\/secure-java-ee-rest-api&amp;source=gmail&amp;ust=1538637087110000&amp;usg=AFQjCNEDVGIXDmGv_ax7syM_3QAQD9b_Hg\">Build a Java REST API with Java EE and OIDC&#8217;<\/a>\u00a0was originally published on the Okta developer blog on September 12, 2018.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u201cI love writing authentication and authorization code.\u201d ~ No Java Developer Ever. Tired of building the same login screens over and over? Try the Okta API for hosted authentication, authorization, and multi-factor auth. Java EE allows you to build Java REST API s quickly and easily with JAX-RS and JPA. Java EE is an umbrella &hellip;<\/p>\n","protected":false},"author":13127,"featured_media":112,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[1639,1594,54],"class_list":["post-82443","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-enterprise-java","tag-oidc","tag-okta","tag-restful-web-services"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Build a Java REST API with Java EE and OIDC - Java Code Geeks<\/title>\n<meta name=\"description\" content=\"Interested to learn about java rest API? Check our article explaining how to build a Java REST API using Java EE and OIDC\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/developer.okta.com\/blog\/2018\/09\/12\/secure-java-ee-rest-api\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Build a Java REST API with Java EE and OIDC - Java Code Geeks\" \/>\n<meta property=\"og:description\" content=\"Interested to learn about java rest API? Check our article explaining how to build a Java REST API using Java EE and OIDC\" \/>\n<meta property=\"og:url\" content=\"https:\/\/developer.okta.com\/blog\/2018\/09\/12\/secure-java-ee-rest-api\" \/>\n<meta property=\"og:site_name\" content=\"Java Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/javacodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2018-10-08T07:39:48+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2018-10-15T06:32:30+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/enterprise-java-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Matt Raible\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@mraible\" \/>\n<meta name=\"twitter:site\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Matt Raible\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"35 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2018\\\/09\\\/12\\\/secure-java-ee-rest-api#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/10\\\/build-java-rest-api-java-ee-oidc.html\"},\"author\":{\"name\":\"Matt Raible\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/54edd49deb980d7706e2af51514c3f7f\"},\"headline\":\"Build a Java REST API with Java EE and OIDC\",\"datePublished\":\"2018-10-08T07:39:48+00:00\",\"dateModified\":\"2018-10-15T06:32:30+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/10\\\/build-java-rest-api-java-ee-oidc.html\"},\"wordCount\":2596,\"commentCount\":1,\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2018\\\/09\\\/12\\\/secure-java-ee-rest-api#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/enterprise-java-logo.jpg\",\"keywords\":[\"OIDC\",\"Okta\",\"RESTful Web Services\"],\"articleSection\":[\"Enterprise Java\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2018\\\/09\\\/12\\\/secure-java-ee-rest-api#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/10\\\/build-java-rest-api-java-ee-oidc.html\",\"url\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2018\\\/09\\\/12\\\/secure-java-ee-rest-api\",\"name\":\"Build a Java REST API with Java EE and OIDC - Java Code Geeks\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2018\\\/09\\\/12\\\/secure-java-ee-rest-api#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2018\\\/09\\\/12\\\/secure-java-ee-rest-api#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/enterprise-java-logo.jpg\",\"datePublished\":\"2018-10-08T07:39:48+00:00\",\"dateModified\":\"2018-10-15T06:32:30+00:00\",\"description\":\"Interested to learn about java rest API? Check our article explaining how to build a Java REST API using Java EE and OIDC\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2018\\\/09\\\/12\\\/secure-java-ee-rest-api#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2018\\\/09\\\/12\\\/secure-java-ee-rest-api\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2018\\\/09\\\/12\\\/secure-java-ee-rest-api#primaryimage\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/enterprise-java-logo.jpg\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/enterprise-java-logo.jpg\",\"width\":150,\"height\":150,\"caption\":\"java-interview-questions-answers\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2018\\\/09\\\/12\\\/secure-java-ee-rest-api#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Enterprise Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\\\/enterprise-java\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Build a Java REST API with Java EE and OIDC\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"name\":\"Java Code Geeks\",\"description\":\"Java Developers Resource Center\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"alternateName\":\"JCG\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.javacodegeeks.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/javacodegeeks\",\"https:\\\/\\\/x.com\\\/javacodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/54edd49deb980d7706e2af51514c3f7f\",\"name\":\"Matt Raible\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/753d82443e50aed1ed2746573af191fe3e45c277ff3bd29873012a1b614355a7?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/753d82443e50aed1ed2746573af191fe3e45c277ff3bd29873012a1b614355a7?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/753d82443e50aed1ed2746573af191fe3e45c277ff3bd29873012a1b614355a7?s=96&d=mm&r=g\",\"caption\":\"Matt Raible\"},\"description\":\"Java Champion and Developer Advocate @okta with a passion for skiing, mtn biking, VWs, &amp; good beer.\",\"sameAs\":[\"https:\\\/\\\/developer.okta.com\",\"https:\\\/\\\/x.com\\\/mraible\"],\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/author\\\/matt-raible\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Build a Java REST API with Java EE and OIDC - Java Code Geeks","description":"Interested to learn about java rest API? Check our article explaining how to build a Java REST API using Java EE and OIDC","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/developer.okta.com\/blog\/2018\/09\/12\/secure-java-ee-rest-api","og_locale":"en_US","og_type":"article","og_title":"Build a Java REST API with Java EE and OIDC - Java Code Geeks","og_description":"Interested to learn about java rest API? Check our article explaining how to build a Java REST API using Java EE and OIDC","og_url":"https:\/\/developer.okta.com\/blog\/2018\/09\/12\/secure-java-ee-rest-api","og_site_name":"Java Code Geeks","article_publisher":"https:\/\/www.facebook.com\/javacodegeeks","article_published_time":"2018-10-08T07:39:48+00:00","article_modified_time":"2018-10-15T06:32:30+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/enterprise-java-logo.jpg","type":"image\/jpeg"}],"author":"Matt Raible","twitter_card":"summary_large_image","twitter_creator":"@mraible","twitter_site":"@javacodegeeks","twitter_misc":{"Written by":"Matt Raible","Est. reading time":"35 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/developer.okta.com\/blog\/2018\/09\/12\/secure-java-ee-rest-api#article","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/2018\/10\/build-java-rest-api-java-ee-oidc.html"},"author":{"name":"Matt Raible","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/54edd49deb980d7706e2af51514c3f7f"},"headline":"Build a Java REST API with Java EE and OIDC","datePublished":"2018-10-08T07:39:48+00:00","dateModified":"2018-10-15T06:32:30+00:00","mainEntityOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2018\/10\/build-java-rest-api-java-ee-oidc.html"},"wordCount":2596,"commentCount":1,"publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"image":{"@id":"https:\/\/developer.okta.com\/blog\/2018\/09\/12\/secure-java-ee-rest-api#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/enterprise-java-logo.jpg","keywords":["OIDC","Okta","RESTful Web Services"],"articleSection":["Enterprise Java"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/developer.okta.com\/blog\/2018\/09\/12\/secure-java-ee-rest-api#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.javacodegeeks.com\/2018\/10\/build-java-rest-api-java-ee-oidc.html","url":"https:\/\/developer.okta.com\/blog\/2018\/09\/12\/secure-java-ee-rest-api","name":"Build a Java REST API with Java EE and OIDC - Java Code Geeks","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/developer.okta.com\/blog\/2018\/09\/12\/secure-java-ee-rest-api#primaryimage"},"image":{"@id":"https:\/\/developer.okta.com\/blog\/2018\/09\/12\/secure-java-ee-rest-api#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/enterprise-java-logo.jpg","datePublished":"2018-10-08T07:39:48+00:00","dateModified":"2018-10-15T06:32:30+00:00","description":"Interested to learn about java rest API? Check our article explaining how to build a Java REST API using Java EE and OIDC","breadcrumb":{"@id":"https:\/\/developer.okta.com\/blog\/2018\/09\/12\/secure-java-ee-rest-api#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/developer.okta.com\/blog\/2018\/09\/12\/secure-java-ee-rest-api"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/developer.okta.com\/blog\/2018\/09\/12\/secure-java-ee-rest-api#primaryimage","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/enterprise-java-logo.jpg","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/enterprise-java-logo.jpg","width":150,"height":150,"caption":"java-interview-questions-answers"},{"@type":"BreadcrumbList","@id":"https:\/\/developer.okta.com\/blog\/2018\/09\/12\/secure-java-ee-rest-api#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.javacodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Java","item":"https:\/\/www.javacodegeeks.com\/category\/java"},{"@type":"ListItem","position":3,"name":"Enterprise Java","item":"https:\/\/www.javacodegeeks.com\/category\/java\/enterprise-java"},{"@type":"ListItem","position":4,"name":"Build a Java REST API with Java EE and OIDC"}]},{"@type":"WebSite","@id":"https:\/\/www.javacodegeeks.com\/#website","url":"https:\/\/www.javacodegeeks.com\/","name":"Java Code Geeks","description":"Java Developers Resource Center","publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"alternateName":"JCG","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.javacodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.javacodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.javacodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/javacodegeeks","https:\/\/x.com\/javacodegeeks"]},{"@type":"Person","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/54edd49deb980d7706e2af51514c3f7f","name":"Matt Raible","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/753d82443e50aed1ed2746573af191fe3e45c277ff3bd29873012a1b614355a7?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/753d82443e50aed1ed2746573af191fe3e45c277ff3bd29873012a1b614355a7?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/753d82443e50aed1ed2746573af191fe3e45c277ff3bd29873012a1b614355a7?s=96&d=mm&r=g","caption":"Matt Raible"},"description":"Java Champion and Developer Advocate @okta with a passion for skiing, mtn biking, VWs, &amp; good beer.","sameAs":["https:\/\/developer.okta.com","https:\/\/x.com\/mraible"],"url":"https:\/\/www.javacodegeeks.com\/author\/matt-raible"}]}},"_links":{"self":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/82443","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/users\/13127"}],"replies":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/comments?post=82443"}],"version-history":[{"count":0,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/82443\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media\/112"}],"wp:attachment":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media?parent=82443"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/categories?post=82443"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/tags?post=82443"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}