-
Notifications
You must be signed in to change notification settings - Fork 73
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
Get a refreshed access token if expired #837
Comments
@pradel while looking into this I've spotted an issue that, even implementing the pattern you mentioned, would prevent it from working properly. I am working on a fix, will let you know about an ETA as soon as I have an idea of problem. |
Fix ready for next release: #840 |
@cesarenaldi will the token be refreshed if no calls are made to Lens for a long time? |
Yes, the token from |
A fix for this is now available in:
Also if you use Wagmi bindings bear in mind the latest: See updated reference docs: https://lens-protocol.github.io/lens-sdk/modules/_lens_protocol_react_web.Core.html |
BTW, the approach you suggested is probably better IMO, just didn't want to introduce an API breaking change as I am aware several teams rely on the |
I assume this issue is solved then. |
@krzysu tried with the latest version and the token is still not refreshed, can you please reopen the issue? |
@pradel sorry, I only got to this now. I managed to reproduce some issue at bootstrap time. Hook returns |
The behavior I noticed is after 30 mins of inactivity (so when the access token expires) |
Experiencing an issue with the client whereby the
Is this related to this issue? |
@pradel a fix for this in the next release. |
@b-bot this issue was specifically for the Lens React SDK. The Said that, at a quick glance I don't see the method you would need to invoke to refresh credentials when you encounter Can I ask you about your integration? Are you using the |
@cesarenaldi Perhaps this is my misunderstanding but I thought the client manages the session entirely. Would I need to use the storage interface to manually do this or where is it persisted? I'm running through the full auth flow on the backend via a tRPC API (This is why I cannot use the React Hooks SDK). Client is being used on FE and BE. Edit: here the docs say it automatically refreshes - https://docs.lens.xyz/docs/refresh-jwt#lensclient |
@b-bot ok, we have few things going on here. Let's start from the simple one. The In this regards it's similar to the Lens React SDK.
But before going into that I would like to understand more about your use case to make sure it's what you need. Can I ask how do you authenticate the LensClient on the BE? Is this using an app Lens Profile of your choice? And on the FE, is this authenticated as well? With what Profile? The user's Profile? |
@b-bot sorry for editing my previous comment, there were imprecisions @krzysu made me realize. For all intent and purposes the The persistent storage is likely to play a role in you use case but still need to understand what Profile you expect to log-in with on either sides (BE and FE). |
@cesarenaldi This is making more sense now. So I'm using Lens Client in a custom credentials provider via Here's a snippet. async authorize(credentials) {
if (!credentials) return;
try {
await lensClient.authentication.authenticate({
id: credentials.id,
signature: credentials.signature,
});
const authenticated =
await lensClient.authentication.isAuthenticated();
const profile = await lensClient.profile.fetch({
forProfileId: credentials.profileId,
});
}
return profile;
} My question is what should I use as the storage interface? I cannot use local storage because I need to use this in the backend too. Unless I purely use it on the backend which should be fine. What would be great is if you could pass the access token into the client options (from the session) and it would assume this is the auth on the frontend. Then yes the omission of the refresh method is what made me think that happens automatically - and that a persistent storage was already included (should have dug deeper in the code). Edit: forgot to mention this is all with the users wallet and their profile signing a request. |
Not sure how accurate is the snippet, but if the It appears to me your use of With ephemeral instances scoped to the request, you can keep the default storage which is an in-memory storage. You actually want to avoid using a shared storage cause you would risk to use an authentication state from a request that possibly belong to another user. Now the question is: do you plan to mediate other Lens request through endpoints in your BE or is this just for issuing your authenticated session? If your only purpose is to verify the user identity and issue an authenticated session token to your user, I recommend complete the auth handshake on the client ( You can also fetch info about the profile, the Lens If, on the other hand, you actually need to mediate requests to the Lens API via other endpoints in your BE, the need of using ephemeral |
@cesarenaldi Alright so I've gone ahead and adjusted my flow to your suggested. So I at least have persisted auth on the frontend. I passed the verified The import {
type IStorageProvider,
LensClient,
development,
production,
} from '@lens-protocol/client';
import { isDev } from '..';
class BrowserStorageProvider implements IStorageProvider {
getItem(key: string) {
return window.localStorage.getItem(key);
}
setItem(key: string, value: string) {
window.localStorage.setItem(key, value);
}
removeItem(key: string) {
window.localStorage.removeItem(key);
}
}
const isBrowser = typeof window !== 'undefined';
const storageProvider = isBrowser && new BrowserStorageProvider();
const lensClientConfig = {
environment: isDev() ? development : production,
...(isBrowser && storageProvider ? { storage: storageProvider } : {}),
};
export const lensClient = new LensClient(lensClientConfig); The problem is I do need to use this in the backend. I have a How is this possible? |
First question: is this ephemeral? In my experience with NextJS the While the approach is fine on the client-side where the only main thread is for the user, on the server you might have a pool of threads (or processes) that is used to serve incoming requests. Said that, there is a lot of magic going on with NextJS and Vercel so don't know if they are spawning and destroying an new JS execution context for each request. Gut feeling is that they might not, cause it would make start up time unpredictable depending of how much code run at module level of the overall import chain (and we are talking about dependencies of dependencies being imported and evaluated). By ephemeral I meant an instance of the Sending the access token to your server is useful for occasional usage. For example to verify the user identify before issuing app specific session token(s). However, because it last only for 30 minutes and then it needs to be refreshed, you need to make sure you pass a fresh one with every request. You can't simply put in in the shared session after successful login. In 30 minutes time it will not be usable by your BE request handlers. An approach I know people are using is to define a cookie based storage: #842 (comment) With such approach the client and the server will automatically share the same internal state (i.e. refresh token). The ephemeral instance of the |
This NextJS doc page gives some insights when they talk about Serverless Node.js and raises the same concern about boot up time: https://nextjs.org/docs/app/building-your-application/rendering/edge-and-nodejs-runtimes So I guess, it depends on the way you run it. As instantiating a function createLensClient() {
return new LensClient(...);
} and use such function to create an ephemeral instance in the API route handler or a middleware for it. |
@cesarenaldi Thanks for all the help dude, really appreciate it. Went through the cookie storage method for the client and ended up removing it after. I'm using Lens in such a wide array of environments it becomes a little messy. (tRPC, middleware, frontend) The client doesn't really suit serverless architecture IMO and would be better if running Next in a Docker image. My idea with storing the access token in the session was to also get the refresh token there and use it to persist the auth. There is a callback I have that runs every time the session is accessed and I wanted to validate it in there (possibly refresh, was going to submit a PR to add that method to the client) Ultimately what I settled on was lens client authenticated calls strictly on frontend and unauthenticated calls going through my API. I would have preferred to just use the React Hooks but no integration exists yet for my library (thirdweb) So yeah everything works now. I look forward to the new docs teased on X - can maybe explain some of these concepts in this thread there and help others. |
Hey @b-bot can you please share some insights on
would love to hear your take. If this is an issue with cold boot or specific to your auth setup. Regarding:
This is possible. You can have an authenticated instance of the There is not a clear way to 'extract' the refresh token from the React SDK but can provide you a workaround in the short term and add a bespoke hook for that.
This is where custom I would also recommend to use React SDK if your app is leveraging React. All the heavy lifting of dealing with Lens Protocol and API intricacies is done for you. I will be happy to help on TG, are you in the Lens Dev Garden group? |
@cesarenaldi Sure, so a couple of things. Since RSC the runtime can be confusing so I needed to almost write variations of it to maintain context. I tried async local storage as that looked the most promising as it provides a unique store per call chain. However I also do some logic using S3 triggers - this invokes an AWS Lambda separate from Vercel in response to bucket CRUD operations. I realised it's impossible to make authenticated calls because my storage doesn't work here. So I do the call on the frontend and pass the dynamic data to it now. I realise this is not a normal scenario most devs will be doing but this explains my comment. If we can get that refresh token somehow that would be ideal because I could pass that where I need authenticated access briefly when no store is present. This would essentially create a makeshift per user "API Token". I could also bind my auth session to Lens - if it cannot refresh I terminate the browser session too! If there is no method to retrieve currently how is I actually wrote a binding and got it to work, but it did seem a little hacky. Will take a look at the example. What's your opinion on using React Hooks AND the client, would this complicate authentication further? I am not but you can add me there |
In the meantime you could extract the refresh token by accessing the client storage use in the React SDK. Either you create it using whatever underlying mechanism you like for the client and you pass it around, or you rely on the default (i.e. leverages Once you have
Notice the item label contains the environment name ( Regarding:
Just added you to the TG group. Feel free to DM me to discuss details further. |
@b-bot the PR with the |
A fix for this Issue thread was released as part of last 2.x alpha. Current stable 2.1 includes such fix. @pradel can you please confirm this is solved in your integration? |
@cesarenaldi did a quick test and it seems to be working, I guess we can close the issue and reopen it in case the issue appears again? |
@pradel awesome news! Closing this for now. |
Is your feature request related to a problem? Please describe.
To authenticate a user against my Rest API, I forward the Lens access token and send it to my server, then call the Lens API to verify that it's valid. This process is working fine as recommended by the lens docs.
To get the access token, I use the useAccessToken hook but that returns the current accessToken that might be expired, I need a way to get a refreshed access token.
Describe the solution you'd like
I guess smth like the following would solve my problem
The text was updated successfully, but these errors were encountered: