OAuth 2 is an authorization framework that enables applications to obtain limited access to user accounts on an HTTP service, such as Facebook, GitHub, and DigitalOcean. It works by delegating user authentication to the service that hosts the user account, and authorizing third-party applications to access the user account. OAuth 2 provides authorization flows for web and desktop applications, and mobile devices.
OAuth2 Roles
OAuth2 provides 4 different roles.
Resource Owner: User
Client: Application
Resource Server: API
Authorization Server: API
OAuth2 Grant Types
Following are the 4 different grant types defined by OAuth2
Authorization Code: used with server-side Applications
Implicit: used with Mobile Apps or Web Applications (applications that run on the user's device)
Resource Owner Password Credentials: used with trusted Applications, such as those owned by the service itself
Client Credentials: used with Applications API access
Spring Boot OAUTH2 Project Structure
OAuth2 Authorization Server Config
This class extends AuthorizationServerConfigurerAdapter and is responsible for generating tokens specific to a client.Suppose, if a user wants to login to the project via facebook then facebook auth server will be generating tokens for the project this case, the project becomes the client which will be requesting for authorization code on behalf of user from facebook - the authorization server.
Here, JwtAccessTokenConverter is the helper that translates between JWT encoded token values and OAuth authentication information. We have added our custom signature to make the JWT token more robust.Apart from JwtTokenStore, spring security also provides InMemoryTokenStore and JdbcTokenStore.
Here, we are using in-memory credentials with client_id as maissen-client and CLIENT_SECRET as maissen-secret(bcrypted here in Spring Boot 2).But you are free to use JDBC implementation too.
@EnableAuthorizationServer: Enables an authorization server.AuthorizationServerEndpointsConfigurer defines the authorization and token endpoints and the token services.
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
static final String CLIEN_ID = "maissen-client";
//static final String CLIENT_SECRET = "maissen-secret";
static final String CLIENT_SECRET = "$2a$04$e/c1/RfsWuThaWFCrcCuJeoyvwCV0URN/6Pn9ZFlrtIWaU/vj/BfG";
static final String GRANT_TYPE_PASSWORD = "password";
static final String AUTHORIZATION_CODE = "authorization_code";
static final String REFRESH_TOKEN = "refresh_token";
static final String IMPLICIT = "implicit";
static final String SCOPE_READ = "read";
static final String SCOPE_WRITE = "write";
static final String TRUST = "trust";
static final int ACCESS_TOKEN_VALIDITY_SECONDS = 1*60*60;
static final int FREFRESH_TOKEN_VALIDITY_SECONDS = 6*60*60;
@Autowired
private AuthenticationManager authenticationManager;
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("as466gf");
return converter;
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Override
public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
configurer
.inMemory()
.withClient(CLIEN_ID)
.secret(CLIENT_SECRET)
.authorizedGrantTypes(GRANT_TYPE_PASSWORD, AUTHORIZATION_CODE, REFRESH_TOKEN, IMPLICIT )
.scopes(SCOPE_READ, SCOPE_WRITE, TRUST)
.accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS).
refreshTokenValiditySeconds(FREFRESH_TOKEN_VALIDITY_SECONDS);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.tokenStore(tokenStore())
.authenticationManager(authenticationManager)
.accessTokenConverter(accessTokenConverter());
}
}
Resource Server Config
Resource in our context is the REST API which we have exposed for the crud operation. To access these resources, the client must be authenticated. In real-time scenarios, whenever a user tries to access these resources, the user will be asked to provide his authenticity and once the user is authorized then he will be allowed to access these protected resources.
resourceId : the id for the resource (optional, but recommended and will be validated by the auth server if present). ResourceServerConfig.java
This class extends WebSecurityConfigurerAdapter and provides usual spring security configuration.Here, we are using bcrypt encoder to encode our passwords. You can try this online Bcrypt Tool to encode and match bcrypt passwords.Following configuration basically bootstraps the authorization server and resource server.
@EnableWebSecurity : Enables spring security web security support.
@EnableGlobalMethodSecurity : Support to have method level access control such as @PreAuthorize @PostAuthorize SecurityConfig.java
Below is the default script that can be used for first use. script.sql
create table user (id bigint not null auto_increment, age integer, first_name varchar(255), last_name varchar(255), password varchar(255), salary bigint, username varchar(255), primary key (id)) engine=MyISAM;
INSERT INTO user (age, first_name, last_name,password,salary,username) values (23, 'admin', 'admin','$2a$04$EZzbSqieYfe/nFWfBWt2KeCdyq0UuDEM1ycFF8HzmlVR6sbsOnw7u',12345,'admin');
Angular OAUTH2 Implementation
First we will be generating an Angular 7 app using angular cli and then create different components for create, edit, add and delete user. The step by step demonstration of creating Angular 7 app can be found in my previous article here - Angular 7 CRUD App.Below is the project structure for the same.
Below is the list of command that we have used to generate above project structure.
npm i npm@latest -g
ng new my-dream-app
cd my-dream-app
ng serve
ng g component login
ng g component add-user
ng g component edit-user
ng g component list-user
We have the similar implementation to add and edit user. The implementation is very basic and do let me for any clarification required in the comment section below:
After a successful login, list-user route will be loaded and getUsers() will be invoked that will load the list of users from the API and the user list will be shown in a tabular form. Each row will have a button to either update or delete any user entry. Add button will open a new form to add a new user. On click of the edit button, the selected user id will be cached in session storage and edit component will be loaded with user details auto populated from the DB. A click on delete button will instantly delete the user from DB and update the table. add-user.component.html
In this article, we discussed about implementing Spring Boot OAUTH2 with Angular application. We configured our authorization server and resource server using OAUTH2 and secured our REST APIs. The same REST APIs was accesses with angular client after generating JWT OAUTH token.