MoinMoin Logo
  • Comments
  • Immutable Page
  • Menu
    • Navigation
    • RecentChanges
    • FindPage
    • Local Site Map
    • Help
    • HelpContents
    • HelpOnMoinWikiSyntax
    • Display
    • Attachments
    • Info
    • Raw Text
    • Print View
    • Edit
    • Load
    • Save
  • Login

Navigation

  • Start
  • Sitemap
Revision 13 as of 2020-06-17 17:33:10
  • jwt

jwt (JSON Web Token)

JSON Web Token

  • https://tools.ietf.org/html/rfc7519

  • https://en.wikipedia.org/wiki/JSON_Web_Token

  • https://jwt.io/

  • https://www.devglan.com/spring-security/spring-boot-jwt-auth

  • https://www.baeldung.com/spring-security-oauth-jwt

  • https://www.tutorialspoint.com/spring_boot/spring_boot_oauth2_with_jwt.htm

Overview

In authentication, when the user successfully logs in using their credentials, a JSON Web Token will be returned and must be saved locally (typically in local or session storage, but cookies can also be used), instead of the traditional approach of creating a session in the server and returning a cookie.

The tokens are designed to be compact,[2] URL-safe,[3] and usable especially in a web-browser single-sign-on (SSO) context. JWT claims can be typically used to pass identity of authenticated users between an identity provider and a service provider, or any other type of claims as required by business processes.

This is a stateless authentication mechanism as the user state is never saved in server memory. The server's protected routes will check for a valid JWT in the Authorization header, and if it is present, the user will be allowed to access protected resources. As JWTs are self-contained, all the necessary information is there, reducing the need to query the database multiple times.

Adapted tutorials point Spring boot + JWT example

  • https://www.tutorialspoint.com/spring_boot/spring_boot_oauth2_with_jwt.htm

The example in the tutorial doesn't run out of the box. It doesn't explain how to load the private key (PEM). Also it relies on Java 8. If we try to use the example with Java 11 it doesn0t work due to issues with xml bind.

Structure

.
├── build_image.sh
├── connect_container.sh
├── Dockerfile
├── get_token.sh
├── jwt.pem
├── pom.xml
├── run_container.sh
├── src
│   └── main
│       ├── java
│       │   └── com
│       │       └── tutorialspoint
│       │           └── websecurityapp
│       │               ├── CustomDetailsService.java
│       │               ├── CustomUser.java
│       │               ├── OAuth2Config.java
│       │               ├── OAuthDao.java
│       │               ├── SecurityConfiguration.java
│       │               ├── UserEntity.java
│       │               └── WebsecurityappApplication.java
│       └── resources
│           ├── application.properties
│           ├── data.sql
│           └── schema.sql
└── stop_container.sh
  • mkdir -p src/main/java/com/tutorialspoint/websecurityapp/
  • mkdir src/main/resources/
  • openssl genrsa -out jwt.pem 2048 # generate private key

run_container.sh

   1 docker run -d -p 8080:8080 --name test test_image

Dockerfile

   1 FROM openjdk:8-alpine
   2 RUN apk add maven
   3 RUN mkdir -p /usr/src/tutpoint-jwt
   4 COPY . /usr/src/tutpoint-jwt
   5 WORKDIR /usr/src/tutpoint-jwt
   6 RUN mvn clean install
   7 CMD ["java","-jar","target/websecurityapp-0.0.1-SNAPSHOT.jar"]

