{"id":84685,"date":"2018-12-20T08:35:38","date_gmt":"2018-12-20T06:35:38","guid":{"rendered":"http:\/\/www.javacodegeeks.com\/?p=84685"},"modified":"2018-12-28T09:29:33","modified_gmt":"2018-12-28T07:29:33","slug":"build-basic-spring-boot-using-postgresql","status":"publish","type":"post","link":"https:\/\/www.javacodegeeks.com\/2018\/12\/build-basic-spring-boot-using-postgresql.html","title":{"rendered":"Build a Basic App with Spring Boot and JPA using PostgreSQL"},"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_campaign=text_website_all_multiple_dev_ciam_build-basic-app-spring-boot-jpa_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Try the Okta API for hosted authentication, authorization, and multi-factor auth.<\/a><\/span><\/p>\n<p>Every non-trivial application needs a way to save and update data: a resource server that is accessible via HTTP. Generally, this data must be secured. Java is a great language with decades of history in professional, enterprise development, and is a great choice for any application\u2019s server stack. Within the Java ecosystem, Spring makes building secure resource servers for your data simple. When coupled with Okta, you get professionally maintained OAuth and JWT technologies easily integrated into Spring Boot using Spring Security.<\/p>\n<p>In this post, you\u2019re going to build a resource server using Spring Boot and Spring Data JPA. On top of that, you\u2019re going to implement a group-based authentication and authorization layer using OAuth 2.0. If this sounds complicated &#8211; don\u2019t worry! It\u2019s not.<\/p>\n<p>Before we dig in, let\u2019s cover some background:<\/p>\n<p>A<strong>resource server<\/strong>&nbsp;is a programmatic access point for your server\u2019s functions and data (basically the same as an API server and\/or possibly REST server).<\/p>\n<p><strong>JPA<\/strong>&nbsp;is the Java Persistence API, a specification for managing relational databases using Java. It describes an abstraction layer between Java classes and a relational database.<\/p>\n<p><a href=\"https:\/\/spring.io\/projects\/spring-data-jpa\"><strong>Spring Data JPA<\/strong><\/a>&nbsp;is a wrapper around JPA providers such as Hibernate. As you\u2019ll see, it makes persisting your Java classes as simple as adding some annotations and creating a simple repository interface. No need to actually write persistence or retrieval methods! Another great benefit is that you can change the underlying database implementation transparently without having to change any code. For example, in this tutorial, you\u2019ll be using Postgres, but later if you decided you\u2019d rather use MySQL, all you\u2019d have to do is change out some dependencies.<\/p>\n<h2 class=\"wp-block-heading\" id=\"install-postgresql-for-jpa-persistence\">Install PostgreSQL for JPA Persistence<\/h2>\n<p>You\u2019ll need to have PostgreSQL installed for this tutorial. If you don\u2019t already have it installed, go to&nbsp;<a href=\"https:\/\/www.postgresql.org\/download\/\">their downloads page<\/a>&nbsp;and install it.<\/p>\n<p>The next thing you\u2019ll need to do is create a Postgres user and database for the project. For this, you can use the Postgres CLI.<br \/>\nYou should be able to run the following command: <code>psql -V<\/code> and get a response like:<\/p>\n<pre class=\"gutter: false;brush:bash\">psql (PostgreSQL) 11.12<\/pre>\n<h2 id=\"create-a-postgresql-database-for-your-jpa-entities\">Create a PostgreSQL Database for Your JPA Entities<\/h2>\n<p>Before you can use your database, you need to do a few things. You need to:<\/p>\n<ol>\n<li>Create a user for the app<\/li>\n<li>Set a password for that user<\/li>\n<li>Create a database for the app<\/li>\n<li>Grant privileges on the database for the user<\/li>\n<\/ol>\n<p>This tutorial uses&nbsp;<em>jpatutorial<\/em>&nbsp;for the username and&nbsp;<em>springbootjpa<\/em>&nbsp;for the database name. Feel free to change these if you like, but you\u2019ll have to remember to use your custom values throughout the tutorial.<\/p>\n<p>Type&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">psql<\/code>&nbsp;from the terminal to enter the Postgres shell. Then enter the following command.<\/p>\n<h3 id=\"create-a-user\">Create a user<\/h3>\n<pre class=\"gutter: false;brush:bash\">create user jpatutorial;<\/pre>\n<p>The shell should respond with:&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">CREATE ROLE<\/code><\/p>\n<p><strong>Don\u2019t forget the semicolon!<\/strong>&nbsp;I would never, ever do this. I am definitely not speaking from experience. But if you don\u2019t type in the semicolon&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">psql<\/code>&nbsp;doesn\u2019t process the command and you can lose 20-30 minutes in frustrated confusion wondering what is happening until you&nbsp;<em>do<\/em>&nbsp;enter a semicolon, at which point it tries to process all of your commands.<\/p>\n<h3 id=\"give-the-user-a-password\">Give the user a password<\/h3>\n<pre class=\"gutter: false;brush:bash\">alter user jpatutorial with encrypted password '&lt;your really secure password&gt;';<\/pre>\n<p>The shell should respond with:&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">ALTER ROLE<\/code>.<\/p>\n<h3 id=\"create-the-database\">Create the database<\/h3>\n<pre class=\"gutter: false;brush:bash\">create database springbootjpa;<\/pre>\n<p>The shell should respond with:&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">CREATE DATABASE<\/code>.<\/p>\n<h3 id=\"grant-privileges\">Grant privileges<\/h3>\n<pre class=\"gutter: false;brush:bash\">grant all privileges on database springbootjpa to jpatutorial;<\/pre>\n<p>The shell should respond with&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">GRANT<\/code>.<\/p>\n<p>Finally, type&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">\\q<\/code>&nbsp;to quit the shell, if you want.<\/p>\n<p>If you want to read more about&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">psql<\/code>&nbsp;you can take a look at&nbsp;<a href=\"https:\/\/www.postgresql.org\/docs\/9.2\/app-psql.html\">Postgres\u2019 docs<\/a>.<\/p>\n<h2 id=\"build-a-spring-boot-resource-server\">Build a Spring Boot Resource Server<\/h2>\n<p>Clone the starter project from the GitHub repository and check out the&nbsp;<strong>start<\/strong>&nbsp;branch:<\/p>\n<pre class=\"gutter: false;brush:bash\">git clone -b start https:\/\/github.com\/oktadeveloper\/okta-spring-boot-jpa-example.git<\/pre>\n<p>The starter project is a clean slate Spring Boot project with just a little bit of Postgres-specific configuration already in place. If you look in the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">build.gradle<\/code>&nbsp;file you\u2019ll see a PostgreSQL JPA connector dependency. You\u2019ll also notice the file&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">src\/main\/resources\/hibernate.properties<\/code>&nbsp;whose sole purpose is to get rid of an annoying warning\/error that doesn\u2019t really matter to us. The&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">src\/main\/resources\/application.yml<\/code>&nbsp;file also has some properties pre-filled for you.<\/p>\n<p>Go ahead and open the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">application.yml<\/code>&nbsp;file and fill in the password you created for your database user. You should also update the username, database name, and port (if they are different).<\/p>\n<pre class=\"gutter: false;brush:js\">spring:  \n  jpa:  \n    hibernate:  \n      ddl-auto: create  \n    database-platform: org.hibernate.dialect.PostgreSQLDialect  \n  datasource:  \n    url: \"jdbc:postgresql:\/\/localhost:5432\/springbootjpa\"  \n    username: jpatutorial  \n    password: &lt; your password &gt;\n<\/pre>\n<p>The&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">ddl-auto<\/code>&nbsp;property specifies hibernate\u2019s behavior upon loading. The options are:<\/p>\n<ul>\n<li>validate:&nbsp;<em>validates the schema but makes no changes<\/em><\/li>\n<li>update:&nbsp;<em>updates the schema<\/em><\/li>\n<li>create:&nbsp;<em>creates the schema, destroying any previous data<\/em><\/li>\n<li>create-drop:&nbsp;<em>like create, but also drops the schema when the session closes (useful for testing)<\/em><\/li>\n<\/ul>\n<p>You\u2019re using&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">create<\/code>. Each time the program is run, a new database is created, starting with fresh tables and data.<\/p>\n<p><code class=\"highlighter-rouge\" style=\"font-size: 13px;\">database-platform<\/code>&nbsp;is actually unnecessary. Spring Data\/Hibernate can autodetect the platform. However, without this property, if you run the app without having started your Postgres server, what you\u2019ll get is a rather unhelpful error about not having added this config property instead of being told to start your server. This happens because Hibernate cannot autodetect the database platform, so complains about that before complaining about there not actually being a running server.<\/p>\n<p>Run the app with&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">.\/gradlew bootRun<\/code>. You should see something like this:<\/p>\n<pre class=\"gutter: false;brush:bash; wrap-lines:false\">2018-11-21 09:27:50.233  INFO 31888 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Located MBean 'dataSource': registering with JMX server as MBean [com.zaxxer.hikari:name=dataSource,type=HikariDataSource]\n2018-11-21 09:27:50.302  INFO 31888 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''\n2018-11-21 09:27:50.308  INFO 31888 --- [           main] c.o.s.SpringBootJpaApplication           : Started SpringBootJpaApplication in 21.361 seconds (JVM running for 21.848)\n&lt;=========----&gt; 75% EXECUTING [4m 26s]\n&gt; :bootRun\n<\/pre>\n<p>It doesn\u2019t do much just yet, though. There are no domain models, resource repositories, or controller classes.<\/p>\n<h2 id=\"add-a-domain-class-with-spring-data-and-jpa\">Add a Domain Class with Spring Data and JPA<\/h2>\n<p>A domain or model is the programmatic representation of the data you will be storing. The magic of Spring Data and JPA is that Spring can take a Java class and turn it into a database table for you. It will even autogenerate the necessary load and save methods. The best part is that this is (more or less) database independent.<\/p>\n<p>You\u2019re using PostgreSQL in this tutorial, and you could pretty easily switch it to MySQL if you wanted, just by changing a dependency in the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">build.gradle<\/code>&nbsp;file. And, of course, creating a MySQL database and updating the necessary properties in the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">application.yml<\/code>&nbsp;file. This is super useful for testing, development, and long-term maintenance.<\/p>\n<p>Keep reading to learn how to develop a simple server to store types of kayaks.<\/p>\n<p>Create a Java file in the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">com.okta.springbootjpa<\/code>&nbsp;package called&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">Kayak.java<\/code>. Your kayak model will have a name, an owner, a value, and a make\/model.<\/p>\n<pre class=\"gutter: false;brush:java\">package com.okta.springbootjpa;\n\nimport lombok.Data;\n\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.GenerationType;\nimport javax.persistence.Id;\n\n@Entity \/\/ This tells Hibernate to make a table out of this class\n@Data \/\/ Lombok: adds getters and setters\npublic class Kayak {\n\n    public Kayak(String name, String owner, Number value, String makeModel) {\n        this.name = name;\n        this.owner = owner;\n        this.value = value;\n        this.makeModel = makeModel;\n    }\n\n    @Id\n    @GeneratedValue(strategy=GenerationType.AUTO)\n    private Integer id;\n\n    private final String name;\n\n    private String owner;\n\n    private Number value;\n\n    private String makeModel;\n}\n<\/pre>\n<p>This project uses&nbsp;<strong>Lombok<\/strong>&nbsp;to avoid having to code a bunch of ceremony getters and setters and whatnots. You can check out&nbsp;<a href=\"https:\/\/projectlombok.org\/\">their docs<\/a>, or more specifically for&nbsp;<a href=\"https:\/\/projectlombok.org\/features\/Data\">the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">@Data<\/code>&nbsp;annotation you\u2019re using<\/a>.<\/p>\n<p>The&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">@Entity<\/code>&nbsp;annotation is what tells Spring that this class is a model class and should be transformed into a database table.<\/p>\n<p>Most properties can be mapped automatically. The<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">id<\/code>&nbsp;property, however, is decorated with a couple annotations because we need to tell JPA that this is the ID field and that it should be auto-generated.<\/p>\n<h2 id=\"implement-a-crud-repository-with-spring-data-jpa\">Implement a CRUD Repository with Spring Data JPA<\/h2>\n<p>With the domain class defined, Spring knows enough to build the database table, but it doesn\u2019t have any controller methods defined. There\u2019s no output or input for the data. Spring makes adding a resource server trivial. In fact, it\u2019s so trivial, you probably won\u2019t believe it.<\/p>\n<p>In the package&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">com.okta.springbootjpa<\/code>, create an interface called&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">KayakRepository.java<\/code>.<\/p>\n<pre class=\"gutter: false;brush:java\">package com.okta.springbootjpa;\n\nimport org.springframework.data.repository.CrudRepository;\nimport org.springframework.data.rest.core.annotation.RepositoryRestResource;\n\n@RepositoryRestResource\npublic interface KayakRepository extends CrudRepository&lt;Kayak, Integer&gt; {\n}\n<\/pre>\n<p>That\u2019s it!<br \/>You can now create, read, update, and delete kayaks from the resource server. In just a sec you\u2019re going to do exactly that, but before you do, make one more change.<br \/>Add the following&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">init()<\/code>&nbsp;method to the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">SpringBootJpaApplication<\/code>&nbsp;class:<\/p>\n<pre class=\"gutter: false;brush:java\">package com.okta.springbootjpa;\n\nimport org.springframework.boot.ApplicationRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\n\nimport java.text.NumberFormat;\nimport java.text.ParseException;\nimport java.util.stream.Stream;\n\n@SpringBootApplication\npublic class SpringBootJpaApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootJpaApplication.class, args);\n    }\n\n  @Bean\n  ApplicationRunner init(KayakRepository repository) {\n\n    String[][] data = {\n        {\"sea\", \"Andrew\", \"300.12\", \"NDK\"},\n        {\"creek\", \"Andrew\", \"100.75\", \"Piranha\"},\n        {\"loaner\", \"Andrew\", \"75\", \"Necky\"}\n    };\n\n    return args -&gt; {\n      Stream.of(data).forEach(array -&gt; {\n        try {\n          Kayak kayak = new Kayak(\n              array[0],\n              array[1],\n                  NumberFormat.getInstance().parse(array[2]),\n              array[3]\n          );\n          repository.save(kayak);\n        }\n        catch (ParseException e) {\n          e.printStackTrace();\n        }\n      });\n      repository.findAll().forEach(System.out::println);\n    };\n  }\n  \n}\n<\/pre>\n<p>This method will be run when the application starts. It loads some sample data into the resource server just to give you something to look at in the next section.<div style=\"display:inline-block; margin: 15px 0;\"> <div id=\"adngin-JavaCodeGeeks_incontent_video-0\" style=\"display:inline-block;\"><\/div> <\/div><\/p>\n<h2 id=\"test-your-spring-boot-resource-server\">Test Your Spring Boot Resource Server<\/h2>\n<p>HTTPie is a great command line utility that makes it easy to run requests against the resource server. If you don\u2019t have HTTPie installed, install it using&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">brew install httpie<\/code>. Or head over to&nbsp;<a href=\"https:\/\/httpie.org\/\">their website<\/a>&nbsp;and make it happen. Or just follow along.<\/p>\n<p>Make sure your Spring Boot app is running. If it isn\u2019t, start it using&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">.\/gradlew bootRun<\/code>.<\/p>\n<p>Run a GET request against your resource server:&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">http :8080\/kayaks<\/code>, which is shorthand for&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">http GET http:\/\/localhost:8080\/kayaks<\/code>.<\/p>\n<p>You\u2019ll see this:<\/p>\n<pre class=\"gutter: false;brush:js\">HTTP\/1.1 200\nContent-Type: application\/hal+json;charset=UTF-8\nDate: Wed, 21 Nov 2018 20:39:11 GMT\nTransfer-Encoding: chunked\n\n{\n    \"_embedded\": {\n        \"kayaks\": [\n            {\n                \"_links\": {\n                    \"kayak\": {\n                        \"href\": \"http:\/\/localhost:8080\/kayaks\/1\"\n                    },\n                    \"self\": {\n                        \"href\": \"http:\/\/localhost:8080\/kayaks\/1\"\n                    }\n                },\n                \"makeModel\": \"NDK\",\n                \"name\": \"sea\",\n                \"owner\": \"Andrew\",\n                \"value\": 300.12\n            },\n            {\n                \"_links\": {\n                    \"kayak\": {\n                        \"href\": \"http:\/\/localhost:8080\/kayaks\/2\"\n                    },\n                    \"self\": {\n                        \"href\": \"http:\/\/localhost:8080\/kayaks\/2\"\n                    }\n                },\n                \"makeModel\": \"Piranha\",\n                \"name\": \"creek\",\n                \"owner\": \"Andrew\",\n                \"value\": 100.75\n            },\n            {\n                \"_links\": {\n                    \"kayak\": {\n                        \"href\": \"http:\/\/localhost:8080\/kayaks\/3\"\n                    },\n                    \"self\": {\n                        \"href\": \"http:\/\/localhost:8080\/kayaks\/3\"\n                    }\n                },\n                \"makeModel\": \"Necky\",\n                \"name\": \"loaner\",\n                \"owner\": \"Andrew\",\n                \"value\": 75\n            }\n        ]\n    },\n    \"_links\": {\n        \"profile\": {\n            \"href\": \"http:\/\/localhost:8080\/profile\/kayaks\"\n        },\n        \"self\": {\n            \"href\": \"http:\/\/localhost:8080\/kayaks\"\n        }\n    }\n}\n<\/pre>\n<p>This output gives you a pretty solid idea of the format of data that the Spring Boot resource returns. You can also add a new kayak using a POST.<\/p>\n<p>Command:<\/p>\n<pre class=\"gutter: false;brush:bash\">http POST :8080\/kayaks name=\"sea2\" owner=\"Andrew\" value=\"500\" makeModel=\"P&amp;H\"<\/pre>\n<p>Reply:<\/p>\n<pre class=\"gutter: false;brush:js\">HTTP\/1.1 201\nContent-Type: application\/json;charset=UTF-8\nDate: Wed, 21 Nov 2018 20:42:14 GMT\nLocation: http:\/\/localhost:8080\/kayaks\/4\nTransfer-Encoding: chunked\n\n{\n    \"_links\": {\n        \"kayak\": {\n            \"href\": \"http:\/\/localhost:8080\/kayaks\/4\"\n        },\n        \"self\": {\n            \"href\": \"http:\/\/localhost:8080\/kayaks\/4\"\n        }\n    },\n    \"makeModel\": \"P&amp;H\",\n    \"name\": \"sea2\",\n    \"owner\": \"Andrew\",\n    \"value\": 500\n}\n<\/pre>\n<p>If you list the kayaks again (<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">http :8080\/kayaks<\/code>) you\u2019ll see the new kayak among the listed items.<\/p>\n<pre class=\"gutter: false;brush:js\">HTTP\/1.1 200\nContent-Type: application\/hal+json;charset=UTF-8\nDate: Wed, 21 Nov 2018 20:44:22 GMT\nTransfer-Encoding: chunked\n\n{\n    \"_embedded\": {\n        \"kayaks\": [\n            ...\n            {\n                \"_links\": {\n                    \"kayak\": {\n                        \"href\": \"http:\/\/localhost:8080\/kayaks\/4\"\n                    },\n                    \"self\": {\n                        \"href\": \"http:\/\/localhost:8080\/kayaks\/4\"\n                    }\n                },\n                \"makeModel\": \"P&amp;H\",\n                \"name\": \"sea2\",\n                \"owner\": \"Andrew\",\n                \"value\": 500\n            }\n        ]\n    },\n    ...\n}\n<\/pre>\n<p>You can also delete the kayak. Run this command:&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">http DELETE :8080\/kayaks\/4<\/code>&nbsp;This deletes the kayak with ID = 4, or the kayak we just created. GET the list of kayaks a third time and you\u2019ll see that it\u2019s gone.<\/p>\n<p>With very minimal code, using Spring Boot you can create a fully functioning resource server. This data is being persisted to your Postgres database.<\/p>\n<p>You can verify this by using the Postgres command shell. At the terminal, type&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">psql<\/code>&nbsp;to enter the shell, then type the following commands.<\/p>\n<p>Connect to the database:<\/p>\n<pre class=\"gutter: false;brush:bash\">\\connect springbootjpa<\/pre>\n<pre class=\"gutter: false;brush:bash\">psql (9.6.2, server 9.6.6)\nYou are now connected to database \"springbootjpa\" as user \"cantgetnosleep\".<\/pre>\n<p>Show the table contents:<\/p>\n<pre class=\"gutter: false;brush:sql\">SELECT * FROM kayak;<\/pre>\n<pre class=\"gutter: false;brush:bash; wrap-lines:false\">id | make_model |  name  | owner  |                                                                                   value\n----+------------+--------+--------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n  1 | NDK        | sea    | Andrew | \\xaced0005737200106a6176612e6c616e67...8704072c1eb851eb852\n  2 | Piranha    | creek  | Andrew | \\xaced0005737200106a6176612e6c616e672e...078704059300000000000\n  3 | Necky      | loaner | Andrew | \\xaced00057372000e6a6176612e6c616e67...7870000000000000004b\n  5 | P&amp;H        | sea2   | Andrew | \\xaced0005737200116a6176612e6...08b0200007870000001f4\n(4 rows)\n<\/pre>\n<p>A couple things to note. First, notice that&nbsp;<em>value<\/em>&nbsp;is being stored as a binary object because it was defined as a&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">Number<\/code>&nbsp;type instead of a primitive (double, float, or int). Second, remember that this data is being erased and the entire table is being recreated on every boot of the app because of the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">ddl-auto: create<\/code>&nbsp;line in the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">application.yml<\/code>&nbsp;file.<\/p>\n<h2 id=\"set-up-authentication\">Set Up Authentication<\/h2>\n<p>Okta is a software-as-service identity, authentication, and authorization provider. While I have definitely worked on projects where outsourcing everything to SaaS providers created more problems than it promised to solve, authentication and authorization is a place where this model makes total sense. Online security is hard. Vulnerabilities are found and servers must be updated quickly. Standards change and code needs modification. All of these changes have the potential to create new vulnerabilities. Letting Okta handle security means that you can worry about the things that make your application unique.<\/p>\n<p>To show you how easy it is to set up, you\u2019re going integrate Okta OAuth and add token-based authentication to the resource server. If you haven\u2019t already, head over to&nbsp;<a href=\"http:\/\/developer.okta.com\/?utm_campaign=text_website_all_multiple_dev_ciam_build-basic-app-spring-boot-jpa_null&amp;utm_source=jcg&amp;utm_medium=cpc\">developer.okta.com<\/a>&nbsp;and sign up for a free account. Once you have an account, open the developer dashboard and create an OpenID Connect (OIDC) application by clicking on the&nbsp;<strong>Application<\/strong>&nbsp;top-menu item, and then on the&nbsp;<strong>Add Application<\/strong>&nbsp;button.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" width=\"984\" height=\"645\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/12\/create-app.png\" alt=\"Spring Boot and JPA\" class=\"wp-image-84687\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/12\/create-app.png 984w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/12\/create-app-300x197.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/12\/create-app-768x503.png 768w\" sizes=\"(max-width: 984px) 100vw, 984px\" \/><\/figure>\n<\/div>\n<p>Select&nbsp;<strong>Single-Page App<\/strong>.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" width=\"694\" height=\"740\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/12\/app-settings.png\" alt=\"Spring Boot and JPA\" class=\"wp-image-84688\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/12\/app-settings.png 694w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/12\/app-settings-281x300.png 281w\" sizes=\"(max-width: 694px) 100vw, 694px\" \/><\/figure>\n<\/div>\n<p>The default application settings are great, except that you need to add a&nbsp;<strong>Login Redirect URI<\/strong>:&nbsp;<code>a<\/code>. You\u2019re going to use this in a moment to retrieve a test token.<\/p>\n<p>Also, note your&nbsp;<strong>Client ID<\/strong>, as you\u2019ll need that in a moment.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" width=\"822\" height=\"1024\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/12\/general-settings-822x1024.png\" alt=\"Spring Boot and JPA\" class=\"wp-image-84689\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/12\/general-settings-822x1024.png 822w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/12\/general-settings-241x300.png 241w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/12\/general-settings-768x957.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/12\/general-settings.png 1318w\" sizes=\"(max-width: 822px) 100vw, 822px\" \/><\/figure>\n<\/div>\n<h2 class=\"wp-block-heading\" id=\"configure-your-spring-boot-resource-server-for-token-authentication\">Configure Your Spring Boot Resource Server for Token Authentication<\/h2>\n<p>Okta has made adding token authentication to Spring Boot super easy. They have a project called Okta Spring Boot Starter (<a href=\"https:\/\/github.com\/okta\/okta-spring-boot\">check out the GitHub project<\/a>) that simplifies the whole process to a few simple steps.<\/p>\n<p>Add a couple dependencies to your&nbsp;<code>build.gradle<\/code>&nbsp;file.<\/p>\n<pre class=\"gutter: false;brush:bash; wrap-lines:false\">compile('org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:2.1.0.RELEASE')  \ncompile('com.okta.spring:okta-spring-boot-starter:0.6.1')\n<\/pre>\n<p>Add the following to the bottom of the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">build.gradle<\/code>&nbsp;file (this resolves a logback logging dependency conflict).<\/p>\n<pre class=\"gutter: false;brush:bash\">configurations.all {  \n  exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'  \n  exclude group: 'org.springframework.boot', module: 'logback-classic'  \n}\n<\/pre>\n<p>Next, you need to add some configuration to your&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">application.yml<\/code>&nbsp;file, replacing&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">{yourClientId}<\/code>&nbsp;with the Client ID from your Okta OIDC application and&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">{yourOktaDomain}<\/code>&nbsp;with your Okta URL. Something like&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">https:\/\/dev-123456.oktapreview.com<\/code>.<\/p>\n<pre class=\"gutter: false;brush:bash\">okta:  \n  oauth2:  \n    issuer: https:\/\/{yourOktaDomain}\/oauth2\/default  \n    client-id: {yourClientId}  \n    scopes: openid profile email\n<\/pre>\n<p>Finally, you need to add the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">@EnableResourceServer<\/code>&nbsp;annotation to your&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">SpringBootVueApplication<\/code>&nbsp;class.<\/p>\n<pre class=\"gutter: false;brush:java; wrap-lines:false\">import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;\n\n@EnableResourceServer  \/\/ &lt;- add me\n@SpringBootApplication  \npublic class SpringBootJpaApplication {  \n  \n    public static void main(String[] args) {  \n        SpringApplication.run(SpringBootJpaApplication.class, args);  \n    }\n    ...\n}\n<\/pre>\n<h2 id=\"test-the-protected-spring-boot-server\">Test the Protected Spring Boot Server<\/h2>\n<p>Stop your Spring Boot server and restart it using:&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">.\/gradlew bootRun<\/code><\/p>\n<p>From the command line, run a simple GET request.<\/p>\n<pre class=\"gutter: false;brush:bash\">http :8080\/kayaks<\/pre>\n<p>You\u2019ll get a 401\/unauthorized.<\/p>\n<pre class=\"gutter: false;brush:bash\">HTTP\/1.1 401\nCache-Control: no-store\nContent-Type: application\/json;charset=UTF-8\n\n{\n    \"error\": \"unauthorized\",\n    \"error_description\": \"Full authentication is required to access this resource\"\n}\n<\/pre>\n<h2 id=\"generate-an-access-token\">Generate an Access Token<\/h2>\n<p>To access the server now, you need a valid access token. You can use&nbsp;<strong>OpenID Connect Debugger<\/strong>&nbsp;to help you do this. In another window, open&nbsp;<a href=\"https:\/\/oidcdebugger.com\/\">oidcdebugger.com<\/a>.<\/p>\n<p><strong>Authorize URI<\/strong>:&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">https:\/\/{yourOktaUrl}\/oauth2\/default\/v1\/authorize<\/code>, with&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">{yourOktaUrl}<\/code>&nbsp;replaced with your actual Okta preview URL.<\/p>\n<p><strong>Redirect URI<\/strong>: do not change. This is the value you added to your OIDC application above.<\/p>\n<p><strong>Client ID<\/strong>: from the OIDC application you just created.<\/p>\n<p><strong>Scope<\/strong>:&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">openid profile email<\/code>.<\/p>\n<p><strong>State<\/strong>: any value you want to pass through the OAuth redirect process. I set it to&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">{}<\/code>.<\/p>\n<p><strong>Nonce<\/strong>: can be left alone. Nonce means \u201cnumber used once\u201d and is a simple security measure used to prevent the same request being used multiple times.<\/p>\n<p><strong>Response Type<\/strong>:&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">token<\/code>.<\/p>\n<p><strong>Response mode<\/strong>:&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">form_post<\/code>.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" width=\"699\" height=\"912\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/12\/oidc-debugger.png\" alt=\"Spring Boot and JPA\" class=\"wp-image-84690\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/12\/oidc-debugger.png 699w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/12\/oidc-debugger-230x300.png 230w\" sizes=\"(max-width: 699px) 100vw, 699px\" \/><\/figure>\n<\/div>\n<p>Click&nbsp;<strong>Send Request<\/strong>. If you are not logged into developer.okta.com, then you\u2019ll be required to log in. If you are (as is likely) already logged in, then the token will be generated for your signed-in identity.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" width=\"604\" height=\"701\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/12\/access-token-success.png\" alt=\"Spring Boot and JPA\" class=\"wp-image-84691\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/12\/access-token-success.png 604w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/12\/access-token-success-258x300.png 258w\" sizes=\"(max-width: 604px) 100vw, 604px\" \/><\/figure>\n<\/div>\n<h2 class=\"wp-block-heading\" id=\"use-the-access-token\">Use the Access Token<\/h2>\n<p>You use the token by including in an&nbsp;<strong>Authorization<\/strong>&nbsp;request header of type&nbsp;<strong>Bearer<\/strong>.<\/p>\n<pre class=\"gutter: false;brush:bash\">Authorization: Bearer eyJraWQiOiJldjFpay1DS3UzYjJXS3QzSVl1MlJZc3VJSzBBYUl3NkU4SDJfNVJr...<\/pre>\n<p>To make the request with HTTPie:<\/p>\n<pre class=\"gutter: false;brush:bash\">http :8080\/kayaks 'Authorization: Bearer eyJraWQiOiJldjFpay1DS3UzYjJXS3QzSVl1...'<\/pre>\n<h2 id=\"add-group-based-authorization\">Add Group-based Authorization<\/h2>\n<p>Up until now, the authorization scheme has been pretty binary. Does the request carry a valid token or not. Now you\u2019re going to add Group-based authentication. Note that despite being used interchangeably sometimes on websites of ill repute, roles and groups are not the same thing, and are different ways of implementing authorization.<\/p>\n<p>A&nbsp;<strong>role<\/strong>&nbsp;is a collection of collection of permissions that a user can inherit. A&nbsp;<strong>group<\/strong>&nbsp;is a collection of users to which a set of standard permissions are assigned. However, in the scope of tokens and how you\u2019re using Spring Security with JPA, the implementation is exactly the same; they\u2019re both passed from the OAuth OIDC application as a string \u201cauthority\u201d to Spring, so for the moment they\u2019re essentially interchangeable. The difference would be in what is protected and how they are defined.<\/p>\n<p>To use group-based authorization with Okta, you need to add a \u201cgroups\u201d claim to your access token. Create an&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">Admin<\/code>&nbsp;group (<strong>Users<\/strong>&nbsp;&gt;&nbsp;<strong>Groups<\/strong>&nbsp;&gt;&nbsp;<strong>Add Group<\/strong>) and add your user to it. You can use the account you signed up with, or create a new user (<strong>Users<\/strong>&gt;&nbsp;<strong>Add Person<\/strong>). Navigate to&nbsp;<strong>API<\/strong>&nbsp;&gt;&nbsp;<strong>Authorization Servers<\/strong>, click the&nbsp;<strong>Authorization Servers<\/strong>&nbsp;tab and edit the default one. Click the&nbsp;<strong>Claims<\/strong>&nbsp;tab and&nbsp;<strong>Add Claim<\/strong>. Name it \u201cgroups\u201d, and include it in the access token. Set the value type to \u201cGroups\u201d and set the filter to be a Regex of&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">.*<\/code>.<\/p>\n<p>Create a new access token using&nbsp;<a href=\"https:\/\/oidcdebugger.com\/\">OIDC Debugger<\/a>. Take a look at your decoded token by going to&nbsp;<a href=\"https:\/\/www.jsonwebtoken.io\/\">jsonwebtoken.io<\/a>&nbsp;and entering in your generated access token.<\/p>\n<p>The payload will look a bit like this:<\/p>\n<pre class=\"gutter: false;brush:js\">{\n \"ver\": 1,\n \"jti\": \"AT.Hk8lHezJNw4wxey1czypDiNXJUxIlKmdT16MrnLGp9E\",\n \"iss\": \"https:\/\/dev-533919.oktapreview.com\/oauth2\/default\",\n \"aud\": \"api:\/\/default\",\n \"iat\": 1542862245,\n \"exp\": 1542866683,\n \"cid\": \"0oahpnkb44pcaOIBG0h7\",\n \"uid\": \"00ue9mlzk7eW24e8Y0h7\",\n \"scp\": [\n  \"email\",\n  \"profile\",\n  \"openid\"\n ],\n \"sub\": \"andrew.hughes@mail.com\",\n \"groups\": [\n  \"Everyone\",\n  \"Admin\"\n ]\n}\n<\/pre>\n<p>The&nbsp;<strong>groups<\/strong>&nbsp;claim carries the groups to which the user is assigned. The user you\u2019re using to sign into the developer.okta.com website will also be a member of both the \u201cEveryone\u201d group and the \u201cAdmin\u201d group.<\/p>\n<p>To get Spring Boot and the resource server to play nicely with group-based authorization, you need to make a few changes to the code.<\/p>\n<p>First, add a new Java class in the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">com.okta.springbootjpa<\/code>&nbsp;package called&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">SecurityConfiguration<\/code>.<\/p>\n<pre class=\"gutter: false;brush:java; wrap-lines:false\">package com.okta.springbootjpa;\n\nimport org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;\n\n@EnableWebSecurity\n@EnableGlobalMethodSecurity(prePostEnabled = true)\npublic class SecurityConfiguration extends WebSecurityConfigurerAdapter {\n}\n<\/pre>\n<p>This configuration class is required to enable the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">@PreAuthorize<\/code>&nbsp;annotation that you\u2019re going to use to protect the resource server based on group membership.<\/p>\n<p>Next, add the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">@PreAuthorize<\/code>&nbsp;annotation to the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">KayakRepository<\/code>, like so:<\/p>\n<pre class=\"gutter: false;brush:java\">...\nimport org.springframework.security.access.prepost.PreAuthorize;\n...\n\n@RepositoryRestResource  \n@PreAuthorize(\"hasAuthority('Admin')\")  \npublic interface KayakRepository extends CrudRepository&lt;Kayak, Long&gt; {  \n}\n<\/pre>\n<p>Finally, in the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">SpringBootJpaApplication<\/code>,&nbsp;<strong>delete<\/strong>&nbsp;the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">ApplicationRunner init(KayakRepository repository)<\/code>method (or just comment out the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">@Bean<\/code>&nbsp;annotation). If you skip this step, the build will fail with the following error:<\/p>\n<pre class=\"gutter: false;brush:bash; wrap-lines:false\">AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext<\/pre>\n<p>The&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">@PreAuthorize<\/code>&nbsp;annotation actually blocks the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">init()<\/code>&nbsp;method from creating the bootstrapped data programmatically because no user is logged in. Thus with the method runs, it throws an error.<\/p>\n<p>Notice that you\u2019re using&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">hasAuthority()<\/code>&nbsp;in the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">@PreAuthorize<\/code>&nbsp;annotation and&nbsp;<strong>not<\/strong>&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">hasRole()<\/code>. The difference is that&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">hasRole()<\/code>&nbsp;expects groups or roles to be in ALL CAPS and to have a&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">ROLE_<\/code>&nbsp;prefix. This can be configured, of course, but&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">hasAuthority()<\/code>&nbsp;comes without this baggage and simply checks whatever claim you\u2019ve defined as the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">okta.oauth2.roles-claim<\/code>&nbsp;in your&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">application.yml<\/code>.<\/p>\n<h2 id=\"test-the-admin-user-in-your-spring-boot-app\">Test the Admin User in Your Spring Boot App<\/h2>\n<p>Restart your Spring Boot app (start with&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">.\/gradlew bootRun<\/code>).<\/p>\n<p>Try an unauthenticated GET request:&nbsp;v class=&#8221;highlighter-rouge&#8221;&gt;http :8080\/kayaks.<\/p>\n<pre class=\"gutter: false;brush:bash\">HTTP\/1.1 401\nCache-Control: no-store\nContent-Type: application\/json;charset=UTF-8\n\n{\n    \"error\": \"unauthorized\",\n    \"error_description\": \"Full authentication is required to access this resource\"\n}\n<\/pre>\n<p>Try it using your token.<\/p>\n<p>Command:<\/p>\n<pre class=\"gutter: false;brush:bash\">http :8080\/kayaks 'Authorization: Bearer eyJraWQiOiJldjFpay1DS3UzYjJXS3QzSVl1MlJZc3VJSzBBYUl3NkU4SDJf...'<\/pre>\n<p>Reply:<\/p>\n<pre class=\"gutter: false;brush:bash\">HTTP\/1.1 200\nCache-Control: no-cache, no-store, max-age=0, must-revalidate\nContent-Type: application\/hal+json;charset=UTF-8\n\n{\n    \"_embedded\": {\n        \"kayaks\": []\n    },\n    \"_links\": {\n        \"profile\": {\n            \"href\": \"http:\/\/localhost:8080\/profile\/kayaks\"\n        },\n        \"self\": {\n            \"href\": \"http:\/\/localhost:8080\/kayaks\"\n        }\n    }\n}<\/pre>\n<p>It worked! We don\u2019t have any kayaks because we had to remove the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">init()<\/code>&nbsp;method above, so the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">_embedded.kayaks<\/code>&nbsp;array is empty.<\/p>\n<p><strong>TIP:<\/strong>&nbsp;going forward, if you don\u2019t want to copy and paste the whole enormous token string, you can store it to a shell variable and reuse it like so:<\/p>\n<pre class=\"gutter:false;brush:bash\">TOKEN=eyJraWQiOiJldjFpay1DS3UzYjJXS3QzSVl1MlJZc3VJSzBBYUl3NkU4SDJf...\nhttp :8080\/kayaks 'Authorization: Bearer $TOKEN'<\/pre>\n<h2 id=\"create-a-non-admin-user\">Create a Non-Admin User<\/h2>\n<p>To demonstrate group-based authorization, you need to create a new user on Okta that isn\u2019t an admin. Go to the&nbsp;<a href=\"https:\/\/developer.okta.com\/?utm_campaign=text_website_all_multiple_dev_ciam_build-basic-app-spring-boot-jpa_null&amp;utm_source=jcg&amp;utm_medium=cpc\">developer.okta.com<\/a>&nbsp;dashboard.<\/p>\n<p>From the top-menu, select&nbsp;<strong>Users<\/strong>&nbsp;and&nbsp;<strong>People<\/strong>.<\/p>\n<p>Click the&nbsp;<strong>Add Person<\/strong>&nbsp;button.<\/p>\n<p>Give the user a&nbsp;<strong>First Name<\/strong>,&nbsp;<strong>Last Name<\/strong>, and&nbsp;<strong>Username<\/strong>&nbsp;(which will also be the&nbsp;<strong>Primary Email<\/strong>). The values do not matter, and you won\u2019t need to be able to check the email. You simply need to know the email address\/username and password so you can log in to Okta in a minute.<\/p>\n<p><strong>Password<\/strong>: change the drop down to&nbsp;<strong>Set by admin<\/strong>.<\/p>\n<p>Assign the user a password.<\/p>\n<p>Click&nbsp;<strong>Save<\/strong>.<\/p>\n<p>You\u2019ve just created a user that is NOT a member of the&nbsp;<em>Admin<\/em>&nbsp;group but is a member of the default group&nbsp;<em>Everyone<\/em>.<\/p>\n<h2 id=\"test-group-based-authorization-in-your-spring-boot-app\">Test Group-based Authorization in Your Spring Boot App<\/h2>\n<p>Log out of your Okta developer dashboard.<\/p>\n<p>Return to the&nbsp;<a href=\"https:\/\/oidcdebugger.com\/\">OIDC Debugger<\/a>&nbsp;and generate a new token.<\/p>\n<p>This time, log in as your new non-admin user. You\u2019ll be asked to choose a security question, after which you\u2019ll be redirected to the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">https:\/\/oidcdebugger.com\/debug<\/code>&nbsp;page where your token can be copied.<\/p>\n<p>If you like, you can go to&nbsp;<a href=\"https:\/\/www.jsonwebtoken.io\/\">jsonwebtoken.io<\/a>&nbsp;and decode your new token. In the payload, the&nbsp;<em>sub<\/em>&nbsp;claim will show the email\/username of the user, and the&nbsp;<em>groups<\/em>&nbsp;claim will show only the&nbsp;<em>Everyone<\/em>&nbsp;group.<\/p>\n<pre class=\"gutter: false;brush:js\">{\n ...\n \"sub\": \"test@gmail.com\",\n \"groups\": [\n  \"Everyone\"\n ]\n}<\/pre>\n<p>If you use the new token to make a request on the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">\/kayaks<\/code>&nbsp;endpoint, you\u2019ll get a 403\/Access Denied.<\/p>\n<pre class=\"gutter: false;brush:bash\">http :8080\/kayaks 'Authorization: Bearer eyJraWQiOiJldjFpay1DS3UzYjJX...'<\/pre>\n<pre class=\"gutter: false;brush:js\">HTTP\/1.1 403\n...\n\n{\n    \"error\": \"access_denied\",\n    \"error_description\": \"Access is denied\"\n}<\/pre>\n<p>To demonstrate the real power of the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">@PreAuthorize<\/code>&nbsp;annotation, create a method-level security constraint. Change the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">KayakRepository<\/code>&nbsp;class to the following:<\/p>\n<pre class=\"gutter: false;brush:java\">@RepositoryRestResource  \npublic interface KayakRepository extends CrudRepository&lt;Kayak, Long&gt; {  \n  \n    @PreAuthorize(\"hasAuthority('Admin')\")  \n    &lt;S extends Kayak&gt; S save(S entity);  \n  \n}<\/pre>\n<p>This restricts only the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">save()<\/code>&nbsp;method to members of the Admin group. The rest of the repository will be restricted simply requiring authentication, but no specific group membership.<\/p>\n<p>Restart your Spring Boot server. Run the same request again.<\/p>\n<pre class=\"gutter: false;brush:bash\">http :8080\/kayaks 'Authorization: Bearer eyJraWQiOiJldjFpay1DS3UzYjJX...'<\/pre>\n<pre class=\"gutter: false;brush:js\">HTTP\/1.1 200\n...\n\n{\n    \"_embedded\": {\n        \"kayaks\": []\n    },\n    \"_links\": {\n        \"profile\": {\n            \"href\": \"http:\/\/localhost:8080\/profile\/kayaks\"\n        },\n        \"self\": {\n            \"href\": \"http:\/\/localhost:8080\/kayaks\"\n        }\n    }\n}<\/pre>\n<p>The kayaks repository is empty, so&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">_.embedded.kayaks<\/code>&nbsp;is an empty array.<\/p>\n<p>Try and create a new kayak.<\/p>\n<pre class=\"gutter: false;brush:bash; wrap-lines:false\">http POST :8080\/kayaks name=\"sea2\" owner=\"Andrew\" value=\"500\" makeModel=\"P&amp;H\" \"Authorization: Bearer eyJraWQiOiJldjFpay1DS3UzYjJX...\"<\/pre>\n<p>You\u2019ll get another 403. \u201cSaving\u201d is going to equal an HTML POST here.<\/p>\n<p>However, if you use a token generated from your original, admin account, it\u2019ll work.<\/p>\n<p><strong>NOTE:<\/strong>&nbsp;It\u2019s possible your token will be expired and you\u2019ll have to log out of developer.okta.com again and re-generate the token on the&nbsp;<a href=\"https:\/\/oidcdebugger.com\/\">OIDC Debugger<\/a>.<\/p>\n<p>POST a new kayak with the token generated from your admin account.<\/p>\n<p>This time you\u2019ll get a 201.<\/p>\n<pre class=\"gutter: false;brush:bash\">HTTP\/1.1 201\nCache-Control: no-cache, no-store, max-age=0, must-revalidate\nContent-Type: application\/json;charset=UTF-8\n...\n\n{\n    \"_links\": {\n        \"kayak\": {\n            \"href\": \"http:\/\/localhost:8080\/kayaks\/1\"\n        },\n        \"self\": {\n            \"href\": \"http:\/\/localhost:8080\/kayaks\/1\"\n        }\n    },\n    \"makeModel\": \"P&amp;H\",\n    \"name\": \"sea2\",\n    \"owner\": \"Andrew\",\n    \"value\": 500\n}<\/pre>\n<p>Success!<\/p>\n<p>Take a look at&nbsp;<a href=\"https:\/\/docs.spring.io\/spring-data\/commons\/docs\/current\/api\/org\/springframework\/data\/repository\/CrudRepository.html\">Spring Data\u2019s&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">CrudRepository<\/code>&nbsp;interface<\/a>&nbsp;to get an idea of the methods that can be overridden and assigned method-level security. The&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">@PreAuthorize<\/code>&nbsp;annotation can be used with a lot more than just groups, as well. The entire power of Spring\u2019s expression language (SpEL) can be leveraged.<\/p>\n<pre class=\"gutter: false;brush:java\">public interface CrudRepository&lt;T, ID&gt; extends Repository&lt;T, ID&gt; {\n  &lt;S extends T&gt; S save(S entity);\n  &lt;S extends T&gt; Iterable&lt;S&gt; saveAll(Iterable&lt;S&gt; entities);\n  Optional&lt;T&gt; findById(ID id);\n  boolean existsById(ID id);\n  Iterable&lt;T&gt; findAll();\n  Iterable&lt;T&gt; findAllById(Iterable&lt;ID&gt; ids);\n  long count();\n  void deleteById(ID id);\n  void delete(T entity);\n  void deleteAll(Iterable&lt;? extends T&gt; entities);\n  void deleteAll();\n}<\/pre>\n<p>And that\u2019s it! Pretty cool right? In this tutorial, you set up a PostgreSQL database, created a Spring Boot resource server that used Spring Data and JPA to persist a data model, and then turned this data model into a REST API with shockingly little code. Further, you used Okta to add OIDC authentication and OAuth 2.0 authorization to your server application. And finally, you implemented a simple group-based authorization scheme.<\/p>\n<p>If you\u2019d like to check out this complete project, you can find the repo on GitHub at&nbsp;<a href=\"https:\/\/github.com\/oktadeveloper\/okta-spring-boot-jpa-example\">@oktadeveloper\/okta-spring-boot-jpa-example<\/a>.<\/p>\n<p>Watch out for our next post in this series that will cover using a NoSQL database (MongoDB) with Spring WebFlux.<\/p>\n<h2 id=\"learn-more-about-spring-boot-spring-security-and-secure-authentication\">Learn More about Spring Boot, Spring Security, and Secure Authentication<\/h2>\n<p>If you\u2019d like to learn more about Spring Boot, Spring Security, or modern application security, check out any of these great tutorials:<\/p>\n<ul>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2017\/03\/21\/spring-boot-oauth?utm_campaign=text_website_all_multiple_dev_ciam_build-basic-app-spring-boot-jpa_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Get Started with Spring Boot, OAuth 2.0, and Okta<\/a><\/li>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2017\/11\/20\/add-sso-spring-boot-15-min?utm_campaign=text_website_all_multiple_dev_ciam_build-basic-app-spring-boot-jpa_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Add Single Sign-On to Your Spring Boot Web App in 15 Minutes<\/a><\/li>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2018\/06\/12\/mfa-in-spring-boot?utm_campaign=text_website_all_multiple_dev_ciam_build-basic-app-spring-boot-jpa_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Secure Your Spring Boot Application with Multi-Factor Authentication<\/a><\/li>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2018\/08\/16\/secure-api-spring-boot-graphql?utm_campaign=text_website_all_multiple_dev_ciam_build-basic-app-spring-boot-jpa_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Build a Secure API with Spring Boot and GraphQL<\/a><\/li>\n<\/ul>\n<p>If you want to dive deeper, take a look at the&nbsp;<a href=\"https:\/\/github.com\/okta\/okta-spring-boot\">Okta Spring Boot Starter GitHub project<\/a>.<\/p>\n<p>This is a great reference for Spring Data and securing Spring Boot projects:&nbsp;<a href=\"https:\/\/docs.spring.io\/spring-data\/rest\/docs\/current\/reference\/html\/\">https:\/\/docs.spring.io\/spring-data\/rest\/docs\/current\/reference\/html\/<\/a><\/p>\n<p>Vlad Mihalcea has a great tutorial titled&nbsp;<a href=\"https:\/\/vladmihalcea.com\/9-postgresql-high-performance-performance-tips\/\">9 High-Performance Tips when using PostgreSQL with JPA and Hibernate<\/a>.<\/p>\n<p>Baeldung has a helpful tutorial on securing methods in Spring Data \/ Spring Boot projects:&nbsp;<a href=\"https:\/\/www.baeldung.com\/spring-security-method-security\">https:\/\/www.baeldung.com\/spring-security-method-security<\/a><\/p>\n<p>Lastly, if you need some more help with PostgreSQL on Mac OS X, see&nbsp;<a href=\"https:\/\/www.codementor.io\/engineerapart\/getting-started-with-postgresql-on-mac-osx-are8jcopb\">this codementor.io tutorial<\/a>.<\/p>\n<p>If you have any questions about this post, please add a comment below. For more awesome content, follow&nbsp;<a href=\"https:\/\/twitter.com\/oktadev\">@oktadev<\/a>&nbsp;on Twitter, like us&nbsp;<a href=\"https:\/\/www.facebook.com\/oktadevelopers\/\">on Facebook<\/a>, or subscribe to&nbsp;<a href=\"https:\/\/www.youtube.com\/channel\/UC5AMiWqFVFxF1q9Ya1FuZ_Q\">our YouTube channel<\/a>.<\/p>\n<p><a href=\"https:\/\/developer.okta.com\/blog\/2018\/12\/13\/build-basic-app-spring-boot-jpa?utm_campaign=text_website_all_multiple_dev_ciam_build-basic-app-spring-boot-jpa_null&amp;utm_source=jcg&amp;utm_medium=cpc\" target=\"_blank\" rel=\"noopener\" data-saferedirecturl=\"https:\/\/www.google.com\/url?q=https:\/\/developer.okta.com\/blog\/2018\/12\/13\/build-basic-app-spring-boot-jpa&amp;source=gmail&amp;ust=1545223328512000&amp;usg=AFQjCNE4wnf8Hk6WsWfMonjp-vE0LgIsEg\">&#8216;Build an App with Spring Boot and JPA using PostgreSQL&#8217;<\/a>&nbsp;was originally published on the Okta developer blog on December 13, 2018.<\/p>\n<\/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_campaign=text_website_all_multiple_dev_ciam_build-basic-app-spring-boot-jpa_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Try the Okta API for hosted authentication, authorization, and multi-factor auth.<\/a><\/span><\/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. Every non-trivial application needs a way to save and update data: a resource server that is accessible via HTTP. Generally, this data &hellip;<\/p>\n","protected":false},"author":49514,"featured_media":240,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[30,854],"class_list":["post-84685","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-enterprise-java","tag-spring","tag-spring-boot"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Build a Basic App with Spring Boot and JPA using PostgreSQL - Java Code Geeks<\/title>\n<meta name=\"description\" content=\"Interested to learn about Spring Boot and JPA? Check our article showing how you\u2019re going to build a resource server using Spring Boot and Spring Data JPA.\" \/>\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\/12\/13\/build-basic-app-spring-boot-jpa\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Build a Basic App with Spring Boot and JPA using PostgreSQL - Java Code Geeks\" \/>\n<meta property=\"og:description\" content=\"Interested to learn about Spring Boot and JPA? Check our article showing how you\u2019re going to build a resource server using Spring Boot and Spring Data JPA.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/developer.okta.com\/blog\/2018\/12\/13\/build-basic-app-spring-boot-jpa\" \/>\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-12-20T06:35:38+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2018-12-28T07:29:33+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-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=\"Andrew Hughes\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:site\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Andrew Hughes\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"25 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\\\/12\\\/13\\\/build-basic-app-spring-boot-jpa#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/12\\\/build-basic-spring-boot-using-postgresql.html\"},\"author\":{\"name\":\"Andrew Hughes\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/0ded99ab51010abb68790f6189ce99d3\"},\"headline\":\"Build a Basic App with Spring Boot and JPA using PostgreSQL\",\"datePublished\":\"2018-12-20T06:35:38+00:00\",\"dateModified\":\"2018-12-28T07:29:33+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/12\\\/build-basic-spring-boot-using-postgresql.html\"},\"wordCount\":3703,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2018\\\/12\\\/13\\\/build-basic-app-spring-boot-jpa#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"keywords\":[\"Spring\",\"Spring Boot\"],\"articleSection\":[\"Enterprise Java\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2018\\\/12\\\/13\\\/build-basic-app-spring-boot-jpa#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/12\\\/build-basic-spring-boot-using-postgresql.html\",\"url\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2018\\\/12\\\/13\\\/build-basic-app-spring-boot-jpa\",\"name\":\"Build a Basic App with Spring Boot and JPA using PostgreSQL - Java Code Geeks\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2018\\\/12\\\/13\\\/build-basic-app-spring-boot-jpa#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2018\\\/12\\\/13\\\/build-basic-app-spring-boot-jpa#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"datePublished\":\"2018-12-20T06:35:38+00:00\",\"dateModified\":\"2018-12-28T07:29:33+00:00\",\"description\":\"Interested to learn about Spring Boot and JPA? Check our article showing how you\u2019re going to build a resource server using Spring Boot and Spring Data JPA.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2018\\\/12\\\/13\\\/build-basic-app-spring-boot-jpa#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2018\\\/12\\\/13\\\/build-basic-app-spring-boot-jpa\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2018\\\/12\\\/13\\\/build-basic-app-spring-boot-jpa#primaryimage\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"width\":150,\"height\":150,\"caption\":\"spring-interview-questions-answers\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2018\\\/12\\\/13\\\/build-basic-app-spring-boot-jpa#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 Basic App with Spring Boot and JPA using PostgreSQL\"}]},{\"@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\\\/0ded99ab51010abb68790f6189ce99d3\",\"name\":\"Andrew Hughes\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/703689ecb161268c8a6ca8ad4057b8342d22972ec435111a055712b399716dbd?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/703689ecb161268c8a6ca8ad4057b8342d22972ec435111a055712b399716dbd?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/703689ecb161268c8a6ca8ad4057b8342d22972ec435111a055712b399716dbd?s=96&d=mm&r=g\",\"caption\":\"Andrew Hughes\"},\"sameAs\":[\"https:\\\/\\\/developer.okta.com\\\/blog\"],\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/author\\\/andrew-hughes\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Build a Basic App with Spring Boot and JPA using PostgreSQL - Java Code Geeks","description":"Interested to learn about Spring Boot and JPA? Check our article showing how you\u2019re going to build a resource server using Spring Boot and Spring Data JPA.","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\/12\/13\/build-basic-app-spring-boot-jpa","og_locale":"en_US","og_type":"article","og_title":"Build a Basic App with Spring Boot and JPA using PostgreSQL - Java Code Geeks","og_description":"Interested to learn about Spring Boot and JPA? Check our article showing how you\u2019re going to build a resource server using Spring Boot and Spring Data JPA.","og_url":"https:\/\/developer.okta.com\/blog\/2018\/12\/13\/build-basic-app-spring-boot-jpa","og_site_name":"Java Code Geeks","article_publisher":"https:\/\/www.facebook.com\/javacodegeeks","article_published_time":"2018-12-20T06:35:38+00:00","article_modified_time":"2018-12-28T07:29:33+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","type":"image\/jpeg"}],"author":"Andrew Hughes","twitter_card":"summary_large_image","twitter_creator":"@javacodegeeks","twitter_site":"@javacodegeeks","twitter_misc":{"Written by":"Andrew Hughes","Est. reading time":"25 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/developer.okta.com\/blog\/2018\/12\/13\/build-basic-app-spring-boot-jpa#article","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/2018\/12\/build-basic-spring-boot-using-postgresql.html"},"author":{"name":"Andrew Hughes","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/0ded99ab51010abb68790f6189ce99d3"},"headline":"Build a Basic App with Spring Boot and JPA using PostgreSQL","datePublished":"2018-12-20T06:35:38+00:00","dateModified":"2018-12-28T07:29:33+00:00","mainEntityOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2018\/12\/build-basic-spring-boot-using-postgresql.html"},"wordCount":3703,"commentCount":0,"publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"image":{"@id":"https:\/\/developer.okta.com\/blog\/2018\/12\/13\/build-basic-app-spring-boot-jpa#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","keywords":["Spring","Spring Boot"],"articleSection":["Enterprise Java"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/developer.okta.com\/blog\/2018\/12\/13\/build-basic-app-spring-boot-jpa#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.javacodegeeks.com\/2018\/12\/build-basic-spring-boot-using-postgresql.html","url":"https:\/\/developer.okta.com\/blog\/2018\/12\/13\/build-basic-app-spring-boot-jpa","name":"Build a Basic App with Spring Boot and JPA using PostgreSQL - Java Code Geeks","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/developer.okta.com\/blog\/2018\/12\/13\/build-basic-app-spring-boot-jpa#primaryimage"},"image":{"@id":"https:\/\/developer.okta.com\/blog\/2018\/12\/13\/build-basic-app-spring-boot-jpa#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","datePublished":"2018-12-20T06:35:38+00:00","dateModified":"2018-12-28T07:29:33+00:00","description":"Interested to learn about Spring Boot and JPA? Check our article showing how you\u2019re going to build a resource server using Spring Boot and Spring Data JPA.","breadcrumb":{"@id":"https:\/\/developer.okta.com\/blog\/2018\/12\/13\/build-basic-app-spring-boot-jpa#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/developer.okta.com\/blog\/2018\/12\/13\/build-basic-app-spring-boot-jpa"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/developer.okta.com\/blog\/2018\/12\/13\/build-basic-app-spring-boot-jpa#primaryimage","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","width":150,"height":150,"caption":"spring-interview-questions-answers"},{"@type":"BreadcrumbList","@id":"https:\/\/developer.okta.com\/blog\/2018\/12\/13\/build-basic-app-spring-boot-jpa#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 Basic App with Spring Boot and JPA using PostgreSQL"}]},{"@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\/0ded99ab51010abb68790f6189ce99d3","name":"Andrew Hughes","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/703689ecb161268c8a6ca8ad4057b8342d22972ec435111a055712b399716dbd?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/703689ecb161268c8a6ca8ad4057b8342d22972ec435111a055712b399716dbd?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/703689ecb161268c8a6ca8ad4057b8342d22972ec435111a055712b399716dbd?s=96&d=mm&r=g","caption":"Andrew Hughes"},"sameAs":["https:\/\/developer.okta.com\/blog"],"url":"https:\/\/www.javacodegeeks.com\/author\/andrew-hughes"}]}},"_links":{"self":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/84685","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\/49514"}],"replies":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/comments?post=84685"}],"version-history":[{"count":0,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/84685\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media\/240"}],"wp:attachment":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media?parent=84685"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/categories?post=84685"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/tags?post=84685"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}