Setting up okta oidc for use with Spring-boot 2.3.1.RELEASE

Hello,
I’m trying to setup OIDC with existing 2.3.1.RELEASE spring boot application.
I’ve managed to create a small POC using the tutorials and with the help of Matt,

when trying to integrate it with my already existing application, I get the following error:

Caused by: java.lang.NoClassDefFoundError: org/springframework/security/oauth2/client/web/OAuth2LoginAuthenticationFilter
at org.springframework.security.config.annotation.web.builders.HttpSecurity.oauth2Login(HttpSecurity.java:2152) ~[spring-security-config-5.3.3.RELEASE.jar:5.3.3.RELEASE]
at com.morphisec.server.config.security.OktaOAuth2WebSecurityConfigurerAdapter.configure(OktaOAuth2WebSecurityConfigurerAdapter.java:17)

I’m using the following OKTA dependency :

//OKTASSO
compile(“com.okta.spring:okta-spring-boot-starter:1.4.0”)

and the function is pretty basic as showed in tutorial:

@Configuration
class OktaOAuth2WebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
    // all routes protected
    http.authorizeRequests()
            .anyRequest().authenticated()
            // enable OAuth2/OIDC
            .and()
            .oauth2Login();<---- pointing to this line
   }
}

as for my application.yml file it looks like this :

okta:
oauth2:
issuer: https://dev-49353516.okta.com/oauth2/default
client-id: XXXXXXXXXXXXXX
client-secret: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
redirect-uri: /authorization-code/callback

any help would be greatly appreciated :slight_smile:
Thanks a lot
Majd

Hey @Majdma!

I took a quick look and that NotFoundException is related to a class that was added in Spring Security 5.0 (which was a while ago). So my guess is there might be some sort of other dependency issue.

Can you get us your dependency tree (you can strip out any artifacts from your company, but leave a place-holder for them). IIRC, for gradle, you can run something like gradle dependencies.

My guess is your missing spring-security-oauth2-client for some reason.
https://search.maven.org/artifact/org.springframework.security/spring-security-oauth2-client

You can also try adding that dependency to your project (just match your spring-security version 5.3.3.RELEASE, as these versions do NOT correspond to Spring Boot versions).

If there is nothing obvious there a copy of your build.gradle (or the relevant dependency and plugin sections would be helpful)

Keep us posted!
-Brian

Hey @bdemers !

you are correct, after making sure I have all of the suitable dependencies I don’t get this error anymore,
but I’m facing another issue now, when i run the application and go to the login URI,
I get the link to login using OKTA, but when i press on it i get the following error :

400 Bad Request

Identity Provider: Unknown

Error Code: invalid_request

Description: The ‘redirect_uri’ parameter must be a Login redirect URI in the client app settings: https://dev-49353516-admin.okta.com/admin/app/oidc_client/instance/0oauh0ki72iV0nGYX5d6#tab-general

in my application i have the following settings in the application.yml properties file:

okta:
oauth2:
issuer: https://dev-49353516.okta.com/oauth2/default
client-id: XXXXXXXXXXXXXX
client-secret: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
redirect-uri: /authorization-code/callback

and inside the application settings inside okta’s admin page i have the following :

in the POC i did before, it worked with the same settings, what am I missing here ?
Thanks again :slight_smile: really appreciate it
-Majd

Edit:

the login page with the page link and the hover link showed at the bottom

I tried manipulating the redirect Uri, with https and with http, localhost and local IP, still couldn’t reach a good point

Edit 2

it works :slight_smile: , when i used https://XX.XXX.XX.40/login/oauth2/code/okta as the redirect URI.
which is great news, after logging in successfully from okta’s login page, the redirect back is to
/authorization-code/callback how do i catch the user from there (authenticate and authorize) ? and redirect him to the proper dashboard ?

I have some other
@ Override
configure(HttpSecurity http)

in another class called SecurityConfiguration,
I followed the examples in site and I created a class OktaOAuth2WebSecurityConfigurerAdapter that also implement this method, here is the class:

