Integrate Stytch with Spring Security

Hi,
I’m surprised to see no entry for Java/Spring/Kotlin.
Anyhow, has anybody integrated Stytch with Spring Security?

Hey Ben – thanks for posting!

It’s relatively new, but we do actually offer a Java/ Kotlin SDK. Here are links to a Java example app and a Kotlin example app that you may find useful as well!

Regarding Spring Security, I’m not personally aware of any integrations currently using this, but it looks like there may be a way to integrate with Stytch using Spring Security’s JWT Resource Server.

It looks like Spring provides a way to set a JWKS URI, which you should be able to point at our JWKS endpoint.

Please let us know if you have any additional questions, and we’ll be happy to help! We’d also love to hear how that goes if you end up trying it out.

1 Like

Hey Nicole

Looking further into this, Spring Boot provides a library which contains JWT Resource Server dependencies to OAuth (as you posted in the link).

I’m though not sure how a OAuth based JWT resource server can hand out tokens if the user isn’t using OAuth to authenticate… Say the user uses a simple email (magic link) to sign up (using Stytch as an external authentication provider). How is this going to allow him to use OAuth for future use with a OAuth JWT resource server?

Hey Ben! My understanding is that Spring can use Stytch’s JWKS endpoint to retrieve the JWKS for your project, which it can then use to authorize requests that include a Stytch-issued JWT.

Stytch issues JWTs during every successful user authentication, regardless of which product the user used to authenticate. For example, we do return a JWT in response to our OAuth authenticate endpoint, but we also return a JWT in response to our Magic Links authenticate endpoint (and every other /authenticate endpoint).

My understanding is that Stytch would essentially act as the authorization server in this case, minting JWTs and providing the JWKS to validate them.

That said, I could certainly be mistaken about how this Spring Security feature works, as it’s not something that we’ve implemented ourselves. There may be implementation details that prevent Stytch’s JWTs and Spring Security from being compatible.

Until we try this out ourselves, we can’t guarantee that it will work as expected – but I’ve seen some interest internally about potentially creating a Spring Boot example app in the future, and I’ll +1 that on your behalf!

Please let us know if you have any additional questions that we can help out with in the meantime.

Nicole,

That makes a lot of sense - thank you!

I’ve been already working on a Spring Boot / Security integration over the weekend and I’m willing to share my code once it’s all said and done. I was just confused as to how OAuth and Magic Link users get married - but your explanation puts that to rest.

Hey Ben – awesome, very glad to hear that! Would love to check out your code when it’s finished! Please let us know if any other questions come up :slight_smile:

Nicole,

I spent some time reading up in “literature” and they talk about id_token (identification/authentication) and access_token (access to API), which is what an authorization server (Stytch) is providing.

However, I fail to tie that into your API… Either endpoint for OAuth and MagicLink provides a session_token as well as a session_jwt. But in case of MagicLinks, both of these are empty strings according to your documentation:

https://test.stytch.com/v1/magic_links/authenticate

Response:

{
“method_id”: “email-test-81bf03a8-86e1-4d95-bd44-bb3495224953”,
“request_id”: “request-id-test-b05c992f-ebdc-489d-a754-c7e70ba13141”,
“reset_sessions”: false,
“session”: null,
“session_jwt”: “”,
“session_token”: “”,
“status_code”: 200,
“user”: {…},
“user_id”: “user-test-16d9ba61-97a1-4ba4-9720-b03761dc50c6”
}

I do find an id_token and access_token within the response from OAuth’s endpoint:

https://test.stytch.com/v1/oauth/authenticate

but this establishes a session. I thought the whole point of JWT is to have stateless communication…

I guess I’m asking 2 questions:

  1. How do I find an id_token/access_token from a MagicLink response?
  2. Why does Stytch treat stateless (JWT) communication as stateful (session)?

Update:
Let me add another question:
According to the link you provided above (JWK Set Uri), besides a jwk-set-uri, one requires the issuer-uri. What is that in case of Stytch?

Hey Ben! In order to start a new Stytch session, you’ll need to specify the session_duration_minutes parameter while making your /authenticate call (for any product). Otherwise, you’ll receive empty session_token and session_jwt values, since a session will not be started.

We offer JWTs as a more performant alternative to session tokens, since JWTs can be validated locally (without contacting the Stytch API) for the duration of their lifetime (5 minutes). This reduces session authentication latency for applications that need to make frequent session authentication calls. I’d recommend checking out our blog post about session tokens vs. JWTs for some additional context!

Nicole,

When you say one needs to hit /authenticate endpoint for any product, can these products be mixed 'n matched?

Say a user doesn’t have a Google account (OAuth) and thus uses email/MagicLink to log in, can I then use the Stytch OAuth endpoint (as opposed to MagicLink endpoint) to authenticate user given the authorization code provided in MagicLink?

Hey Ben! No, the /authenticate endpoint must match the product that was used to start the authentication flow.

To make sure I understand correctly, what would the use case be for calling a different product’s /authenticate endpoint (given that all /authenticate endpoints return a session_jwt if session_duration_minutes is specified)?

Nicole,

In that case, there would not be such a use case.

