16

I've been scratching my head for about 2 days on how to solve what seemed to be a simple task, but it's starting to drive me crazy.

I have an application where users will use SAML 2.0 to authenticate. I have a react-application set up for the front-end, and was thinking I was gonna use JWT to secure the rest-api communication between front-end and backend.

When a user signs in, the flow is the following:

  1. User accesses www.server.com/ and gets served the static HTML with react-application
  2. User clicks 'Sign in' and accesses www.server.com/login
  3. passport-saml redirects user to saml identity provider. User logs in.
  4. User calls back to www.server.com/callback with a SamlResponse in the req.body which is decoded by passport-saml and put into req.user.
  5. If the user doesn't already exist, I create the user in the database.
  6. I create a JWT.

What should I do next? The problem is that the user is not in the react-application when calling back from the identity provider, so I've lost all state in the application, so whatever I reply with will get sent to the browser.

Is there any way I could force the browser to give me the SamlResponse which the identityprovider is calling back with? Then I could send it to the server as a http-request from the react-application.

Stian Bakken
  • 673
  • 1
  • 5
  • 15

2 Answers2

21

After some thinking, I came up with the following solution which worked quite nicely for me.

SAML has something called RelayState which is a property that the Service Provider has to respond with. So now the process looks like this:

  1. User accesses http://frontendserver.com and gets server the static page with the React application (not signed in.).
  2. User clicks 'Login' and gets redirected to http://backendserver.com/login/?RelayState=http://frontendserver.com which authenticates via passport-saml and redirects user to SP. So I pass the origin of the request in RelayState.
  3. User calls back to http://backendserver.com/callback with the SamlResponse, which includes the RelayState.
  4. I create a token, and redirect the user to RelayState/#token.
  5. I can then parse the url in the React application, and add the token as a header for any further requests.

This might've seemed like the obvious way to do it, but it took me quite a while to figure out that this would work.

Stian Bakken
  • 673
  • 1
  • 5
  • 15
  • 1
    Not as long as the communitcation is done via https. – Stian Bakken May 23 '18 at 08:54
  • 2
    Can you provide a sample app please? – Manoj Jan 20 '19 at 10:35
  • how to logout and check if token is valid when neext time i come to website – ankalal Apr 01 '19 at 12:30
  • 1
    @ankalal JWT doesn't have a clean way to log out. What I do on my app is if the user clicks logout, I simply delete their token from the cookies. If you need to log the user out from the server (let's say delete them), you'd have to have a mechanism that keeps track of tokens on the server (db for example) and invalidates them. – Svet Angelov May 29 '19 at 18:52
  • 1
    Please, can you add more details, please. I get SAMLResponse and redirect to web-app again with 302 status code, but browser prevents any access from JS because of 302. So this step "User calls back to http://backendserver.com/callback with the SamlResponse, which includes the RelayState." in which way should be done ? Detect redirect ? – Eugene Shmorgun Jan 13 '20 at 09:57
0

I know this question is for Node backend, but I found an article of the implementation for a PHP/Apache webserver backend here and I think it can help someone trying to understand the flow of the process of how this type of thing works.

Iruku Kagika
  • 583
  • 1
  • 7
  • 17