@Configuration
class OktaOAuth2WebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
    protected void configure(HttpSecurity http) throws Exception {
        // all routes protected
        http.authorizeRequests()
                .anyRequest().authenticated()
                // enable OAuth2/OIDC
                .and()
                .oauth2Login();
    }
}

but when i remove this class and try to add the

.and()
.oauth2Login();

part to other configure method, im not getting the same result, and even the login link doesn’t work anymore, is there something that I’m missing ?

Thanks a lot, much appreciated
Majd

Hey @Majdma!

I’m having trouble following what worked and what didn’t, and you had two different servers? Maybe start from the top again, and let us know where you are seeing a problem (on the Okta side, or on the Spring side?)

It also sounds like there is a little confusion around the redirectUri. This value defaults to /login/oauth2/code/okta. You can change this by setting: okta.oauth2.redirect-uri
Either way, the “Sign-in redirect URIs” from your screenshot above MUST be an absolute URL that that matches this path. So the easiset option is to leave that property unset, and configure your Okta application (via the Okta admin console) to be https:<your-host>/login/oauth2/code/okta

Any unauthorized request should save the current request URL in the user’s session, automatically redirect you to /login/oauth2/code/okta, which will redirect you to Okta (the user logs in), and you get redirected back to /login/oauth2/code/okta, Spring Security will then finish the OAuth flow automatically, and redirect the user back to the original saved request URL.

So if you open up your browser’s network log (and preserve traffic), you might see something like:

GET → https://my-host/foobar - 302 /login/oauth2/code/okta
GET → https://my-host/login/oauth2/code/okta - 302 - https://dev-49353516.okta.com/…?..&redirect_uri=https://my-host/login/oauth2/code/okta&…
(other requests for user to log in) → 302 - https://my-host/login/oauth2/code/okta?.
GET → https://my-host/login/oauth2/code/okta - 302 https://my-host/foobar

Something like that anyway (from memory, so it might not be 100% correct)

Also note, if you have a custom WebSecurityConfigurerAdapter that does NOT contain .oauth2Login(), Spring will not configure the oauth login. By default, Spring Security defines a WebSecurityConfigurerAdapter that looks very similar to what you have in your example.

Hey @bdemers

Sorry for the too many edits, maybe that made it confusing.
I do already have Multiple security configurations

I had a regular Login Page at /Login
with a form, that uses JWT after authenticating.
okta login form

now after adding all of the stuff of the Okta Integration,
I’ve added another WebSecurityConfigurerAdapter, the most basic one of the OKTA dev tutorial.
as shown above (with some edits) :

@Order(4)
@Configuration
class OktaOAuth2WebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // all routes protected
        http
                .authorizeRequests()
                .antMatchers("/","/login**").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/login")
                .and()
                .oauth2Login();
    }
}

but now I can’t sign in using either way. if I try to login using normal user/pass method, i get 401 for all endpoints, and if I use okta, I also get 401 unauthorized for all endpoints as well,
Can i add the okta webSecurityConfiguration for the exisiting one ?
and are they conflicting and that is the reason why i’m getting the 401 ?

my question is how can i make them live together ? can i add the OKTA security configs to the current one, or should i create it by it’s own and do something with it?

Thanks a lot,
Majd

I’m not sure I fully understand what you mean by:

I had a regular Login Page at /Login
with a form, that uses JWT after authenticating.

Which pages return a 401?

What do your other WebSecurityConfigurerAdapter look like?
(those could be adding other Servlet Filters in front of the filter that handles the OAuth logic)
In general, having multiple adapters should be fine, but you may need to debug them a bit.

Spring Security’s logs are intentionally sparse by default. You can turn this up by adding the following bit of YAML to your application.yml:

logging:
  level:
    org:
      springframework:
        security: DEBUG

If that doesn’t help, I’d suggest creating a simple application to reproduce the issue. Start with the WebSecurityConfigurerAdapter in this post, and then layer in your others, one at a time, until you see the problem. If possible stick that on GitHub (or similar) and point us to it and we might be able to see what is going on.

Keep us posted!

