top of page

OAuth 2.0

  • Writer: Anand Nerurkar
    Anand Nerurkar
  • May 11, 2024
  • 3 min read
ree
ree

IDP - Identity Provider which maintain user credential or user has registered on that platform.

For Ex: Google, Facebook,Linkedin


OIDC- Open ID Connect provide authentication with the help of IDP.


ree
ree
ree
ree
ree
ree
ree
ree

Authorization Code Flow

==

ree
ree
ree
ree
ree

once authenticated, consent is being asked

ree
ree
ree
ree

create auth server

create custom user details service

ree

@Service

@Transactional

public class CustomUserDetailsService implements UserDetailsService {

@Autowired

private UserRepository userRepository;

@Bean

public PasswordEncoder passwordEncoder() {

return new BCryptPasswordEncoder(11);

}

@Override

public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {

User user = userRepository.findByEmail(email);

if(user == null) {

throw new UsernameNotFoundException("No User Found");

}

return new org.springframework.security.core.userdetails.User(

user.getEmail(),

user.getPassword(),

user.isEnabled(),

true,

true,

true,

getAuthorities(List.of(user.getRole()))

);

}

private Collection<? extends GrantedAuthority> getAuthorities(List<String> roles) {

List<GrantedAuthority> authorities = new ArrayList<>();

for(String role: roles) {

authorities.add(new SimpleGrantedAuthority(role));

}

return authorities;

}

}


add configuration for auth server

===


@Configuration(proxyBeanMethods = false)

public class AuthorizationServerConfig {

@Autowired

private PasswordEncoder passwordEncoder;

@Bean

@Order(Ordered.HIGHEST_PRECEDENCE)

public SecurityFilterChain authServerSecurityFilterChain(HttpSecurity http) throws Exception {

OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);

return http.formLogin(Customizer.withDefaults()).build();

}

@Bean

public RegisteredClientRepository registeredClientRepository() {

RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())

.clientId("api-client")

.clientSecret(passwordEncoder.encode("secret"))

.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)

.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)

.authorizationGrantType(AuthorizationGrantType.PASSWORD)

.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)

.scope(OidcScopes.OPENID)

.scope("api.read")

.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())

.build();

return new InMemoryRegisteredClientRepository(registeredClient);

}

@Bean

public JWKSource<SecurityContext> jwkSource() {

RSAKey rsaKey = generateRsa();

JWKSet jwkSet = new JWKSet(rsaKey);

return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);

}

private static RSAKey generateRsa() {

KeyPair keyPair = generateRsaKey();

RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();

RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

return new RSAKey.Builder(publicKey)

.privateKey(privateKey)

.keyID(UUID.randomUUID().toString())

.build();

}

private static KeyPair generateRsaKey() {

KeyPair keyPair;

try {

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");

keyPairGenerator.initialize(2048);

keyPair = keyPairGenerator.generateKeyPair();

} catch (Exception ex) {

throw new IllegalStateException(ex);

}

return keyPair;

}

@Bean

public ProviderSettings providerSettings() {

return ProviderSettings.builder()

.build();

}

}


add defaultsecurityconfig

==

@EnableWebSecurity

public class DefaultSecurityConfig {

@Autowired

private CustomAuthenticationProvider customAuthenticationProvider;

@Bean

SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {

http.authorizeRequests(authorizeRequests ->

authorizeRequests.anyRequest().authenticated()

)

.formLogin(Customizer.withDefaults());

return http.build();

}

@Autowired

public void bindAuthenticationProvider(AuthenticationManagerBuilder authenticationManagerBuilder) {

authenticationManagerBuilder

.authenticationProvider(customAuthenticationProvider);

}

}


add custom authetication provider

===

@Service

public class CustomAuthenticationProvider implements AuthenticationProvider {

@Autowired

private CustomUserDetailsService customUserDetailsService;

@Autowired

private PasswordEncoder passwordEncoder;

@Override

public Authentication authenticate(Authentication authentication) throws AuthenticationException {

String username = authentication.getName();

String password = authentication.getCredentials().toString();

UserDetails user= customUserDetailsService.loadUserByUsername(username);

return checkPassword(user,password);

}

private Authentication checkPassword(UserDetails user, String rawPassword) {

if(passwordEncoder.matches(rawPassword, user.getPassword())) {

return new UsernamePasswordAuthenticationToken(user.getUsername(),

user.getPassword(),

user.getAuthorities());

}

else {

throw new BadCredentialsException("Bad Credentials");

}

}

@Override

public boolean supports(Class<?> authentication) {

return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);

}

}


add websecurityconfig in client side project

==

ree

ree
ree

Authorization code flow: This flow allows a client application to access protected resources like web APIs.  It’s designed for confidential applications, such as regular web applications. The app’s client secret must be securely stored on the client side. This flow is suitable for server-side web applications where the source code is not exposed publicly.

  • Client credentials flow: This is an OAuth 2.0 grant type where applications request access tokens directly without user intervention. Used when the client is also the resource owner, it authenticates the application using its client ID and secret. Suitable for server-to-server authentication, the returned access token grants access to specific, predefined scopes.

  • Resource owner password credentials: This is an OAuth 2.0 grant type in which the resource owner (typically the user) provides their service credentials (username and password) directly to the client application. The client then exchanges these credentials for an access token from the authorization server.

  • Hybrid flow: Suitable for applications that can store client secrets, this flow enables immediate access to ID tokens alongside ongoing access to refresh tokens. 

  • Device authorization flow: This flow is suitable for input-constrained devices that connect to the internet. Instead of authenticating the user directly, the device asks the user to go to a link on their computer or smartphone and authorize the device.

  • PKCE flow: An extension to the OAuth 2.0 Authorization Code flow, it is designed to enhance its security when used with public clients, like mobile applications or single-page web apps. These clients can’t reliably store client secrets.

The main difference between the authorization code flow and the client credentials flow is that the client credentials flow relies on application authorization rather than involving the user.

ree
ree
ree
ree

 
 
 

Recent Posts

See All

Comments

Rated 0 out of 5 stars.
No ratings yet

Add a rating
  • Facebook
  • Twitter
  • LinkedIn

©2024 by AeeroTech. Proudly created with Wix.com

bottom of page