Secure Server-to-Server Communication with Spring Boot and OAuth 2.0

Brian Demers

Hi Rafael,
Sorry about the delay!

I’m not sure, is there anything in your log files? (Spring Security logs are intentionally sparse by default) you can increase the logging by setting logging.level.root=DEBUG (or pick a more targeted logger). that usually shows the cause of the 401.

Keep us posted!

Zenwalker …

Hey this works but not as a stand alone app and server you have provided in github.

So I developed my task based on the understanding from above article.

I am getting a token. I am using AWS cognito services for token issue.

Thanks

Matt Raible

I’m pretty sure this example works with Okta. I’m sorry it doesn’t work with AWS Cognito. Maybe you should just use Okta?! :smiley:

You can get 1000 monthly active users for free with a forever-free developer account.

Steve Pants

I keep getting compile errors for the cred server (spring-boot:run)

Is this app not compatible with Maven 3.6?

[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.0.0.RELEASE:run (default-cli) on project creds-example-server: An exception occurred while running. null: InvocationTargetException: 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 java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException: javax.xml.bind.JAXBException → [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.0.0.RELEASE:run (default-cli) on project creds-example-server: An exception occurred while running. null
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:215)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
at org.apache.maven.lifecycle… (SingleThreadedBuilder.java:56)
at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)

Rafael Braga

I’ve found the issue, it lied with the version I was using. On this page you use an older version (which is understandable since this was written 2 years ago). That version passes the “Bearer” token with a lowercase “b”. That causes the auth request to fail. Updated and voilà, it worked!

Brian Demers

Thanks for the follow up Rafael!
Updating this post for the current versions of Spring is on my TODO list!

Sara

what if we need to authorize some methods not all ? what we should do ?
using this caused
<unauthorizedexception>
<error>unauthorized</error>
<error_description>Full authentication is required to access this resource</error_description>
</unauthorizedexception>

for any end point in the application even if PreAuthorize is not added

Brian Demers

Hi Sara!
I think your question is covered in more detail in this post: https://developer.okta.com/…

But to summarize briefly, there are two places you can add access controls to your endpoints via HttpSecurity (or reactive equivalent) and with annotations. You can configure your anonymous routes in HttpSecurity. If you don’t specify any configuration it’s secured by default.

Sara

thanks for the fast response ^^ .
I tried to change the token validation end-point to my authentication server (customized one), Im having many clients , in order to make this work should I have all client id, secret added in properties file ??

another thing debugging the request when it received to my authentication server, the header is Authorization: Basic (cliendId and secret) in base 64, I though that the header would be Bearer:(with token we already have from authentication server) , is this working in this way ?

the question is having clientid and secret in prop file is a must ? it seems its used in the header when communication with authentication server for introspection.

thanks in advance

Sara

and if we need to add more than one client how we would do that in properties file ?

Brian Demers

There are a few questions here :slight_smile:

Related to “Basic” vs “Bearer”, your resource server would accept the “Bearer” token. Communication with the Authorization Server may use basic auth.

If you need to support multiple multiple clients, make sure you are using a recent version of Spring Security and add additional registration/provider configurations:
https://docs.spring.io/spri…

For example:


spring:
security:
oauth2:
client:
registration:
client-one:
client-id: okta-client-id1
client-secret: okta-client-secret1
scope: read, write
client-two:
client-id: okta-client-id2
client-secret: okta-client-secret2
scope: read, write
provider:
client-one:
authorization-uri: https://dev-1234.oktapreview.com/oauth2/v1/authorize
token-uri: https://dev-1234.oktapreview.com/oauth2/v1/token
client-two:
authorization-uri: https://dev-4321.okta.com/oauth2/v1/authorize
token-uri: https://dev-4321.okta.com/oauth2/v1/token


NOTE: I didn’t this this config, i’m just using it to illustrate client-one and client-two

Does this help?

John Hines

@disqus_u7ZhPHjjDC, I want in implement the extra credit but my Spring Boot app is at 2.3.0.RELEASE. Has the okta-spring-boot project been updated to support this version? If not, is it possible to implement the Jwt Verifier separately in it’s place? If so, how do I integrate this with this initial demo?

rajiv kumar

Hey Brain nice article.
I have few questions here? I have implemented 3 microservices (book, user and library services) where my library service is depending on book & user services for exchange of data. all these 3 services are configured with spring cloud config, eureka and zuul api-gateway(as an edge server).
and my library service uses feign clients to communicate with book & user service and also configured the hystrix fallbacks for each book & user service using respective feign client using fallback param. Now I have two questions

1) How we can configure the feign clients for security(like you did in the above example for rest template using OAuth2RestTemplate)?

2) assume if a service acts as both client & server (the service can be both resource server as well as client) then how we can do configuration

Note:- I have already configured the spring OAuth2 along with OIDC using okta at zuul api-gateway application. now I’m able to access both book & user service through edge-service without issues. but when I’m trying to do rest call using library service (if it calls either book/user service internally) then I’m getting 500 error. I have also added the UserFeignClientInterceptor inside library service but no use. here is my source code

Brian Demers

