-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
OIDC support #124
Comments
There are a few options in terms of existing React libraries. Although many of them seem to be poorly documented.
They all seem to use the same underlying library: https://github.com/IdentityModel/oidc-client-js |
Whilst the use of Redux for this feels wrong to me, (it only needs to store some tokens doesn't it? I wouldn't think there would be that much async stuff going on. Then again, maybe there is...) perhaps it wouldn't be the end of the world if we already need Redux for #125. |
Possibly, Redux is useful for handling the updating of access tokens. Then again, I wonder if that would be so infrequent that it could be done synchronously. |
Another concern for this work is the security of tokens. I suspect that cookies might be better than local storage. Or perhaps we could be even more cautious. Perhaps the server could return the tokens in headers (or a cookie) and the app could just put them in memory and delete any cookies. |
oidc-react appears to not support SSR. Issue raised at: bjerkio/oidc-react#329 |
It occurs to me that this isn't necessarily a React issue. We could solve most of this problem with just a middleware on the server. The problem would only arise once the access token expires. As at that point queries to GraphQL would start to fail. |
Another contender might be https://github.com/react-keycloak/react-keycloak . However this would make the solution specific to Keycloak and I'm not sure what the benefit of that would be. - If Keycloak implements OIDC then surely we can just work with that? |
So far the libraries appear to be oriented towards the client-side and even require a client with a 'public' access type (no client secret). - We would normally only use 'confidential' on UIs and 'bearer-only' on APIs. I wonder if it would be better to write our own one specifically for isomorphic applications. To my mind the ideal process would be:
i.e. The client would never need to do an actual login as it would be receiving tokens from the server. I'm not sure anything out there works like this currently. It's also possible that I've misunderstood something. |
Looks like louketo-proxy puts the refresh token in a separate cookie called It looks like it is encrypted: https://github.com/louketo/louketo-proxy/blob/master/docs/user-guide.md#encryption-key It also looks like it's possible to use a server-side data store for them instead. It makes sense to take more care over handling the refresh token as it is a longer-lived credential. However, if we want the client to handle updating the access token we will need to find a way of sharing the refresh token with it in an unencrypted form. We could have a special endpoint that the client could hit in order to receive the unencrypted refresh token? |
(I say unencrypted, but I only mean unencrypted at rest; TLS would be in place for the transit, at least in production.) |
Another alternative might be to not have the client even do the refreshing of access tokens. Perhaps the client could simply refresh the page when the access token expires and let the server do it. Although there's probably a big risk of losing the users work with this strategy... |
https://www.oauth.com/oauth2-servers/access-tokens/refreshing-access-tokens/ |
Perhaps, rather than ever holding the (unencrypted) refresh token, the client could hit a special endpoint on the server to get a new access token? - This might be a better fit given the server will be using the auth-code flow. |
https://www.oauth.com/oauth2-servers/access-tokens/refreshing-access-tokens/ This suggests that it is the server that should get the new access token. It does sort of imply that the request token is the real credential here. i.e. What's the point of the access token? |
I suppose it means that you are checking in with the auth / SSO service. i.e. The Auth service can refuse you a new access token if the session has been revoked. |
The question then becomes, should we have a special endpoint for getting a new access token or should the server simply try to replace expired access tokens as and when it receives them. (Which is what louketo-proxy does, I think.) If we go down the route of doing this automatically, there's really nothing for the client to do on the auth side. (Maybe we could even just use louketo-proxy and be done with it.) We would want get the information from the token in to the client though. |
The automatic way feels a bit wrong for API endpoints (including |
Perhaps the first pass for implementing this is the following:
|
Upsides (to this 'first pass'):
Downsides:
|
Doing auth in the app could be a 'second pass' and be enabled (or disabled!) with a feature flag to maintain ease of testing. |
Part of my suggesting the |
It feels like trying to React without Redux is something you can't really do for long, and the longer you try, the worse your problems become when you finally given... |
Is part of the goal here to not use KeyCloak gatekeeper (or whatever they're calling KeyCloak proxy these days)? |
This whole issue feels like a server-side problem that is at a higher level than the rendering library; all the RBAC stuff should be handled before any React work, all that React should be doing is rendering one page when RBAC has successfully finished or an error when there's a problem with the roles/access. |
Why would you bother refreshing the page when you can use ajax or an iframe? |
...or has expired, in which case the client would have to re-login (a common activity when using KC) |
The client should be essentially dumb as far as RBAC goes, it should just pass back whatever tokens the server issued after first (or most recent) login. This means an access token will work until it expires, then the refresh token will mean new access tokens can be issued, until that too expires at which point the client will have to login again (but this login should be possible without interfering with the user's session). |
I'm not sure I see why React would need access to information about the user, all RBAC work should be handled outside of the scope of React. All React should be doing is rendering the resulting information. |
Again, look at how |
What was it about HAPI's handling of auth and security that you liked?
I'm not sure that's true though. I've been doing pretty well without it. People are saying that React's context API fulfils most of the use cases for Redux. So I suppose the question is, what do you think we need it for?
I think it would be nice to not require it, in the long-run. So far we support serverless deployment so it would be nice to keep that rather than require a proxy is in place.
Well the question is how we pull that off without having the app just break when things expire. (Refreshing the page would be a cheap way to achieve this.)
It's fairly normal to show who you are currently logged in as. So that would be one use case. The other would be to preempt what the user will be able to do and provide them with a helpful message. |
The different |
I think that's the thing. For simple data-stores the new 'context API' can be used. The rest of Redux's use-case seems to be around managing events and I'm not sure that we need that if we are sticking to having SSR as a fall-back.
Can we though? What if the user needs to log-in? |
The first pass of this (relying on headers from louketo-proxy) is now done. Specifically we can:
This should allow us to protect our data and provide the user with helpful information when they don't have permission to perform certain actions. We can also apply different authentication modes depending on the situation which should help with local development and functional testing. For the second pass I'm considering using Passport.js. |
|
Yes, I think so. (Famous last words!) The main difference with Restify is that you have to ensure that |
This is now done but will need future improvement as detailed in #158. |
We should build in support for authentication with OpenID Connect.
This is complicated by isomorphic rendering. i.e. Really the initial login should be done via SSR but the client should take over the handling of tokens as well as allow us to inspect the login information from the token. Meanwhile, any API endpoints need to support inspecting tokens outside of React. (And in fact, that is the most important point to get right in terms of security.)
It would probably be best if the SSR React component would put the tokens in a cookie. I think this is how louketo-proxy works. I'd like to avoid forcing a server-side session store if at all possible.
The text was updated successfully, but these errors were encountered: