Get Started with Spring Boot, OAuth 2.0, and Okta

Nishant

Sure let me try your example then. Thanks matt :slight_smile:

Nishant

Hi Matt, We can see that @EnableOAuth2Sso is removed from spring-security-oauth2-autoconfigure:2.0.1.RELEASE. So do we have any alternate for this? As I want to implement Okta with OIDC for Spring boot 2.0.0 or greater version.

Matt Raible

@EnableOAuth2Sso is included in spring-security-oauth2-autoconfigure:2.0.1.RELEASE. What makes you think it’s not?


jar xvf spring-security-oauth2-autoconfigure-2.0.1.RELEASE.jar | grep EnableOAuth2Sso
inflated: org/springframework/boot/autoconfigure/security/oauth2/client/EnableOAuth2SsoCondition.class
inflated: org/springframework/boot/autoconfigure/security/oauth2/client/EnableOAuth2Sso.class

Nishant

You are correct matt. I was referring some other pom entry. :slight_smile:

Nishant

Hi Matt,
How to handle accessDenied exception (HttpClientErrorException: 404 Not Found) for users who are not in Group assigned to application created in Okta?

Matt Raible

I don’t know. I haven’t encountered this issue in any of the example applications I’ve written. I’d suggest posting your question to Stack Overflow with the code you’re using. Make sure to tag it with “spring-security” and “oauth” tags too.

Nishant

Ohk Matt. I have opened a case in okta support.

Sram

Nice one, however, it appears that to make the authentication scale, one might add in typical enterprise environments the following:

1 - token translation end point (optional ) if required to allow opaque token for untrusted clients
2 - have the tokens cached and add session concept if required
3 - verify JWT typically happens at protected resources like to-be micro services etc.,
4 - API gateway shall negotiate the OAUTH dance for access tokens that is shown above

Brian Demers

Hey @disqus_H8vaWXp4hL:disqus

IIRC, you can configure Exception handling in HttpSecurity or use @ControllerAdvice (depending on the exception)

It looks like this Baeldung post covers it: https://www.baeldung.com/ex…

Amol Jadhav

Hi Matt,
is it possible to have our own login page instead of Okta ?

Brian Demers

It is!
There are a couple different ways to do this:

1.) Setup a “custom domain” for your Okta Org like <a href="http://id.example.com" rel="nofollow noopener" title="id.example.com">id.example.com</a> (recommended): https://developer.okta.com/…
(then customize this page through your Okta admin console)

2.) Host your own login page: https://github.com/okta/sam…
The second option isn’t ideal from a pure OAuth perspective, but gives you a lot of customization.

Amol Jadhav

Thank you Brian. your blogs are very helpful. One more question I have, in case of mobile app(first-party as well as thir party) it is recommended to use auth code flow with PKCE. But my understanding is this flow is possible only with browser based redirection.
if I don’t want to redirect to browser still is it possible to implement PKCE flow ?
or do you suggest to go with ROPC flow ?

Brian Demers

There are a lot of questions packed into this :slight_smile:
The latest draft spec of the OAuth Best Practices, says to NOT use ROPC
https://tools.ietf.org/html…

Okta has an Authentication API (authn) which can be used for migration cases and situations where a redirect cannot be used (we have mobile SDKs for this too). This option is NOT OAuth, but Okta provides an OAuth extension where you can exchange an Authn session token for an OAuth access token (when needed).

Of course, in general, I’d usually recommend a the auth code flow with PKCE. In general it usually less work to implement and contains less risk (i.e. your application never touches the user’s credentials).

John Ruggentaler

I got helloWorld.groovy to run and login without issue but helloOAuth.groovy won’t start. It’s unable to initialize bean ‘scopedTarget.oauth2ClientContext’. See output below. Is this caused by incompatible Spring Boot version? Is there a workaround or fix? Yes I did notice “Heads up… this blog post is old!” at the top of the post but I am working on using Okta in my Grails app written in Groovy and was trying to find a working example of Okta authentication that I am familiar with…


