Authenticating end users
Authentication
The Zendesk SDK enables secure authentication of end users, allowing agents to reliably verify user identities within Zendesk. Before proceeding with the steps below, ensure you have completed the prerequisites in Authenticating users.
For a practical example, see our demo app repository, which demonstrates user authentication in action.
LoginUser
To authenticate a user, call the loginUser
API with a valid JWT (JSON Web Token) generated by your backend. This securely links the end user to their Zendesk identity, enabling agents to verify and personalize their experience.
See Creating a JWT token for details on generating a JWT.
Swift
The result of loginUser
can be observed in the optional completionHandler
.
Zendesk.instance?.loginUser(with: "your_jwt_here") { result in
switch result {
case .success(let user):
// Handle successful authentication
case .failure(let error):
// Handle authentication failure
}
}
Objective-C
Zendesk *instance = [Zendesk instance];
[instance loginUserWith:@"your_jwt_here" completionHandler:^(ZDKZendeskUser * _Nullable user, NSError * _Nullable error) {
// ...
}];
Note:
During login, if the SDK fails to authenticate the user using loginUser
, an unauthenticated user will be created as a fallback. This ensures the user can still access messaging features, but their identity will not be verified until a successful authentication occurs.
Additionally, if your integration uses multiple instances of the Zendesk SDK, each loginUser
call will assign a different user to each instance. For more information on switching between SDK instances, see SDK Instances.
LogoutUser
To unauthenticate a user, call the logoutUser
API. This will remove the user's authentication and clear their session from the SDK.
Usage:
Swift
The result of logoutUser
can be observed in the optional completionHandler
.
Zendesk.instance?.logoutUser { result in
switch result {
case .success:
// Handle successful logout
case .failure(let error):
// Handle logout failure
}
}
Objective-C
Zendesk *instance = [Zendesk instance];
[instance logoutUserWithCompletionHandler:^(NSError * _Nullable error) {
// ...
}];
This function is intended mainly for authenticated users. When an unauthenticated user next accesses the conversation screen after logout, a new user profile and conversation will be created.
Authentication lifecycle
Once loginUser
is successful, the user remains authenticated until the token expires, an authentication error occurs, or you explicitly call logoutUser
to end the session.
You can create your JWT with an expiration timestamp using the optional exp
property. See Creating a JWT token.
Authentication expiration and re-authentication
When the token expires, the server will return a expiredJWT
error indicating "The JWT has expired". This error can be captured through the authenticationFailed
event listener. When this occurs, you can seamlessly re-authenticate the user by providing a new JWT using the AuthenticationDelegate
(recommended), which allows the SDK to refresh the token automatically. If you do not use the delegate, you must manually call loginUser
to re-authenticate. If the now unauthenticated user attempts to start a conversation, they will be directed to the conversation screen with an error, and the conversation content will not be visible.
Since the SDK doesn't automatically renew the token, you will have to handle the re-authentication process.
Handling authentication failures with ZendeskEvent.authenticationFailed
You can log any authentication failures from the SDK using ZendeskEvent.authenticationFailed
. This is useful for debugging or troubleshooting authentication issues. However, for production apps, it is recommended to use the AuthenticationDelegate
for seamless token refresh and re-authentication (see below). The following example demonstrates a manual approach for handling JWT expiry:
Swift
Below is a code sample how to reauthenticate a user after their JWT has expired.
Zendesk.instance?.addEventObserver(self) { event in
switch event {
case .authenticationFailed(let error as NSError):
if error.localizedDescription.contains("The JWT has expired") {
// Handle logging for event
Using AuthenticationDelegate for token refresh
To simplify handling token expiry and re-authentication, you can use the AuthenticationDelegate
. This delegate allows your app to provide a new JWT token when the SDK detects an invalid or expired token, enabling seamless re-authentication for the end user.
Implement the AuthenticationDelegate
protocol then initialize and assign the implemented class.
final class ZendeskAuthenticationDelegate: AuthenticationDelegate {
private let authHandler: (@escaping (String) -> Void) -> Void
init(authHandler: @escaping (@escaping (String) -> Void) -> Void) {
self.authHandler = authHandler
}
func onInvalidAuth(_ completion: @escaping (String) -> Void) {
authHandler(completion)
}
}
Zendesk.authenticationDelegate = ZendeskAuthenticationDelegate { completion in
Task {
// Fetch or generate a new JWT token from your backend
let newJwtToken = fetchNewJwtFromBackend()
// Provide the new token to the SDK
completion(newJwtToken)
}
}
- The
onInvalidAuth
method is called when the SDK detects an invalid or expired JWT. - You should fetch or generate a new JWT from your backend and pass it to the completion handler.
- This approach ensures the user remains authenticated without manual intervention or interruption to their conversation.
Authentication merges
When the loginUser
API identifies that an unauthenticated user in the Zendesk SDK matches an existing user in Zendesk (for example, from previous activity on another device or platform), the SDK will merge the data from both the unauthenticated and authenticated user accounts. For more information, see Merging because of a login event.
This allows a user to start a conversation while unauthenticated and then log in seamlessly, with their conversation history and data combined under their authenticated account.
- Single-conversation: Once logged in, the user will see that their previous conversation has been combined with conversations from their logged-in account, allowing them to continue seamlessly as an authenticated user.
- Multi-conversation: Once logged in, the user will see that their previous conversations in the conversation list screen appear alongside the conversations from their logged-in account, providing a unified experience.
Checking the current SDK user and authentication state
Zendesk.getCurrentUser
checks the current SDK user and their authentication status at any time. This allows you to determine if the user is authenticated or unauthenticated, and to access the new ZendeskAuthenticationType
property on the ZendeskUser
object.
Swift
var currentUser = Zendesk.instance?.getCurrentUser()
if currentUser?.authenticationType == .jwt {
// User is authenticated with JWT
} else {
// User is unauthenticated
}
Objective-C
User *currentUser = [[Zendesk instance] getCurrentUser];
if (currentUser != nil && currentUser.authenticationType == AuthenticationTypeJWT) {
// User is authenticated with JWT
} else {
// User is unauthenticated with JWT
}
Common pitfalls & troubleshooting
Token expiry during a conversation
- If the JWT expires while the user is active, the recommended approach is to use the
AuthenticationDelegate
. This delegate allows your app to seamlessly provide a new JWT token when the SDK detects an invalid or expired token, ensuring the user remains authenticated without interruption. - The SDK will trigger the delegate's
onInvalidAuth
method, where you should fetch or generate a new JWT from your backend and pass it to the completion handler. - This approach provides a robust and user-friendly way to handle token expiry and re-authentication.
Example: Handling token expiry with AuthenticationDelegate
Zendesk.authenticationDelegate = ZendeskAuthenticationDelegate { completion in
Task {
// Fetch or generate a new JWT token from your backend
let newJwtToken = fetchNewJwtFromBackend()
// Provide the new token to the SDK
completion(newJwtToken)
}
}
- The
onInvalidAuth
method is called when the SDK detects an invalid or expired JWT. - You should fetch or generate a new JWT from your backend and pass it to the completion handler.
- This ensures the user remains authenticated without manual intervention or interruption to their conversation.
User merges when authenticating after unauthenticated use
If a user starts a conversation while unauthenticated and then logs in, Zendesk will attempt to merge the unauthenticated and authenticated user data. For more information, see Merging because of a login event.
This can result in conversation history being combined, which may be confusing if not expected.
- To avoid unwanted merges, always authenticate users before showing the messaging UI. Ideally,
loginUser
should be called as soon as the user is logged into your app. - If you must allow unauthenticated use, clearly communicate to users that their conversations may be merged upon login.
Best practices for authentication
- Authenticate Early: Always authenticate users before displaying the messaging screen to avoid unwanted merges and ensure a seamless experience.
- Check JWT Expiry: Before calling
loginUser
, check that the JWT is not close to expiry. If it is, generate a new token. - Handle Expiry Gracefully: Use the
AuthenticationDelegate
to automatically handle JWT expiry. When the SDK detects an expired or invalid JWT, the delegate'sonInvalidAuth
method is triggered, allowing your app to fetch or generate a new JWT from your backend and seamlessly update the user's authentication without interrupting their conversation. This is the recommended approach for robust, user-friendly token refresh. - Communicate to Users: If your flow allows starting a conversation while unauthenticated, inform users that their conversations may be merged with their authenticated account later.
FAQ
Q: What happens if my JWT expires during a conversation?
- A: The SDK emits an
AuthenticationFailed
event. The recommended approach is to use theAuthenticationDelegate
, which allows your app to seamlessly provide a new JWT token and automatically re-authenticate the user without interruption to their conversation.
Q: Why do conversations merge when a user logs in after starting while unauthenticated?
- A: Zendesk merges the unauthenticated and authenticated user data to provide a seamless experience.
Q: How long does a user stay logged in?
- A: The user remains authenticated until an authentication error occurs, or you explicitly call
logoutUser
with a valid JWT. If the user's JWT token is invalidated and a new one cannot be retrieved using theAuthenticationDelegate
, the user will also be implicitly logged out and will need to be re-authenticated to regain access to authenticated features.
Q: How can I check if the current user is authenticated or anonymous?
A: Use the new Zendesk.getCurrentUser()
API. This returns a ZendeskUser
object, which includes the authenticationType
property. You can check if authenticationType
is authenticated or unauthenticated.
Q: What does Zendesk.getCurrentUser()
return if no user is logged in?
A: If no user is logged in, the SDK will return the current unauthenticated user object.
Q: Does the SDK automatically clear user data or create a new anonymous user on authentication failure?
A: No. The SDK now emits an AuthenticationFailed
event and maintains the current user state until a valid JWT is provided.
Q: How can I use the current user API to improve my authentication flow?
A: You can check the user's authentication status before displaying sensitive features or prompting for login, and handle authentication state transitions more reliably in your app.