src/main/java/com/tutorialspoint/websecurityapp/SecurityConfiguration.java

   1 package com.tutorialspoint.websecurityapp;
   2 
   3 import org.springframework.beans.factory.annotation.Autowired;
   4 import org.springframework.context.annotation.Bean;
   5 import org.springframework.context.annotation.Configuration;
   6 
   7 import org.springframework.security.authentication.AuthenticationManager;
   8 import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
   9 import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
  10 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  11 import org.springframework.security.config.annotation.web.builders.WebSecurity;
  12 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  13 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  14 import org.springframework.security.config.http.SessionCreationPolicy;
  15 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  16 import org.springframework.security.crypto.password.PasswordEncoder;
  17 
  18 @Configuration
  19 @EnableWebSecurity
  20 @EnableGlobalMethodSecurity(prePostEnabled = true)
  21 public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
  22    @Autowired
  23    private CustomDetailsService customDetailsService;
  24 
  25    @Bean
  26    public PasswordEncoder encoder() {
  27       return new BCryptPasswordEncoder();
  28    }
  29 
  30    @Override
  31    @Autowired
  32    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  33       auth.userDetailsService(customDetailsService).passwordEncoder(encoder());
  34    }
  35 
  36    @Override
  37    protected void configure(HttpSecurity http) throws Exception {
  38       http.authorizeRequests().anyRequest().authenticated().and().sessionManagement()
  39          .sessionCreationPolicy(SessionCreationPolicy.NEVER);
  40    }
  41 
  42    @Override
  43    public void configure(WebSecurity web) throws Exception {
  44       web.ignoring();
  45    }
  46 
  47    @Override
  48    @Bean
  49    public AuthenticationManager authenticationManagerBean() throws Exception {
  50       return super.authenticationManagerBean();
  51    }
  52 }

src/main/java/com/tutorialspoint/websecurityapp/OAuth2Config.java

   1 package com.tutorialspoint.websecurityapp;
   2 
   3 import org.springframework.beans.factory.annotation.Autowired;
   4 import org.springframework.context.annotation.Bean;
   5 import org.springframework.context.annotation.Configuration;
   6 
   7 import org.springframework.security.authentication.AuthenticationManager;
   8 import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
   9 import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
  10 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  11 import org.springframework.security.config.annotation.web.builders.WebSecurity;
  12 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  13 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  14 import org.springframework.security.config.http.SessionCreationPolicy;
  15 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  16 import org.springframework.security.crypto.password.PasswordEncoder;
  17 
  18 @Configuration
  19 @EnableWebSecurity
  20 @EnableGlobalMethodSecurity(prePostEnabled = true)
  21 public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
  22    @Autowired
  23    private CustomDetailsService customDetailsService;
  24 
  25    @Bean
  26    public PasswordEncoder encoder() {
  27       return new BCryptPasswordEncoder();
  28    }
  29 
  30    @Override
  31    @Autowired
  32    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  33       auth.userDetailsService(customDetailsService).passwordEncoder(encoder());
  34    }
  35 
  36    @Override
  37    protected void configure(HttpSecurity http) throws Exception {
  38       http.authorizeRequests().anyRequest().authenticated().and().sessionManagement()
  39          .sessionCreationPolicy(SessionCreationPolicy.NEVER);
  40    }
  41 
  42    @Override
  43    public void configure(WebSecurity web) throws Exception {
  44       web.ignoring();
  45    }
  46 
  47    @Override
  48    @Bean
  49    public AuthenticationManager authenticationManagerBean() throws Exception {
  50       return super.authenticationManagerBean();
  51    }
  52 }

src/main/java/com/tutorialspoint/websecurityapp/CustomUser.java

   1 package com.tutorialspoint.websecurityapp;
   2 
   3 import org.springframework.security.core.userdetails.User;
   4 
   5 public class CustomUser extends User {
   6    private static final long serialVersionUID = 1L;
   7    public CustomUser(UserEntity user) {
   8       super(user.getUsername(), user.getPassword(), user.getGrantedAuthoritiesList());
   9    }
  10 } 

src/main/java/com/tutorialspoint/websecurityapp/UserEntity.java

   1 package com.tutorialspoint.websecurityapp;
   2 
   3 import java.util.ArrayList;
   4 import java.util.Collection;
   5 import org.springframework.security.core.GrantedAuthority;
   6 
   7 public class UserEntity {
   8    private String username;
   9    private String password;
  10    private Collection<GrantedAuthority> grantedAuthoritiesList = new ArrayList<>();
  11    
  12    public String getPassword() {
  13       return password;
  14    }
  15    public void setPassword(String password) {
  16       this.password = password;
  17    }
  18    public Collection<GrantedAuthority> getGrantedAuthoritiesList() {
  19       return grantedAuthoritiesList;
  20    }
  21    public void setGrantedAuthoritiesList(Collection<GrantedAuthority> grantedAuthoritiesList) {
  22       this.grantedAuthoritiesList = grantedAuthoritiesList;
  23    }
  24    public String getUsername() {
  25       return username;
  26    }
  27    public void setUsername(String username) {
  28       this.username = username;
  29    }
  30 }

