Two-factor authentication and possible Tyk bug?

We are implementing two-factor authentication, and after much consideration we’ve gone with an approach that I would like to run by you. We’ve also run into an issue with Tyk that seems to prevent this approach from working.

Consider a client app hosted at app.example.com, and our login page hosted at login.example.com. The Tyk-managed API is public at api.example.com. It has an endpoint, at api.example.com/session that internally returns the meta-data from the Tyk key/session.

We’re using the OAuth 2 flow to sign people into app.example.com, basically:

This is working great. Now we want to introduce two-factor authentication, but we don’t want to do it all the time. Only when the user is trying to access certain resources which are even more restricted. My initial idea was to do the same thing again but indicate in the scope parameter that two-factor authentication is required. I quickly realized Tyk strips away the scope parameter.

My next approach was to redirect the user to login.example.com, carrying along their access_token, which login.example.com then uses to upgrade their key after successfully authenticating, i.e.:

  • User tries to access even more restricted area on app.example.com
  • User is redirected to login.example.com, carrying their app.example.com token
  • User authenticates using SMS or whatever
  • Server at login.example.com updates the Tyk key/session identified by the access_token to indicate in the meta-data that the user is now authenticated using two-factor authentication
  • User is redirected back to app.example.com, where the same token is now upgraded

First of all, what do you think of this approach?

Second, I’m having problems updating the the key. More precisely, I can upgrade it using PUT or POST to /tyk/keys/{access_token}, and it’s updated correctly. But when I redirect back to app.example.com, and it tries to access /session in my API which in turn GETs /tyk/keys/{access_token} (to return it’s meta-data) it hasn’t been updated.

If I sleep my code a few seconds after updating the key, before retrieving it again from app.example.com, it works.

Any idea why this would happen? Does it take time for it to propagate through my single-node Tyk system or something?

Tyk by default hold local cache of tokens for 5 seconds, and you can try disabling it by setting disable_cached_session_state to true.

Hope it helps!

Thanks @leon! I appreciate the response, and that’s good to know for the future. To solve this I decided to go down another route though. I’ve realized Tyk isn’t really supposed to be treated as a session store, but rather sync with another session store through hooks/notifications, so I created my own store and that solved it.

Hi @richardolsson, I read your post and I am working on almost the same things. Appreciate if you can share about the approach for creating your own store in 2FA?

@richardolsson @leon
Besides, how can you resolve the scope parameter issue in TYK? For example, if user checks to allow one scope (e.g read account) out of two scopes (e.g. read/write account), how can the access token in TYK control this scope limited access? Thanks

@neonlai You could use any type of store. We decided to create a micro-service which manages everything related to authentication (verifying credentials, sending one-time passwords etc) and took care of communications with Tyk there. It’s not complicated, it was just a way to get around relying on Tyk for session data storage.

As far as the scope parameter is concerned, I consider this a huge shortcoming of Tyk. We haven’t been able to use scope for this reason, but luckily it doesn’t affect us much since we don’t have scoped access in our API anyway. That’s on our wishlist though, and when we get there we are probably going to have to migrate away from Tyk. :frowning:

Thanks @richardolsson ! For your sharing, do you mean you store the TYK generated/re-generated token in your micro-services?

About the scope, I am trying but obviously its not working as you said. Not sure if we can use Open ID connect approach to achieve this.