Hey @disqus_Lz5aas3YQK !
Take a look at this post: https://developer.okta.com/…
It has an example that uses Feign and configures the authentication used.

The TL;DR is you add an intercepter that adds the “Authorization” header to the outbound requests.
Let us know if this doesn’t help!

David

Hi Brian, thanks for writing this. It’s one of the clearest guides I could find on how to use client credentials in Spring Boot.

While following along, I discovered that the Spring Security OAuth project is deprecated, so your code works, but there are deprecation warnings on ClientCredentialsResourceDetails and OAuth2RestTemplate. There is a OAuth 2.0 Migration Guide which is helpful, but it doesn’t replace a good tutorial. I’m wondering if you’ve written an updated guide?

Brian Demers

Not yet, but it’s on the TODO list.
The Spring docs, cover the topic pretty good now too: https://docs.spring.io/spri…

If there is something that isn’t clear in that doc, let us know, it’s probably something we can add to the next post!

David

Thanks for replying, Brian. That documentation is very helpful, but as a beginner I do get lost in it. I started at the top with “OAuth 2.0 Client” and got lost reading class names (OAuth2AuthorizedClientRepository, OAuth2AuthorizedClientProvider, DefaultOAuth2AuthorizedClientManager) long before I reached the “Additional features” section you linked to. All of this is great for an experienced Spring dev I’ll bet, but as an experienced Java dev new to Spring, tutorials like this one are ideal.

If anyone reading my comment needs help right away, checkout the Migration Guide I linked in my top comment. In particular in links to this sample that demonstrates the client credentials grant, albeit not so clearly as Brian’s tutorial.

Luca Bonetti

Hello! I am developing a Vue frontend and a Spring Boot REST API backend. Users will get personalized data according to who they are, so I have some questions about this post (more or less):

1) Since I use okta-spring-boot-starter version 2.0.1 with spring-boot-starter-security from Spring Boot 2.4.3 as described here and in the following pages, is it still required to use clientId and clientSecret in application.properties to validate the JWT access token the frontend sends me within each request? Also, because of the Okta library, is the validation happening locally in my Spring Boot or remotely contacting Okta? At the moment, my application.properties contains okta.auth2.issuer and okta.oauth2.audience only
2) I would like to store in my backend DB something unique to represent the user that the JWT access token represents; I was thinking about the sub claim but I know it’s the email address: is it supposed to be unique, according to Okta? Should I be calling the /userinfo endpoint exposed by Okta instead?
3) I can think about the information from the previous answer to be used to store a new user after the first successful call to the API (since I assume the token is valid after local or remote validation): is this considered a good practice? Are there alternatives? What about user deletion? I won’t be notified if a user is unsubscribed from my Okta application

I know there could be much confusion in my questions but I hope they are all understandable.

Brian Demers

Hey Luca!

Great questions, I’ll try to answer all of them. It also sounds like you are NOT using the client credentials flow but instead building a “Resource Server”, where a client sends you a token, and your server validates it, either locally in the case of a JWT, or remotely per the OAuth spec.

1.) The client Id an secret are only needed if you use “opaque” tokens. For Okta’s JWT’s the issuer and audience is all you need

2.) Another great question. The “sub” claim will contain the user’s unique id if the token was created with the “openid” scope. Is it possible to change how your front end gets the token to add this scope? There are a couple of other options to get this value too, but this would be the easiest. You wouldn’t need to call the /userinfo enpoint manually. Spring Security will do that for you if you use “opaque” tokens (technically it would call the /v1/introspect, endpoint.

3.) Number three starts getting into user lifecycle. There are a few ways to handle this, a heavier solution like SCIM, or a just an event hook.

I’m not sure what type of app you are building, but, it’s often easier (and more secure) to push the authentication into the backend, then you don’t access tokens being sent from your browser at all.

Even if you don’t end up using JHipster, it might be worth messing with it, many of these concepts are baked in out of the box: https://www.youtube.com/wat…

If you still have questions can you let us a little more about your application. How does the user initially get an access token from the front end. Do you have a single API service or does that frontend use the same API token to contact a bunch of other services too?

Luca Bonetti

Thank you! Yeah, I looked at the docs better and found out my flow is the Authorization Code Flow + PKCE because the base for the application was taken from here and here. I am sorry for the confusion. I still have some questions about your reply:
1) Ok, I get it. So the example I started from does remote check with a call to the issuer URI? I will dive deeper in the article you provided but I would like to also know about that code, since I could not find this detail
2) As you can see, I started from here and so this is handled by the Okta Vue Library for me. I know i must use access tokens instead of ID ones for the Resource Server and so I was just thinking if there is something unique in this token I can use to save the user in my DB, if using the sub claim that contains the email address is considered a bad practice
3) What is SCIM? Thanks for the hooks link, will definitely take a look at them as they seem to be what I was looking for regarding user deletion

I think the overall architecture is much clearer, now. I simply took the samples and put them together, misunderstanding the flow that was used. At the moment, the frontend performs requests to Okta and uses the obtained access token to authenticate to the API service from the Spring Boot Resource Server. The API Resource Server is single, at the moment. I will also take a look at JHipster, since the project is not completely designed yet, thanks for the suggestion!