The reason I was asking is because I was confused about how to offer different ways of authentication (different Stytch products) with one auth handler only. But since one needs to follow a fixed authentication flow, one needs to implement an auth handler for each offered product.
For some moment I was under the impression that an authorization code could be used for any given product…

So if I choose to offer MagicLink AND OAuth log in options, I would need to pass in a session_duration_minutes param in order to retrieve a JWT. I’m assuming this is what they refer to as id_token.

How do I then get an access_token, which will help me to determine if a user has access to my API? I know now how to validate the access_token (by using Stytch’s jwk set uri endpoint).
In other words, where is the Stytch endpoint that hands out access_token?

According to Spring doc, the authentication server should provide both, issuing and validating:

spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://idp.example.com
jwk-set-uri: https://idp.example.com/.well-known/jwks.json

Hey Ben,

So if I choose to offer MagicLink AND OAuth log in options, I would need to pass in a session_duration_minutes param in order to retrieve a JWT.

To clarify, any backend /authenticate endpoint requires a session_duration_minutes parameter in order to generate a Stytch session and JWT - this is why the API response you posted earlier didn’t have a session_jwt value.

I’m assuming this is what they refer to as id_token.

Are you referring to Spring Security here?

An id_token is a standardized token returned in OAuth flows, which is why you’re seeing it in the /authenticate response for Stytch-powered OAuth flows (but not Email Magic Link flows).

How do I then get an access_token, which will help me to determine if a user has access to my API? I know now how to validate the access_token (by using Stytch’s jwk set uri endpoint).
In other words, where is the Stytch endpoint that hands out access_token?

Our understanding of Spring Boot’s role in this is something like the following:

  • Set up a JWT OAuth Resource server, pointed at the Stytch JWKS API endpoint, which will be used to validate (Stytch-issues) JWTs
  • Have your users go through a Stytch-powered authentication flow, like Email Magic Links or OAuth. In either of these cases, as long as session_duration_minutes is supplied to the /authenticate call (and the user’s authentication is successful), Stytch will generate a new session along with a Session JWT.
  • When your users need to access auth-restricted content, your application passes the Stytch-issues JWT to the Resource server, which validates the JWT using the JWKS endpoint provided earlier.

Again, we haven’t set this up ourselves with Sprint Boot specifically, but from what we can glean from Spring Boot’s documentation, I believe this is how the flow would work with Stytch!

One other thing to call out is that Stytch-issued session JWTs always have a 5 minute (300 second) lifetime, but can be exchanged for a new JWT via a /sessions/authenticate call as long as the underlying Stytch session is still valid. The reason that we set the JWT lifetime to 5 minutes is because JWTs cannot be revoked – so in order to minimize the window in which a compromised JWT could be used, we cap their lifetime. You can read more about this in our our blog post about session JWTs vs. session token!

What does your frontend looks like, or the overall flow of your application? One option to account for the 5 minute expiration is to have fallback logic such that if the JWT validation fails on your backend (due to an expired JWT), your code falls back to a /sessions/authenticate call with the expired JWT, which as long as the underlying session is still valid, will mint a new JWT that can be re-validated.

Hey Matt,

Thank you for lining out your train of thought here and I do see it the same way. For the past week I’ve been researching and playing around with how this works in Spring Security.

The examples I’ve found to date all show how to set up a Resource Server in Spring Boot / Spring Security using a JWT issuer-uri AND jwk-set-uri, where a 3rd party Authorization Server is pinged to retrieve tokens and to validate them provided the public key (through the JWKS).

In one of the forums I’ve found somebody saying one just has to not provide the issuer-uri if the tokens are received through another method (which is true in Stytch’s case), but then I read this in the Spring doc:

Consequently, Resource Server does not ping the authorization server at startup. We still specify the issuer-uri so that Resource Server still validates the iss claim on incoming JWTs.

It sounds like the validation through given jwk-set-uri happens only if the issuer-uri is provided…

To date I’ve written a MagicKey and OAuth2 Spring Security authentication provider, which consumes the Stytch JWT, which then gets embedded into the “Spring way of doing security”. I’ve not yet figured out how I can marry this with the Resource Server APIs and how the framework will validate tokens.

I’m still in the middle of researching. Again, I’m just surprised that you guys haven’t provided a tutorial how to set this up in the Spring framework. It’s not that Java/Spring is a small fish, especially in the backend world… On top of that, I’m not a security specialist and feel like I’ve now have to first become one before I can tackle this.

Long story short, I would appreciate if one of your “eat-drink-sleep” security guys would write up a Java/Kotlin/Spring/Stytch tutorial.

Hey Ben,

We’ve let our team know about this. They’re planning to work on a Spring example at some point in the future, but we don’t have a specific ETA at the moment. Once we release that, hopefully the Spring + Stytch integration process will be clearer!

We’ll follow up on this post with any updates and a link to the example once it has been released.

1 Like

Hi,

Any updates on this? Have you found a date where you can release a Spring Boot Security and Stytch example?

Hey Ben,

Our team made a Spring Boot + Stytch Email Magic Links example app recently, but we’re still working on the Spring Security piece. It’s on our team’s radar, but I don’t have a set ETA at this point in time – sorry about that.

I’ll follow up here once we have that available!

Hey Ben,

No news at the moment, sorry about that! We’ll be sure keep this thread up to date with any updates.