Build a Web App with Spring Boot and Spring Security 15 Minutes

Build a Web App with Spring Boot and Spring Security 15 Minutes

In this tutorial, you’re going to use Spring Boot to build a simple web application with a user registration system and a login system.

Fabio Ebner

Did u have a sample to how can I security my springboot-rest-api with okta and access that api from a client (in my case a vue js) tks

Felix Friedman - IQ-C

Andrew, great post. With this approach, how do we change the default login uri (/login), error URI (/error), authenticationSuccess URI? Also how should logout be handled?

Matt Raible

Yes, please see Bootiful Development with Spring Boot and Vue.

Brian Demers

Hey Felix!
Most of the official Spring documentation describes how to use Spring Boot 2.1’s OAuth support. If you are on 2.1, take a look at: https://github.com/okta/sam…

If you are on 1.5
For logout:
https://github.com/okta/sam…
ain/java/com/okta/spring/example/CodeFlowExampleApplication…#L64

Configuring the login path:
"security.oauth2.sso.loginPath = /authorization-code/callback"

https://github.com/okta/sam…

Does that help?

Felix Friedman - IQ-C

Thank you for the quick response. We are on Spring Boot 2.1. The security.oauth2.sso.loginPath configuration parameter works. Thank you so much.
The Spring Boot 2.1 example you’re referring to however, doesn’t seem to be using the @EnableOAuth2Sso annotation that is shown in this example. It would be great to also be able to provide authentication success url and authentication failure URLs. I haven’t been able to find a reference on how to do it with @EnableOAuth2Sso annotation. Also haven’t been able to find a recommendation for how to handle logout.

Brian Demers

The OAuth library Spring Security uses changed recently. (@EnableOAuth2Sso is not in the new package). We are working on writing updated blog posts.)

Until then take a look at the samples let us know!

Felix Friedman - IQ-C

Thank you Brian. Not sure what you mean by @EnableOAuth2Sso is not in the new package. Which package are you referring to?
For the time being, I’m able to use the default configuration for authentication success. Will be on the lookout for the updated blog.

Brian Demers

This link has a little more info https://docs.spring.io/spri…

Felix Friedman - IQ-C

Thank you Brian. It’s a really good reference. The discussion on /error sheds more light. Seems like the suggestion is to basically open access to it, which doesn’t seem ideal for us. Ideally would want to do some kind of custom processing such as redirecting back to login screen with some kind of an error.
I’m not seeing anything about authentication success url settings.

Brian Demers

Take a look at: HttpSecurity.oauth2Login().successHandler() and HttpSecurity.oauth2Login().failureHandler()

Felix Friedman - IQ-C

Thank you Brian. I added HttpSecurity.oauth2Login().successHandler(successHandler()). I have a successHandler Bean defined in our project. However it results in following error on startup:


APPLICATION FAILED TO START

Description:

Method springSecurityFilterChain in org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration required a bean of type ‘org.springframework.security.oauth2.client.registration.ClientRegistrationRepository’ that could not be found.

The following candidates were found but could not be injected:
- Bean method ‘clientRegistrationRepository’ in ‘OAuth2ClientRegistrationRepositoryConfiguration’ not loaded because OAuth2 Clients Configured Condition registered clients is not available

Action:

Consider revisiting the entries above or defining a bean of type ‘org.springframework.security.oauth2.client.registration.ClientRegistrationRepository’ in your configuration.