hello @bdemers,
thanks a lot for helping me with everything.

I’ve managed to gain access to the API endpoints with Okta, login.
1- I receive back a session cookie and its saved in the browser, and then i can use it to create requests to the API endpoints, can i get a JWT token instead ?

2- somehow I have to choose at the beginning what WebSecurityConfigurerAdapter i’m going to use, because if i set the okta’s settings in the application.yml file then an Oauth2AuthorizationFilter works and it breaks the normal login flow, and if I remove the Okta’s setting from the application.yml file then i can login regularly (DB auth) but i don’t have the Okta’s capabilities.
is there a way to to turn this filter off ? if I want to have a normal login and Okta’s login together ?

3- My UI is angular, and when i try to reach pages in the application itself, it doesn’t seem to work, but i can reach the api endpoints ( controllers) with the session cookie, and I want to still keep the normal login flow with the bearer token, and also support okta. do you recommend that i change the session cookie somehow to a jwt ? or to make my angular UI work with the session cookie itself ? we already have interceptors and use bearer token authentication to bring the static resources from the backend (spring boot)

as for the questions:
trying to reach /dashboard page after authentication with okta, and i cant reach that and it return 401.
if i sign in from the form and if i sign in from the okta login.

and also the Oauth2Auth filter works even if i try to login from the regular (DB auth) login which breaks the flow.

thanks a lot
Majd

Hi @Majdma!

I didn’t realize you were trying to use .oauth2Login() and a login mechanism from a custom hosted login page. These two things are usually incompatible (you can technically do it, but it’s not recommended).

Generally speaking, the most secure option is to handle all authentication on the back end of your application and redirect to an OAuth IdP (like Okta), when needed. The easiest way to think about it is if you use a “Login with GitHub” or “Login with Google” option. On the Okta side, you can use a custom domain and theme the page as needed (so your users are redirected to something like accounts.example.com). From here your front end can communicate with the backend using standard cookies. As a bonus, both your frontend and backend work the same way if you still have a need for a user/password form.

All that said, I think the root of your problem might be that you are configuring your backend as .oauth2Login() (which means it sets up an OAuth 2 Authorization Code Flow, that’s the OAuth redirect), but also some custom bearer token authentication? This last part is what I’m unclear on, the easiest way to configure a Resource Server (basically API that handles a Bearer token), is to configure your WebSecurityConfigurerAdapter with .oauth2ResourceServer().jwt()

The resource server is typically stateless, while the oauth2Login() is not. You can enable them both to support multiple types of clients:

...
    .oauth2Login()
        .and()
    .oauth2ResourceServer().jwt();

I’m not sure if this answers your question or helps, but let me know and I’ll try to give a more focused answer!

hello @bdemers ,
Thanks for the response, I will try to make my self as clear as possible and describe all the the system and all of problems I’m facing.

Technologies:
SPRING boot 2.3.9.RELEASE as a back-end server (that also serves resources and redirections) using
compile(“com.okta.spring:okta-spring-boot-starter:1.4.0”)
Angular 9 as Front End consuming “@okta/okta-angular”: “^3.1.0”,

tried to follow this guide (Build a CRUD App with Angular 9 and Spring Boot 2.2) but at the angular side we are always getting false for the" this.oktaAuth.isAuthenticated() " and we added all of the IP’s as trusted origins, and redirect URL’s in the Okta application page, and the Okta security API page as well.
and also once we connect from the link from the UI for the SPA Application inside of okta’s admin page, we get back a cookie and not a token, can i make Okta return me a JWT token instead of the cookie that it sets in the browser.

another question, if i have two applications inside the okta’s admin page, SPA app for the angular UI and Web app for the spring boot back end, how do they know that they are compatible? via the issuer ?

The flow for the Regular DB login:
1- enter user/pass from the custom Login page ( angular )
2- send user/pass basic auth to back end and get a jwt token
3- webconfigurerAdapter for handling permissions and apply filters that checks the JWT
4- UI saves token and attach it to each request from the UI to the backend
5- filter checks ROLE and JWT and allow access to the required resource

