marcpp
May 10, 2024, 12:22pm
1
I’m trying to make this example code work.
So basically I’ve got a “Log in” button and a “Greet” button. And here’s what’s happening:
I click the “Greet” button: it displays “Hello, 2vxsx-fae!”
I click “Log in”: another tab opens and I log into my Internet Identity, then the tab closes
I click the “Greet” button again: it displays “Hello, a5sm3-2jqyf-of34i-2y4rc-jras6-ll7yf-in4ha-…!”
So far, so good!
But here comes the issue : if I click the “Greet” button a third time, it says “Hello, 2vxsx-fae!” again, as if I was logged out
I doubt this is the expected behavior. Is there anything else I must do so that the user remains logged in for some time?
Thanks a lot for your help!
I know it’s probably not what you want to hear but, there is probably an issue in your code .
Unless you have set a session duration to least only few seconds (default duration is 30 minutes), I would not see any other reason why this quirk happens than a race condition or something similar.
Have you double checked that you are accessing the same authenticated object and that you do not trigger some unexpected logout?
Sorry did not noticed you shared some code. Are you exactly trying out the example you linked or did you tweaked it?
marcpp
May 10, 2024, 12:59pm
4
I tweaked it a bit, so you’re probably right. But nothing crazy.
In the backend, I haven’t touched anything:
public query ({ caller }) func greet() : async Text {
return "Hello, " # Principal.toText(caller) # "!";
};
In the frontend, I’m using React:
import { useState } from 'react';
import { createActor, myapp_backend } from 'declarations/myapp_backend';
import { AuthClient } from "@dfinity/auth-client";
import { HttpAgent } from "@dfinity/agent";
export default function Home() {
const [greeting, setGreeting] = useState('');
let actor = myapp_backend;
function handleSubmit(event) {
event.preventDefault();
actor.greet().then((greeting) => {
setGreeting(greeting);
});
return false;
}
async function login(event) {
event.preventDefault();
let authClient = await AuthClient.create();
let internetProvider = process.env.DFX_NETWORK == 'local' ? 'http://' + process.env.CANISTER_ID_INTERNET_IDENTITY + '.localhost:4943' : 'https://identity.ic0.app/';
await new Promise((resolve) => {
authClient.login({
identityProvider: internetProvider,
onSuccess: resolve,
});
});
const identity = authClient.getIdentity();
const agent = new HttpAgent({identity});
actor = createActor(process.env.CANISTER_ID_MYAPP_BACKEND, {
agent,
});
return false;
}
return (
<>
<img src="/logo2.svg" alt="DFINITY logo" />
<br />
<br />
<form action="#" onSubmit={login}>
<button className="success" id="login">Log in</button>
</form>
<br />
<form action="#" onSubmit={handleSubmit}>
<label htmlFor="name">Enter your name: </label>
<input id="name" alt="Name" type="text" />
<button className="primary" type="submit">Greet</button>
</form>
<section id="greeting">{greeting}</section>
</>
);
}
See anything wrong?
Once you set state, your component re-renders, thus the actor variable is re-created. Which means it won’t be the actor it was after login with the II identity instance agent.
Put your actor either outside the component, in a ref or state to persist it across renders.
Or the all page is reloaded because the form is submitted. Indeed as said above or a “quick and dirty init just for test purpose only” like:
useEffect(() => {
const authClient = await AuthClient.create();
const identity = authClient.getIdentity();
const agent = new HttpAgent({identity});
actor = createActor(process.env.CANISTER_ID_MYAPP_BACKEND, {
agent,
});
},[]);
i.e. when you create a new authclient, per default, it creates a client for what’s availalbe in indexedb. So if nothing is present, it create an anonymous, if something is present, it create a client for it regardless if the length of the session is over or not.
That seems to be avoided with event.preventDefault() at least, it was the first thing on my mind though till I saw the React code posted.
Thanks a lot guys. That indeed was the issue! I’ll make sure to keep that in mind in the future