spring run helloOAuth.groovy
. ____ _ __ _
/\ / __ _ () __ __ _ \ \ \ <br>( ( )_
| '_ | '| | ’ / ` | \ \ \ <br>\/ )| |)| | | | | || (| | ) ) ) )
’ |
| .__|| ||| |_, | / / / /
=========|
|==============|/=//// :: Spring Boot :: (v2.5.0)

2021-06-10 13:00:05.744 INFO 25130 — [ runner-0] o.s.boot.SpringApplication : Starting application using Java 1.8.0_232 on JRMBP.lan with PID 25130 (started by jr in /Users/jr/dev/Spring/okta-oauth2-example)
2021-06-10 13:00:05.751 INFO 25130 — [ runner-0] o.s.boot.SpringApplication : No active profile set, falling back to default profiles: default
2021-06-10 13:00:05.851 WARN 25130 — [kground-preinit] o.s.h.c.j.Jackson2ObjectMapperBuilder : For Jackson Kotlin classes support please add “com.fasterxml.jackson.module:jackson-module-kotlin” to the classpath
2021-06-10 13:00:06.490 WARN 25130 — [ runner-0] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name ‘scopedTarget.oauth2ClientContext’ defined in class path resource [org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2RestOperationsConfiguration$SessionScopedConfiguration$ClientContextConfiguration.class]: Cannot register bean definition [Root bean: class [null]; scope=session; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=false; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2RestOperationsConfiguration$SessionScopedConfiguration$ClientContextConfiguration; factoryMethodName=oauth2ClientContext; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2RestOperationsConfiguration$SessionScopedConfiguration$ClientContextConfiguration.class]] for bean ‘scopedTarget.oauth2ClientContext’: There is already [Root bean: class [null]; scope=session; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=false; primary=false; factoryBeanName=org.springframework.security.oauth2.config.annotation.web.configuration.OAuth2ClientConfiguration$OAuth2ClientContextConfiguration; factoryMethodName=oauth2ClientContext; initMethodName=null; destroyMethodName=(inferred); defined in org.springframework.security.oauth2.config.annotation.web.configuration.OAuth2ClientConfiguration$OAuth2ClientContextConfiguration] bound.
2021-06-10 13:00:06.500 INFO 25130 — [ runner-0] ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with ‘debug’ enabled.
2021-06-10 13:00:06.520 ERROR 25130 — [ runner-0] o.s.b.d.LoggingFailureAnalysisReporter :


APPLICATION FAILED TO START

Description:

The bean ‘scopedTarget.oauth2ClientContext’, defined in class path resource [org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2RestOperationsConfiguration$SessionScopedConfiguration$ClientContextConfiguration.class], could not be registered. A bean with that name has already been defined in org.springframework.security.oauth2.config.annotation.web.configuration.OAuth2ClientConfiguration$OAuth2ClientContextConfiguration and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.cli.app.SpringApplicationLauncher.launch(SpringApplicationLauncher.java:68)
at org.springframework.boot.cli.command.run.SpringApplicationRunner$RunThread.run(SpringApplicationRunner.java:168)
Caused by: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name ‘scopedTarget.oauth2ClientContext’ defined in class path resource [org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2RestOperationsConfiguration$SessionScopedConfiguration$ClientContextConfiguration.class]: Cannot register bean definition [Root bean: class [null]; scope=session; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=false; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2RestOperationsConfiguration$SessionScopedConfiguration$ClientContextConfiguration; factoryMethodName=oauth2ClientContext; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2RestOperationsConfiguration$SessionScopedConfiguration$ClientContextConfiguration.class]] for bean ‘scopedTarget.oauth2ClientContext’: There is already [Root bean: class [null]; scope=session; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=false; primary=false; factoryBeanName=org.springframework.security.oauth2.config.annotation.web.configuration.OAuth2ClientConfiguration$OAuth2ClientContextConfiguration; factoryMethodName=oauth2ClientContext; initMethodName=null; destroyMethodName=(inferred); defined in org.springframework.security.oauth2.config.annotation.web.configuration.OAuth2ClientConfiguration$OAuth2ClientContextConfiguration] bound.
at org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition(DefaultListableBeanFactory.java:995)
at org.springframework.aop.scope.ScopedProxyUtils.createScopedProxy(ScopedProxyUtils.java:92)
at org.springframework.context.annotation.ScopedProxyCreator.createScopedProxy(ScopedProxyCreator.java:40)
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod(ConfigurationClassBeanDefinitionReader.java:284)
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:153)
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:129)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:343)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:247)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:311)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:112)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:746)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:564)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:438)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:337)
… 6 more