src/main/java/com/tutorialspoint/websecurityapp/WebsecurityappApplication.java

   1 package com.tutorialspoint.websecurityapp;
   2 
   3 import org.springframework.boot.SpringApplication;
   4 import org.springframework.boot.autoconfigure.SpringBootApplication;
   5 import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
   6 import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
   7 import org.springframework.web.bind.annotation.RequestMapping;
   8 import org.springframework.web.bind.annotation.RestController;
   9 
  10 @SpringBootApplication
  11 @EnableAuthorizationServer
  12 @EnableResourceServer
  13 @RestController
  14 public class WebsecurityappApplication {
  15    public static void main(String[] args) {
  16       SpringApplication.run(WebsecurityappApplication.class, args);
  17    }
  18    @RequestMapping(value = "/products")
  19    public String getProductName() {
  20       return "Honey";   
  21    }
  22 } 

src/main/java/com/tutorialspoint/websecurityapp/CustomDetailsService.java

   1 package com.tutorialspoint.websecurityapp;
   2 
   3 import org.springframework.beans.factory.annotation.Autowired;
   4 import org.springframework.security.core.userdetails.UserDetailsService;
   5 import org.springframework.security.core.userdetails.UsernameNotFoundException;
   6 import org.springframework.stereotype.Service;
   7 
   8 @Service
   9 public class CustomDetailsService implements UserDetailsService {
  10    @Autowired
  11    OAuthDao oauthDao;
  12 
  13    @Override
  14    public CustomUser loadUserByUsername(final String username) throws UsernameNotFoundException {
  15       UserEntity userEntity = null;
  16       try {
  17          userEntity = oauthDao.getUserDetails(username);
  18          CustomUser customUser = new CustomUser(userEntity);
  19          return customUser;
  20       } catch (Exception e) {
  21          e.printStackTrace();
  22          throw new UsernameNotFoundException("User " + username + " was not found in the database");
  23       }
  24    }
  25 } 

src/main/java/com/tutorialspoint/websecurityapp/OAuthDao.java

   1 package com.tutorialspoint.websecurityapp;
   2 
   3 import java.sql.ResultSet;
   4 import java.util.ArrayList;
   5 import java.util.Collection;
   6 import java.util.List;
   7 
   8 import org.springframework.beans.factory.annotation.Autowired;
   9 import org.springframework.jdbc.core.JdbcTemplate;
  10 import org.springframework.security.core.GrantedAuthority;
  11 import org.springframework.security.core.authority.SimpleGrantedAuthority;
  12 import org.springframework.stereotype.Repository;
  13 
  14 @Repository
  15 public class OAuthDao {
  16    @Autowired
  17    private JdbcTemplate jdbcTemplate;
  18 
  19    public UserEntity getUserDetails(String username) {
  20       Collection<GrantedAuthority> grantedAuthoritiesList = new ArrayList<>();
  21       String userSQLQuery = "SELECT * FROM USERS WHERE USERNAME=?";
  22       List<UserEntity> list = jdbcTemplate.query(userSQLQuery, new String[] { username },
  23          (ResultSet rs, int rowNum) -> {
  24          
  25          UserEntity user = new UserEntity();
  26          user.setUsername(username);
  27          user.setPassword(rs.getString("PASSWORD"));
  28          return user;
  29       });
  30       if (list.size() > 0) {
  31          GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_SYSTEMADMIN");
  32          grantedAuthoritiesList.add(grantedAuthority);
  33          list.get(0).setGrantedAuthoritiesList(grantedAuthoritiesList);
  34          return list.get(0);
  35       }
  36       return null;
  37    }
  38 } 

src/main/resources/schema.sql

   1 CREATE TABLE USERS (ID INT PRIMARY KEY, USERNAME VARCHAR(45), PASSWORD VARCHAR(60));

src/main/resources/application.properties

security.oauth2.resource.filter-order=3 
logging.file=/tmp/testout.log

src/main/resources/data.sql

   1 INSERT INTO USERS (ID, USERNAME,PASSWORD) VALUES (
   2    1, 'tutorialspoint@gmail.com','$2a$08$fL7u5xcvsZl78su29x1ti.dxI.9rYO8t0q5wk2ROJ.1cdR53bmaVG');
   3 
   4 INSERT INTO USERS (ID, USERNAME,PASSWORD) VALUES (
   5    2, 'myemail@gmail.com','$2a$08$fL7u5xcvsZl78su29x1ti.dxI.9rYO8t0q5wk2ROJ.1cdR53bmaVG');

build_image.sh

   1 docker build -t test_image .

pom.xml

   1 <?xml version = "1.0" encoding = "UTF-8"?>
   2 <project xmlns = "http://maven.apache.org/POM/4.0.0" 
   3    xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   4    xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 
   5    http://maven.apache.org/xsd/maven-4.0.0.xsd">
   6    
   7    <modelVersion>4.0.0</modelVersion>
   8    <groupId>com.tutorialspoint</groupId>
   9    <artifactId>websecurityapp</artifactId>
  10    <version>0.0.1-SNAPSHOT</version>
  11    <packaging>jar</packaging>
  12    <name>websecurityapp</name>
  13    <description>Demo project for Spring Boot</description>
  14 
  15    <parent>
  16       <groupId>org.springframework.boot</groupId>
  17       <artifactId>spring-boot-starter-parent</artifactId>
  18       <version>1.5.9.RELEASE</version>
  19       <relativePath /> <!-- lookup parent from repository -->
  20    </parent>
  21 
  22    <properties>
  23       <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  24       <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  25       <java.version>1.8</java.version>
  26    </properties>
  27 
  28    <dependencies>
  29       <dependency>
  30          <groupId>org.springframework.boot</groupId>
  31          <artifactId>spring-boot-starter-jdbc</artifactId>
  32       </dependency>
  33       
  34       <dependency>
  35          <groupId>org.springframework.boot</groupId>
  36          <artifactId>spring-boot-starter-security</artifactId>
  37       </dependency>
  38       
  39       <dependency>
  40          <groupId>org.springframework.boot</groupId>
  41          <artifactId>spring-boot-starter-web</artifactId>
  42       </dependency>
  43       
  44       <dependency>
  45          <groupId>org.springframework.security.oauth</groupId>
  46          <artifactId>spring-security-oauth2</artifactId>
  47       </dependency>
  48       
  49       <dependency>
  50          <groupId>org.springframework.security</groupId>
  51          <artifactId>spring-security-jwt</artifactId>
  52       </dependency>
  53       
  54       <dependency>
  55          <groupId>com.h2database</groupId>
  56          <artifactId>h2</artifactId>
  57       </dependency>
  58       
  59       <dependency>
  60          <groupId>org.springframework.boot</groupId>
  61          <artifactId>spring-boot-starter-test</artifactId>
  62          <scope>test</scope>
  63       </dependency>
  64       
  65       <dependency>
  66          <groupId>org.springframework.security</groupId>
  67          <artifactId>spring-security-test</artifactId>
  68          <scope>test</scope>
  69       </dependency>
  70    </dependencies>
  71 
  72    <build>
  73       <plugins>
  74          <plugin>
  75             <groupId>org.springframework.boot</groupId>
  76             <artifactId>spring-boot-maven-plugin</artifactId>
  77          </plugin>
  78       </plugins>
  79    </build>
  80    
  81 </project>

get_token.sh

   1 ACCESS_TOKEN=$(curl -X POST --url http://localhost:8080/oauth/token --user tutorialspoint:my-secret-key --data 'grant_type=password&username=myemail@gmail.com&password=password' | jq -r '.access_token')
   2 echo $ACCESS_TOKEN
   3 curl -X GET http://localhost:8080/products  --header "Authorization: Bearer $ACCESS_TOKEN"

connect_container.sh

   1 docker exec -it test /bin/sh

stop_container.sh

   1 docker stop test
   2 docker rm test
  • MoinMoin Powered
  • Python Powered
  • GPL licensed
  • Valid HTML 4.01