""2019-01-14 09:40:51 [Catalina-startStop-1] ERROR o.apache.catalina.core.ContainerBase - A child container failed during start
"java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/strserver]]
at java.util.concurrent.Future…(Unknown Source)
at java.util.concurrent.FutureTask.get(Unknown Source)
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:939)
at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:872)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1419)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409)
at java.util.concurrent.Future…(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/strserver]]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:167)
… 6 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘springSecurityFilterChain’ defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method ‘springSecurityFilterChain’ threw exception; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type ‘org.springframework.security.oauth2.client.registration.ClientRegistrationRepository’ available
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:627)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:456)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBean…:1288)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBean…:1127)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBean…:538)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBean…:498)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistr…:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:307)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory…:846)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext…:863)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext…:546)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplication…:142)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
at org.springframework.boot.Sp…(SpringApplication.java:316)
at org.springframework.boot.we…(SpringBootServletInitialize…:157)
at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitialize…:137)
at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.onStartup(SpringBootServletInitialize…:91)
at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerIniti…:171)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5196)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
… 6 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method ‘springSecurityFilterChain’ threw exception; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type ‘org.springframework.security.oauth2.client.registration.ClientRegistrationRepository’ available
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy…:185)
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:622)
… 30 common frames omitted
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type ‘org.springframework.security.oauth2.client.registration.ClientRegistrationRepository’ available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory…:343)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory…:335)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext…:1101)
at org.springframework.security.config.annotation.web.configurers.oauth2.client.OAuth2ClientConfigurerUtils.getClientRegistrationRepositoryBean(OAuth2ClientConfigurerUtils…:53)
at org.springframework.security.config.annotation.web.configurers.oauth2.client.OAuth2ClientConfigurerUtils.getClientRegistrationRepository(OAuth2ClientConfigurerUtils…:46)
at org.springframework.security.config.annotation.web.configurers.oauth2.client.OAuth2LoginConfigurer.init(OAuth2LoginConfigurer.java:427)
at org.springframework.security.config.annotation.web.configurers.oauth2.client.OAuth2LoginConfigurer.init(OAuth2LoginConfigurer.java:132)
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.init(AbstractConfiguredSecurityB…:371)
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.doBuild(AbstractConfiguredSecurityB…:325)
at org.springframework.securit…(AbstractSecurityBuilder.java:41)
at org.springframework.security.config.annotation.web.builders.WebSecurity.performBuild(WebSecurity.java:294)
at org.springframework.security.config.annotation.web.builders.WebSecurity.performBuild(WebSecurity.java:79)
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.doBuild(AbstractConfiguredSecurityB…:334)
at org.springframework.securit…(AbstractSecurityBuilder.java:41)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration.springSecurityFilterChain(WebSecurityConfiguration.java:104)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$6461f3b4.CGLIB$springSecurityFilterChain$5(<generated>)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$6461f3b4$$FastClassBySpringCGLIB$$d5f2a303.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer…:363)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$6461f3b4.springSecurityFilterChain(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy…:154)
… 31 common frames omitted
"2019-01-14 09:40:51 [main] ERROR o.apache.catalina.core.ContainerBase - A child container failed during start
"java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost]]
at java.util.concurrent.Future…(Unknown Source)
at java.util.concurrent.FutureTask.get(Unknown Source)
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:939)
at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:262)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.StandardService.startInternal(StandardService.java:422)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:793)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.startup.Catalina.start(Catalina.java:670)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:353)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:493)
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost]]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:167)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1419)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409)
at java.util.concurrent.Future…(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: org.apache.catalina.LifecycleException: A child container failed during start
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:947)
at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:872)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
… 6 common frames omitted
"2019-01-14 09:40:51 [main] ERROR org.apache.catalina.startup.Catalina - The required Server component failed to start so Tomcat is unable to start.
"org.apache.catalina.LifecycleException: Failed to start component [StandardServer[8005]]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:167)
at org.apache.catalina.startup.Catalina.start(Catalina.java:670)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:353)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:493)
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardService[Catalina]]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:167)
at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:793)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
… 7 common frames omitted
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina]]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:167)
at org.apache.catalina.core.StandardService.startInternal(StandardService.java:422)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
… 9 common frames omitted
Caused by: org.apache.catalina.LifecycleException: A child container failed during start
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:947)
at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:262)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
… 11 common frames omitted

Mark Norman

Okta documentation for validating Okta access tokens recommends verifying a token’s signature. This blog entry does not appear to implement Okta’s recommendation. Do you know if the Okta spring boot starter handles signature verification? I could not answer that question after my first pass through their GitHub repo.

Brian Demers

It follows Okta’s validation requirements. But this is propbably something we should highlight in the Readme, as this adds additional “claim” validation to the default Spring Security implementation.

abcd

@disqus_KFqipLUsW6:disqus is it true that we have to modify this application to validate the JWT. Based on the link you shared, we either have to cache the key to see if token signature is valid or use the remote okta call to achieve the same?
@Andrew is my understanding correct?

Brian Demers

Okta’s libraries handle the validation for you, the “validating Okta access tokens” guide documents how to do this outside of one of our connivance libraries.

Deepak Vengatesh

How to handle expired JWT error (com.nimbusds.jwt.proc.BadJWTException: Expired JWT)? Grant type refresh token is enabled. Looking for options to implement refresh token flow to solve this issue. I’m using com.okta.spring:okta-spring-boot-starter:0.6.0 , com.okta.jwt:okta-jwt-verifier:0.3.0 , springBootVersion = ‘2.1.2.RELEASE’ . Kindly suggest a solution or some document to look into specific to the above mentioned versions.

srinivas kucherla

I followed this blog, but when i log into okta login , i am not getting prinicpal back , hence blank values. any help is a big help

Brian Demers

Hey @srinivaskucherla!

Have you tried the updated post listed in the header of the page? There have been a number of improvements on both the Spring Security side, and Okta since this was originally published.

srinivas kucherla

can you share the post please ?