-
Notifications
You must be signed in to change notification settings - Fork 217
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
Support SSR #256
Comments
This library only targets browsers at this time, though there are a few unnecessary uses of I'm not super confident that this library can gracefully target a fully server-side implementation in its current form. I think you're better off using panva/node-openid-client for server-side applications, though I'd be happy to review an implementation of a cookie-based storage adapter if you have one to contribute. |
We should do the obvious things (e.g. deal with localStorage and sessionStorage), such that not everybody needs to do it like this: https://github.com/johnsonandjohnson/Bodiless-JS/blob/b9d9addcc9117ab6942306265deb87d832ace9fd/packages/bodiless-oidc/src/UserManager.ts#L49-#L63. The |
The main purpose of server-side rendering is to resolve the user from cookies on server-side so that we can base on the user authentication to render the corresponding content during SSR. Its different from node-openid-client which is really do the oidc process on server side. To be clear, SSR only need a similar functionality as the webstorage provided that can resolve the user (also check if the user is expired). My current way to do it is grab the webstorage from the user manager settings, and do And I use a trick to solve the UserManager problem with |
You guys rock, thanks for taking on this project. I'm using this in a static Next.js app via the The only issues I've ran into so far are the JSON parsing error in #257 which you beat me to fixing! The other is that it's a bit difficult to get oidc-client-ts working with next but it looks like you've already done a bit there too If possible, it would be really nice if oidc-client-ts could be instantiated without accessing any browser-specific APIs as it would open it up to users of Next. The most popular next auth library requires you to deploy it along with a backing node service unfortunately; it won't work if you only deploy the static files to a CDN via |
I use it with Next.js too. I would like to achieve the SSR if server is available on Next.js side. The only storage that server can access like what frontend do is cookie storage. I created a cookie storage with help of "universal-cookie", it share the same api interface between frontend and backend. Then I pass it to the user manager settings to initialize the user manager in server side. Frontend rendering use the reaact-cookie to access the "universal-cookie". Assuming both stored cookies are the same, the SSR should match the one in Frontend side. |
Sorry for butting in here, but I never understood this request. If you're doing SSR, then why aren't you using a server-side library? Given the session management and protocol mechanics, a SSR app should do things differently than a client-side JS app. Also, unrelated, I never understood why people wanted to put their access tokens into a cookie from a client-side app -- you're just exposing them to potential leakage and putting end users at more risk. But, admittedly, I don't understand how some of the JS frameworks blend and blur the line between SSR and how their client-side frameworks do their rendering. But yea, my feedback here is really think thru where you're exposing the tokens and if that's really what you want. |
@brockallen We aren't actually using the SSR functionality in next - ie there is no node backend serving our app. Next allows you to "static export" a site, so it will render your app at build time, emit your site as static files and then you can just serve it from a CDN. https://nextjs.org/docs/advanced-features/static-html-export So we can't make use of any of the server-side libraries unfortunately.
Completely agree. If we had a server then I'd go for a regular authorisation code flow and keep the tokens server side, but we only have a SPA served from a CDN, and our API. For that situation, an authorisation code flow with PKCE is the preferred approach, which exposes the tokens to the client. I'd choose a different approach personally but it's not my call. |
Ah, ok, I think I understand -- so the build process actually runs some of the app and captures the DOM and turns that into static files? Again, sorry for the tangent to educate me on this thread. |
^ @brockallen I also want to echo your concerns, I appreciate the feedback. I think what's maybe attractive about this library compared to others designed for servers is that it has a good client-side API for initiating an authorization code flow. It's also possible to initiate a server-side flow this way using cookies, but it feels wrong to use JS-based cookies, especially for auth. If you're on Next.js using server rendering, the client shouldn't need any auth/user context beyond the data that you supply with @matthetherington your use case is the same as mine, my main motivator for maintaining this library is actually for a couple of static Next.js apps. My question for you is what would an "instantiated" client instance look like? Currently when you construct a UserManager, it fetches metadata from the configured authority. During a static build, this would be a waste of resources because we don't have a way to serialize that data for the UserManager instance on the client to reuse. |
@brockallen yep exactly that. Next does an initial first-pass render, which gets emitted as static files. The client requests the HTML along with the JS, and renders the HTML right away. When the JS has loaded it becomes interactive. @kherock I mostly write C# code day-to-day and you can't have async constructors in that, so stuff like you are describing usually goes in a method that you call following instantiation. Instantiating a class is normally side-effect free. So translated to this, I'm imagining an API (in react) something along the lines of:
|
So then how does that work if the HTML needs to render the user's display name (or something else if not logged in)? That's a challenge when this server rendered stuff doesn't have access to the session. |
Minimal SSR support is now merged, i wont do more than that. I fully agree with @brockallen and @kherock! The library can now be used to "static export" for the likes of |
@brockallen it doesn't 😄 like you said, you'd need a server with access to the session to do that, which would dynamically generate the markup and send it down to the client. As it's just static files served from a CDN, it's the same markup for every user. So for the authenticated pages, we are pretty much just serving up a loading spinner via the html that's in the CDN and then when the JS bundle is loaded it'll redirect to the OIDC Provider. When the OIDC Provider redirects back and we have the user's identity, then the client-side JS can render their display name to the DOM. The benefits are more tangible for the pages that don't require auth but you still get a much quicker first-paint. There's a good write-up of the performance aspects here: https://blog.logrocket.com/next-js-vs-create-react-app/ It's talking about SSR but a lot of the same benefits apply, minus the server-side data fetching. |
I think we now have done what can be done. I will close this issue unless somebody speaks up. |
There are plenty of code access the window object which make the server build fail. It doesn't happen in oidc-client-js.
For example, window.LocalStorage, even I provide a custom CookieStorage, as the source code default value is using window.LocalStorage, the code would fail.
Also, when I call userManager.getUser(), it init a timer which make use of window.setInterval and window.clearInterval, which make it fail in server side build.
Is it possible to change the source code to check if window object exists before access it?
The text was updated successfully, but these errors were encountered: