Saving and Restoring Sessions
If you're writing an app you probably don't want to ask your user to authenticate every time your app starts, or to store their login credentials somewhere on disk. The Agent class provides a way to restore, or authenticate from a stored refresh token and the URI of the server that issued it.
Events are provided so you can react to background token refresh operations and store the updated refresh token for the next time your application app starts.
Authentication Events
An agent provides four authentication related events that you can subscribe to:
Authenticated
CredentialsUpdated
TokenRefreshFailed
Unauthenticated
You can subscribe to these events by adding a handler to the event. For example:
var agent = new BlueskyAgent()
{
agent.SessionCreated += (sender, args) =>
{
Console.WriteLine("Session created");
// Now persist the refresh token and any DPoPKey and DPopNonce, along with the service URI and DID
// it belongs to somewhere secure.
//
// Optionally you can also persist the handle as an indexer to support multiple accounts within the same application.
};
}
The Authenticated
event is raised when a login is successful and a new session is created.The CredentialsUpdated
event is raised when the background
token refresh occurs or you call RefreshSession()
. A TokenRefreshFailed
event is raised when the background refresh fails, or your manual call to
RefreshCredentials()
fails. Unauthenticated
is raised when you call Logout()
.
Important
In your handler for Authenticated
and CredentialsUpdated
it is suggested you store the refresh token, any DPoPKey and DPopNonce, the URI that issued it and the DID it belongs to securely,
in whatever way is appropriate for your platform (for example the
Windows Credential Store,
or the Mac/iOS keychain).
If your application supports multiple accounts you should also store the handle that was used to create the session.
Storing the access token is optional, it is meant to be short lived and may no longer be valid when your application restarts.
You should update these your stored values in your handler for CredentialsUpdated
.
Finally in the handlers for TokenRefreshFailed
and Unauthenticated
events you should remove any stored values you have for the DID and the service.
Restoring or recreating a session
To restore a session from a refresh token (or an access token if you still have a valid one) first create an instance of AtProtoCredential
using AtProtoCredential.Create()
with the information you stored securely then pass it to RefreshCredentials()
.
AtProtoCredential restoredCredential = AtProtoCredential.Create(
service: persistedLoginState.Service,
authenticationType: persistedLoginState.AuthenticationType,
refreshToken: persistedLoginState.RefreshToken,
dPoPProofKey: persistedLoginState.DPoPProofKey,
dPoPNonce: persistedLoginState.DPoPNonce);
bool resumeResult = await agent.RefreshCredentials(
credential: restoredCredential);
if (!resumeResult.Succeeded)
{
Console.WriteLine($"Restore failed.");
}
If the resume is successful the agent will be populated with the current access and refresh tokens and the session will be valid for authenticated
calls.If the tokens were refreshed during restoration (which happens if you have a refresh token, but no access token, or the access token is expired)
the CredentialsUpdated
event will be raised, where you should store the newly refresh credentials.