-
Notifications
You must be signed in to change notification settings - Fork 39
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
feat: Define onTokenExpired event #724
base: main
Are you sure you want to change the base?
feat: Define onTokenExpired event #724
Conversation
Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have the users @danielSbastos on file. In order for us to review and merge your code, please contact the project maintainers to get yourself added. |
Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have the users @danielSbastos on file. In order for us to review and merge your code, please contact the project maintainers to get yourself added. |
@cla-bot check |
The cla-bot has been summoned, and re-checked this pull request! |
Hello @danielSbastos! 👋 The user Thank you 💖 and congrats 🎉 for opening your very first pull request in this repository. |
const userTokens = await devopnessApi.users.loginUser({ email: email, password: pass }); | ||
// The `accessToken` must be set every time a token is obtained or refreshed. | ||
devopnessApi.accessToken = userTokens.data.access_token; | ||
await devopnessApi.users.loginUser({ email: email, password: pass }); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The previous example was intentionally showing new users how to retrieve the accessToken
generated by the login API endpoint.
How would the access token be obtained now?
Could you please make that clear in the README example code/comments?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, this is a good question. Now, in the PR, the accessToken
is being internally set at:
devopness/packages/sdks/javascript/src/services/ApiBaseService.ts
Lines 129 to 135 in e6797f9
private setAuthParams(accessToken : string, refreshToken : string, expiresIn : number) : void { | |
ApiBaseService._accessToken = accessToken || ApiBaseService._accessToken; | |
ApiBaseService._refreshToken = refreshToken || ApiBaseService._refreshToken; | |
ApiBaseService._accessTokenExpiresAt = expiresIn | |
? Date.now() + expiresIn | |
: ApiBaseService._accessTokenExpiresAt; | |
} |
together with the refreshToken
and expiresIn
, which removes the need for the user to set it and instead delegates the responsibility for the SDK. My question is:
- Should the user need to manually set the
accessToken
? If so, then is this behaviour also extended for therefreshToken
andexpiresIn
?- I thought of removing this responsibility from the user mainly because of the
expiresIn
token, since it is transformed in aexpiresAt
atdevopness/packages/sdks/javascript/src/services/ApiBaseService.ts
Lines 132 to 134 in e6797f9
ApiBaseService._accessTokenExpiresAt = expiresIn ? Date.now() + expiresIn : ApiBaseService._accessTokenExpiresAt; _accessTokenExpiresAt
is used after to check if the token is expired, see here). If the user were to set it manually, just like with theaccessToken
, my opinion is that there would be more code burdensome and margin for error. They would have to do something along lines of:
- I thought of removing this responsibility from the user mainly because of the
async function authenticate(email, pass) {
const userTokens = await devopnessApi.users.loginUser({ email: email, password: pass });
devopnessApi.accessToken = userTokens.data.access_token;
devopnessApi.refreshToken = userTokens.data.refresh_token;
devopnessApi.accessTokenExpiresAt = userTokens.data.expiresIn
? Date.now() + userTokens.data.expiresIn
: devopnessApi.accessTokenExpiresAt;
}
authenticate('[email protected]', 'secret-password');
WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the user need to manually set the accessToken? If so, then is this behaviour also extended for the refreshToken and expiresIn?
No, it should not be needed but must be possible.
A simple way for you to test is creating a simple web page that consumes your version of this SDK-JS (npm link can be helpful for local tests).
Imagine you logged into the SDK and SDK set the token internally for the current instance. Fine!
Now the user reloads the page (hits F5) and a new login will be performed instead of re-using the previous token.
That's not the desired state!
A common practice in web development is to store the token in the browser local storage, which is persisted in between page loads, close browser, etc, so the user can get back to the page and still be logged in without being prompted again for login.
For having this behavior in an application that consumes this SDK, the client applications must be able to read/set the accessToken
if that's their intended behavior - which very likely will be, as this a common practice across the web development community.
Makes sense now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahhh, I see now why the user was defining the accessToken
before, it makes sense after you mentioned the issue with the session! 😄
Okay.... I will revert the changes and give the user the responsibility to set the accessToken
, refreshToken
and expiresIn
(it will be converted to a expiresAt
). I will create a setter for both three and isolate the logic of the expiresIn
to expiresAt
conversion (Date.now() + expiresIn
) inside the devopnessApi
object. Maybe with
devopnessApi.setAuth(userTokens.data)
but also with the choice of individually setting each:
devopnessApi.accessToken = <...>
devopnessApi.refreshToken = <...>
devopnessApi.accessTokenExpiresAt = <...>
WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see any need at the moment to allow user to set refreshToen
and accessTokenExpiresAt
.
They already available to the user on the response of users.loginUser()
, so client apps can choose to store it or not, but not to set it to the SDK.
All the SDK needs to be externally set is the accessToken
.
Once the onTokenExpired
event is triggered, client apps can intercept it and use the stored refreshToken
without the need to set it in the SDK instances.
Does it make sense?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it does. Thank you for explaining it clearly :) I'll make the changes!
@danielSbastos please see my comments near
You can follow the introduction guide to Devopness and once logged in you can inspect the call to You can also check the attributes on the response model for each of these endpoints: Hope that helps! |
Hey @jfoliveira, thank you for the inputs! I replied to some and asked a few questions. I think there is a point I did not explained is that I was not able to differentiate solely on the status code 401 if the If the status code if 401 AND the current time is later than |
Hey @jfoliveira, sorry for the delay. I'm thinking of ways to verify the By assuming the user sets in the |
We can't assume that for many reasons including, but not limited to, the fact that this SDK is designed to be used not only browser, but also in Moreover, the developers consuming this SDK are the ones responsible to manage if/how any SDK exposed data, such as We should not impose any requirement on how the client apps consuming this SDK are designed by their developers. |
Gotcha, that makes sense. Maybe the best option is then for the client to implement an interface, injecting it into the SDK, on how to access this token, which its implementation would be up to them? |
We should not care or influence how SDK clients implement anything on their side. We should just expose data and trigger events so client apps can handle the events anyway their developers feel like and read/store the exposed data in any ways that suit them better. I believe I'm not following what is making this implementation so hard and why you're trying to find ways to tell the SDK clients what to do. Are you sure we can't just keep things simple and expose an event handler method as discussed in previous comments and in original issue #25? |
What is making it not so simple is because, right now, the solution to invoke the callback depends on the 401 status code and the Given this, there is a need to define a strategy on how to handle the If you have another idea on how to manage the |
@danielSbastos well, that's the basic requirement of this task. If you didn't know how to check that, which is understandable, I would expect you to have written no code at all and specially before proposing to remove existing working code. As you started adding and removing code, I thought you knew exactly what you were doing. 🤷♂️ That being said ... If you just keep the We would just need to base64 decode the const decodedToken = JSON.parse(
Buffer.from(accessToken.split(".")[1], "base64").toString()
);
console.log(new Date(decodedToken.exp * 1000)); Having that in place, you could have something like the pseudo code below: if (response.statusCode == 401) {
const isTokenExpired = decodedToken.exp < new Date().getTime() / 1000;
if (isTokenExpired) {
"trigger `onTokenExpired` callback"(<params>);
}
} |
Description of change
Hello there,
In this PR, two main changes are introduced:
accessToken
is removed and is instead now done inside the code, together with the setting ofrefreshToken
andexpiresAt
NOTE: This PR is still in draft because I am unsure of the approach to set the
accessToken
,refreshToken
andexpiresAt
. I think this is internal knowledge of the SDK and should be handle there, however, the previous method to set theaccessToken
by the client existed, therefore I am a bit confused as to which approach to follow. Also, by removing the getter and setter ofaccessToken
, a breaking change would be introduced.Issues resolved by this PR
This PR solves #25