├── Oauth.pptx ├── README.md ├── pom.xml └── src └── main ├── java └── com │ └── auth │ ├── BootLauncher.java │ ├── config │ ├── AuthorizationServerConfig.java │ └── BasicSecurityConfig.java │ ├── controller │ ├── UserController.java │ └── dto │ │ └── UserDto.java │ ├── entity │ ├── AuthRole.java │ └── AuthUser.java │ ├── repository │ ├── UserRepository.java │ └── UserRoleRepo.java │ └── service │ ├── AuthUserService.java │ └── UserDetailsServiceImpl.java └── resources ├── application.yml └── data.sql /Oauth.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/github4codedebugger/OAuth-service-Springboot/95cd4839837fd4f2770d8d99c1c5431228ed53b0/Oauth.pptx -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OAuth-service-Springboot 2 | 3 | ## Register endpoint 4 | ~~~ 5 | curl --location --request POST 'http://localhost:8080/oauth/users' \ 6 | --header 'Content-Type: application/json' \ 7 | --data-raw '{ 8 | "userName": "hari", 9 | "password": "hari@123", 10 | "email": "hari.singhar@gmail.com", 11 | "mobile": "9856683254" 12 | }' 13 | 14 | ~~~ 15 | 16 | ## Generate accesstoken endpoint 17 | ~~~~ 18 | Generate Access Token: 19 | curl --location --request POST 'http://localhost:8080/oauth/token?username=hari&password=hari@123&grant_type=password' \ 20 | --header 'Authorization: Basic dGVzdDp0ZW1w' 21 | ~~~ 22 | 23 | 24 | ## Validate endpoint 25 | ~~~ 26 | curl --location --request POST 'http://localhost:8080/oauth/check_token?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1OTg5NjkyNTgsInVzZXJfbmFtZSI6ImhhcmkiLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiMjg5Mjc3MjktMjViZi00NWZmLTk5ODAtYjU1ZTM4Y2NiYzYxIiwiY2xpZW50X2lkIjoidGVzdCIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdfQ.CNjCm3h7JDNMs_CtxkgvnJOW2bhMN6oct5vQk70g7M0' \ 27 | --header 'Authorization: Basic dGVzdDp0ZW1w' 28 | ~~~ 29 | 30 | ## Get Access token from Refresh token endpoint 31 | ~~~ 32 | curl --location --request POST 'http://localhost:8080/oauth/token?grant_type=refresh_token&refresh_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJoYXJpIiwic2NvcGUiOlsicmVhZCIsIndyaXRlIl0sImF0aSI6IjA0YzIxZDQ3LTIyMTctNGYwNi04YjlkLTdiNDBkMzM2YTg5ZCIsImV4cCI6MTU5ODk3MDYwNiwiYXV0aG9yaXRpZXMiOlsiUk9MRV9VU0VSIl0sImp0aSI6IjA5YWI1MmE4LTg5YTktNDdhMy05NjNmLWM4OWFjN2Y2MzJkZiIsImNsaWVudF9pZCI6InRlc3QifQ.tg3YMrTcGXZttCetO6ORlknI5J_Q2OEK97ZYFWYr-bM' \ 33 | --header 'Authorization: Basic dGVzdDp0ZW1w' 34 | ~~~ 35 | 36 | Client Application implementation : https://youtu.be/qgLE1jx7fmk 37 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.auth 7 | auth-service 8 | 1.0-SNAPSHOT 9 | 10 | org.springframework.boot 11 | spring-boot-starter-parent 12 | 2.2.9.RELEASE 13 | 14 | 15 | 16 | 1.8 17 | 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-web 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-data-jpa 27 | 28 | 29 | mysql 30 | mysql-connector-java 31 | runtime 32 | 33 | 34 | org.projectlombok 35 | lombok 36 | provided 37 | 38 | 39 | 40 | org.springframework.security 41 | spring-security-jwt 42 | 1.0.10.RELEASE 43 | 44 | 45 | org.springframework.security.oauth.boot 46 | spring-security-oauth2-autoconfigure 47 | 2.2.9.RELEASE 48 | 49 | 50 | 51 | 52 | 53 | 54 | org.springframework.boot 55 | spring-boot-maven-plugin 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /src/main/java/com/auth/BootLauncher.java: -------------------------------------------------------------------------------- 1 | package com.auth; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class BootLauncher { 8 | public static void main(String[] args) { 9 | SpringApplication.run(BootLauncher.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/auth/config/AuthorizationServerConfig.java: -------------------------------------------------------------------------------- 1 | package com.auth.config; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.beans.factory.annotation.Value; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.context.annotation.Primary; 8 | import org.springframework.jdbc.core.JdbcTemplate; 9 | import org.springframework.security.authentication.AuthenticationManager; 10 | import org.springframework.security.core.userdetails.UserDetailsService; 11 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 12 | import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; 13 | import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; 14 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; 15 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; 16 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; 17 | import org.springframework.security.oauth2.provider.token.DefaultTokenServices; 18 | import org.springframework.security.oauth2.provider.token.TokenStore; 19 | import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore; 20 | import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; 21 | 22 | import java.util.Objects; 23 | 24 | @Configuration 25 | @EnableAuthorizationServer 26 | public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { 27 | 28 | @Autowired 29 | private AuthenticationManager authenticationManager; 30 | 31 | @Autowired 32 | private UserDetailsService userDetailsService; 33 | 34 | @Autowired 35 | private JdbcTemplate jdbcTemplate; 36 | 37 | @Value("${security.signing-key}") 38 | private String signingKey; 39 | 40 | 41 | @Override 42 | public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { 43 | JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); 44 | converter.setSigningKey(signingKey); 45 | 46 | endpoints.tokenStore(tokenStore(jdbcTemplate)) 47 | .reuseRefreshTokens(false) 48 | .accessTokenConverter(converter) 49 | .authenticationManager(authenticationManager) 50 | .userDetailsService(userDetailsService); 51 | } 52 | 53 | @Override 54 | public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception { 55 | oauthServer.tokenKeyAccess("hasAuthority('ROLE_TRUSTED_CLIENT')") 56 | .checkTokenAccess("hasAuthority('ROLE_TRUSTED_CLIENT')"); 57 | } 58 | 59 | @Override 60 | public void configure(ClientDetailsServiceConfigurer config) throws Exception { 61 | config.jdbc(jdbcTemplate.getDataSource()); 62 | } 63 | 64 | 65 | @Bean 66 | public TokenStore tokenStore(JdbcTemplate jdbcTemplate) { 67 | return new JdbcTokenStore(Objects.requireNonNull(jdbcTemplate.getDataSource())); 68 | } 69 | 70 | @Bean 71 | public BCryptPasswordEncoder passwordEncoder() { 72 | return new BCryptPasswordEncoder(); 73 | } 74 | 75 | @Bean 76 | @Primary 77 | public DefaultTokenServices tokenServices() { 78 | DefaultTokenServices defaultTokenServices = new DefaultTokenServices(); 79 | defaultTokenServices.setTokenStore(tokenStore(jdbcTemplate)); 80 | defaultTokenServices.setSupportRefreshToken(true); 81 | return defaultTokenServices; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/auth/config/BasicSecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.auth.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.authentication.AuthenticationManager; 6 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 7 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 8 | import org.springframework.security.config.http.SessionCreationPolicy; 9 | 10 | @Configuration 11 | public class BasicSecurityConfig extends WebSecurityConfigurerAdapter { 12 | 13 | @Bean 14 | @Override 15 | protected AuthenticationManager authenticationManager() throws Exception { 16 | return super.authenticationManager(); 17 | } 18 | 19 | @Override 20 | protected void configure(HttpSecurity http) throws Exception { 21 | http.csrf() 22 | .disable() 23 | .formLogin().disable() 24 | .logout().disable() 25 | .sessionManagement() 26 | .sessionCreationPolicy(SessionCreationPolicy.STATELESS) 27 | .and() 28 | .httpBasic(); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/auth/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.auth.controller; 2 | 3 | import com.auth.controller.dto.UserDto; 4 | import com.auth.entity.AuthUser; 5 | import com.auth.service.AuthUserService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.http.HttpStatus; 8 | import org.springframework.web.bind.annotation.*; 9 | 10 | @RestController 11 | @RequestMapping("/oauth/users") 12 | public class UserController { 13 | 14 | @Autowired 15 | private AuthUserService authUserService; 16 | 17 | @PostMapping 18 | @ResponseStatus(HttpStatus.CREATED) 19 | public AuthUser register(@RequestBody UserDto userDto) { 20 | return authUserService.register(userDto); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/auth/controller/dto/UserDto.java: -------------------------------------------------------------------------------- 1 | package com.auth.controller.dto; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | @Getter 7 | @Setter 8 | public class UserDto { 9 | 10 | private String userName; 11 | 12 | private String password; 13 | 14 | private String email; 15 | 16 | private String mobile; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/auth/entity/AuthRole.java: -------------------------------------------------------------------------------- 1 | package com.auth.entity; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | import javax.persistence.*; 7 | import java.io.Serializable; 8 | 9 | @Getter 10 | @Setter 11 | @Entity 12 | @Table(name = "auth_role") 13 | public class AuthRole implements Serializable { 14 | 15 | private static final long serialVersionUID = 1L; 16 | 17 | @Id 18 | @GeneratedValue(strategy = GenerationType.IDENTITY) 19 | private Long id; 20 | 21 | @Column(name = "role_name") 22 | private String roleName; 23 | 24 | @Column(name = "description") 25 | private String description; 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/auth/entity/AuthUser.java: -------------------------------------------------------------------------------- 1 | package com.auth.entity; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | import javax.persistence.*; 7 | import java.util.List; 8 | 9 | @Getter 10 | @Setter 11 | @Entity 12 | @Table(name = "auth_user") 13 | public class AuthUser { 14 | @Id 15 | @GeneratedValue(strategy = GenerationType.IDENTITY) 16 | @Column(name = "id") 17 | private Long id; 18 | 19 | private String userName; 20 | 21 | private String password; 22 | 23 | private String email; 24 | 25 | private String mobile; 26 | 27 | @ManyToMany(fetch = FetchType.EAGER) 28 | @JoinTable(name = "user_role", joinColumns 29 | = @JoinColumn(name = "user_id", 30 | referencedColumnName = "id"), 31 | inverseJoinColumns = @JoinColumn(name = "role_id", 32 | referencedColumnName = "id")) 33 | private List roles; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/auth/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.auth.repository; 2 | 3 | import com.auth.entity.AuthUser; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | import java.util.Optional; 7 | 8 | public interface UserRepository extends JpaRepository { 9 | Optional findByUserName(String username); 10 | 11 | Optional findByUserNameOrEmail(String username, String email); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/auth/repository/UserRoleRepo.java: -------------------------------------------------------------------------------- 1 | package com.auth.repository; 2 | 3 | import com.auth.entity.AuthRole; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface UserRoleRepo extends JpaRepository { 7 | AuthRole findByRoleNameContaining(String roleName); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/auth/service/AuthUserService.java: -------------------------------------------------------------------------------- 1 | package com.auth.service; 2 | 3 | import com.auth.controller.dto.UserDto; 4 | import com.auth.entity.AuthUser; 5 | import com.auth.repository.UserRepository; 6 | import com.auth.repository.UserRoleRepo; 7 | import com.fasterxml.jackson.databind.ObjectMapper; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.security.crypto.password.PasswordEncoder; 10 | import org.springframework.stereotype.Service; 11 | 12 | import java.util.Collections; 13 | import java.util.Optional; 14 | 15 | @Service 16 | public class AuthUserService { 17 | @Autowired 18 | private UserRepository userRepository; 19 | 20 | @Autowired 21 | private UserRoleRepo userRoleRepo; 22 | 23 | @Autowired 24 | private PasswordEncoder passwordEncoder; 25 | 26 | public AuthUser register(UserDto userDto) { 27 | AuthUser authUser = new ObjectMapper().convertValue(userDto, AuthUser.class); 28 | authUser.setPassword(passwordEncoder.encode(userDto.getPassword())); 29 | authUser.setRoles(Collections.singletonList(userRoleRepo.findByRoleNameContaining("USER"))); 30 | Optional optUser = userRepository.findByUserNameOrEmail(userDto.getUserName(), userDto.getEmail()); 31 | if (!optUser.isPresent()) { 32 | return userRepository.save(authUser); 33 | } 34 | throw new RuntimeException("User already exist"); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/auth/service/UserDetailsServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.auth.service; 2 | 3 | import com.auth.entity.AuthUser; 4 | import com.auth.repository.UserRepository; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.security.core.GrantedAuthority; 7 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 8 | import org.springframework.security.core.userdetails.User; 9 | import org.springframework.security.core.userdetails.UserDetails; 10 | import org.springframework.security.core.userdetails.UserDetailsService; 11 | import org.springframework.stereotype.Component; 12 | 13 | import java.util.List; 14 | import java.util.Optional; 15 | import java.util.stream.Collectors; 16 | 17 | @Component 18 | public class UserDetailsServiceImpl implements UserDetailsService { 19 | 20 | @Autowired 21 | private UserRepository userRepository; 22 | 23 | @Override 24 | public UserDetails loadUserByUsername(String userName) { 25 | // it will be called at access token generation time 26 | Optional optUser = userRepository.findByUserName(userName); 27 | if (optUser.isPresent()) { 28 | AuthUser user = optUser.get(); 29 | List authorities = user.getRoles() 30 | .stream().map(roles -> new SimpleGrantedAuthority(roles.getRoleName())) 31 | .collect(Collectors.toList()); 32 | return new User(user.getUserName(), user.getPassword(), authorities); 33 | } 34 | throw new RuntimeException("user not exist"); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | jpa: 3 | hibernate: 4 | ddl-auto: create 5 | show-sql: true 6 | properties: 7 | hibernate: 8 | dialect: org.hibernate.dialect.MySQL5Dialect 9 | datasource: 10 | url: jdbc:mysql://localhost:3306/db 11 | username: identity 12 | password: identity123 13 | initialization-mode: always 14 | security: 15 | oauth2: 16 | resource: 17 | filter-order: 3 18 | signing-key: 19 | -------------------------------------------------------------------------------- /src/main/resources/data.sql: -------------------------------------------------------------------------------- 1 | drop table if exists oauth_access_token; 2 | create table oauth_access_token( 3 | token_id VARCHAR(255), 4 | token varbinary(4096), 5 | authentication_id VARCHAR(255), 6 | user_name VARCHAR(255), 7 | client_id VARCHAR(255), 8 | authentication varbinary(4096), 9 | refresh_token VARCHAR(255) 10 | ); 11 | 12 | drop table if exists oauth_refresh_token; 13 | create table oauth_refresh_token( 14 | token_id VARCHAR(255), 15 | token varbinary(4096), 16 | authentication varbinary(4096) 17 | ); 18 | 19 | drop table if exists oauth_code; 20 | create table oauth_code( 21 | code VARCHAR(255), 22 | authentication varbinary(4096) 23 | ); 24 | 25 | drop table if exists oauth_approvals; 26 | create table oauth_approvals( 27 | userId VARCHAR(255), 28 | clientId VARCHAR(255), 29 | scope VARCHAR(255), 30 | status VARCHAR(10), 31 | expiresAt TIMESTAMP, 32 | lastModifiedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP 33 | ); 34 | 35 | drop table if exists ClientDetails; 36 | create table ClientDetails( 37 | appId VARCHAR(255) PRIMARY KEY, 38 | resourceIds VARCHAR(255), 39 | appSecret VARCHAR(255), 40 | scope VARCHAR(255), 41 | grantTypes VARCHAR(255), 42 | redirectUrl VARCHAR(255), 43 | authorities VARCHAR(255), 44 | access_token_validity INTEGER, 45 | refresh_token_validity INTEGER, 46 | additionalInformation VARCHAR(4096), 47 | autoApproveScopes VARCHAR(255) 48 | ); 49 | 50 | create index oauth_access_token_id on oauth_access_token(token_id); 51 | create index oauth_refresh_token_id on oauth_access_token(token_id); 52 | 53 | 54 | 55 | --START CLIENT CREDENTIAL TABLES-- 56 | 57 | drop table if exists oauth_client_details; 58 | create table oauth_client_details( 59 | client_id VARCHAR(256) PRIMARY KEY, 60 | resource_ids VARCHAR(256), 61 | client_secret VARCHAR(256), 62 | scope VARCHAR(256), 63 | authorized_grant_types VARCHAR(256), 64 | web_server_redirect_uri VARCHAR(256), 65 | authorities VARCHAR(256), 66 | access_token_validity INTEGER, 67 | refresh_token_validity INTEGER, 68 | additional_information VARCHAR(4096), 69 | autoapprove VARCHAR(256) 70 | ); 71 | 72 | drop table if exists oauth_client_token; 73 | create table oauth_client_token( 74 | token_id VARCHAR(255), 75 | token varbinary(4096), 76 | authentication_id VARCHAR(255), 77 | user_name VARCHAR(255), 78 | client_id VARCHAR(255) 79 | ); 80 | 81 | drop table if exists user_role; 82 | CREATE TABLE user_role ( 83 | user_id bigint(20) NOT NULL, 84 | role_id bigint(20) NOT NULL 85 | ); 86 | 87 | -- ############################################################################################# -- 88 | 89 | -- BASIC AUTH with token time declarationuser_role 90 | -- ACCESS TOKEN VALIDITY = 300 SECOND 91 | -- REFRESH TOKEN VALIDITY = 1800 SECOND 92 | -- insert client details [clientId = test & clientSecret = temp] 93 | INSERT INTO oauth_client_details 94 | (client_id, client_secret, scope, authorized_grant_types, 95 | authorities, access_token_validity, refresh_token_validity) 96 | VALUES ('test', '$2a$10$qgfrPSuoOvcoTYW1oka1r.XuQ67t9tt6erpZ4pa3/rx4Np0EF.fB6', 97 | 'read,write', 'password,refresh_token,client_credentials,authorization_code', 98 | 'ROLE_TRUSTED_CLIENT', 300, 1800); 99 | 100 | 101 | -- ##########################################################-- 102 | -- USER ROLES 103 | 104 | INSERT INTO auth_role(id, role_name, description) 105 | VALUES (1, 'ROLE_ADMIN', 'Admin User - Has permission to perform admin tasks'); 106 | 107 | INSERT INTO auth_role(id, role_name, description) 108 | VALUES (2, 'ROLE_USER', 'CONSULTANT - Has no admin rights'); 109 | --------------------------------------------------------------------------------