the flow that we want for OKTA login
1- press a button to sso via okta from the same custom login page (under the user and pass form)
2- redirect to okta login page or via a pop up window ( doesn’t really matter for now )
3- after authenticating the user in okta, we will redirect the user back to the application’s Dashboard.( preferably with a jwt in the response after authenticating the user)
4- enable all requests to the back end from the UI using the jwt, or the cookie

My current Okta web configurer Adapter

i prefer i cant get a jwt so it would be stateless as well and i can use my other webAdapter that i'm using for the DB login

Override
protected void configure(HttpSecurity http) throws Exception {
// all routes protected
http
                .and()     
                .requestMatchers()
                .and()
                .authorizeRequests()
                .antMatchers("/","/login**").permitAll()
                .and()
                .oauth2ResourceServer().jwt();

Current Flow of things :
we go to the UI login page, and we have the normal login form, that is not working any more because the Oauth2AuthorizationFilter is somehow always activated by the okta settings in application.yml

and we have 2 buttons for SSO (Need one, but need to make it work),
1- one is for the okta login from the SPRING side, when authenticating i get back a cookie saved in Jseesion id, and when I do a request to the backEnd rest controllers using the same browser, i can get responses, but i cant reach any of the UI pages with it.
example : i can reach host:port/api/users
but i can’t reach host:port/dashboard.

2- one from the Angular side (as shown in the guide) it redirects me to the Okta Login page, i do login using the Okta account, but then if I check this.oktaAuth.isAuthenticated() I always get false for some reason, It would really be great if i can get a jwt response from okta’s side when i login if possible, and then i can use this JWT to comunicate with the backend and also get the UI resources.
after logging in and checking the oktaAuth object from the Angular side i have the following :

Even if I use

.and()
    .oauth2ResourceServer().jwt();

instead of oauth2login() I’m still somehow getting redirected to the okta webapp login okta’s page.

this is exactly what I need. but preferably using JWT that i can get to my frontEnd and use it communicate with the backend.

an example of the Form I would like to have :

I really appreciate all of your help
Thanks a lot
Majd

My general advice is to NOT use JWTs as a session replacement, mainly for the reason a user cannot log out.
You need to wait for the token to expire, and there are some other potential issues with exposing your token to the client-side code. If instead your user/password frontend also use cookies, these potential concerns go away.

On to your actual question. I’m not sure I can answer your Angular question, but I’m guessing you are missing a callback. We have another Angluar example as well.

There is also a basic html/js login page, that will get your browser a JWT access token. (I’d still recommend using the Angular option though)

From there you could treat your Spring backend as a Resource Server.

My advice about using a session does mean that if you have a cluster of servers you need to deal with some sort of session store, either sticky sessions or using Spring Session.

Let us know if you have any other questions!

hey @bdemers
great help, I’ve managed to advance in the integration.
Thanks for the help,

Now i do have the token from the UI side after logging in with okta,
and i try to send this bearer token inside the auth header of the requests to the back end, and make the backend act as a resource server, but i get an 401 unauthorized error: that states the following.

WWW-Authenticate: Bearer error=“invalid_token”, error_description=“An error occurred while attempting to decode the Jwt: This aud claim is not equal to the configured aud
ience”, error_uri=“RFC 6750 - The OAuth 2.0 Authorization Framework: Bearer Token Usage

the UI has it’s own spa application in okta admins page.
the BE has it’s own webApplication in okta admins page.

each one has the clientId of it’s application as it’s audience field.

when i check the token i have i can see that i have the UI app clients id as the aud feild.
and that makes it not work with the back-end.

as written in Matts Guide : (Build a CRUD App with Angular 9 and Spring Boot 2.2)

Because you selected Okta as a dependency, you’ll need to create an OIDC app for it to authenticate with Okta. You could use the client ID from your Angular app, but if you ever want to allow people to log in to your Spring Boot app, it’ll need its own OIDC app.

how can i use the same Client Id from the angular app ?
or make both applications in Okta have the same Audience.

thanks for the help :slight_smile:
I really do appreciate all of the help
Majd