Your MCP server can give an agent a one-time link that opens a browser already signed in as the user.
Agents that use a browser can now get past your app's sign-in page without asking the user for a password. By default, Clerk's Frontend API refuses sign-out, Organization switches, and profile changes from the session.
Enforce your own session limits with session token shortcodes, or change one session's expiry with a new Backend API endpoint.
On a paid plan, you can now set session limits per user or device, beyond your instance's custom session lifetime and native app lifetime. For example, enforce shorter sessions on a shared device, or longer ones at a user's choice. Clerk offers two ways to do this.
Revoke sessions based on age from your application
Your backend can then apply whatever rule you need, such as a different limit for business customers. When a session is past your limit, reject the request and revoke the session using the sid claim. Revoking stops the session from getting new tokens, but the token it already has stays valid until it expires, so keep rejecting requests from that session. This approach can only end sessions sooner than your instance's lifetime.
Change a single session's expiry
Use the Backend API to update a session and set a new expire_at, between 5 minutes and 10 years from now. It can be earlier or later than your instance's lifetime.
The change applies only to that session. New sign-ins still start from your instance's lifetime.
Expired, revoked, and other ended sessions can't be revived, and impersonation and agent sessions can't be updated.
The session's inactivity timeout, if it has one, still applies.
Take the session ID from the sid claim of a verified session token, or from a verified webhook such as session.created. Never take it from an unverified client request.
GET /v1/logs now returns email events, and the Application Logs page in the Dashboard shows them next to every other event.
Email events (email.*) are now part of Application Logs. You can fetch them with the GET /v1/logs endpoint of the Backend API. Set type to email.* and payload_filter[recipient_email] to an address to find that recipient's emails. Call the endpoint from your own code or an AI agent to check whether a specific email was delivered to the recipient's mail server.
The Application Logs page in the Dashboard shows email events alongside every other event type, so the unfiltered feed puts a sign-up and its verification email in one timeline.
The Email Logs page still shows them, with three changes:
Recipient, IP address, and message ID filters match exactly instead of by substring.
Blocked sends appear as Bounced or Failed.
Message ID shows the Clerk email ID when one is available.
Email events go back to October 5, 2026, or as far as your plan's retention period allows.
Application Logs now show each sign-in and sign-up as one row, and GET /v1/logs returns groups by default.
Application Logs in the Dashboard now group sign-in and sign-up events. Each sign-in or sign-up shows up as one row with its event count and, once it finishes, whether it completed or failed. Expand a row to see its events in order.
By default, the logs page opens on the Group view. To see one row per event, switch to List next to the refresh button. In the Group view, use the Group filter to show only sign-ins or only sign-ups, and the Status filter to show only groups that completed or failed.
Backend API
GET /v1/logs now returns grouped logs by default. If your code expects one item per event, pass view=flat.
By default, native sessions follow the web browser settings, as they did before. You can set a custom maximum lifetime between 5 minutes and 10 years. Native sessions then use it instead of the web maximum lifetime and inactivity timeout. Session tokens stay short-lived, and SDKs keep refreshing them.
Note
A custom native lifetime is free in development instances. In production, your application needs the Pro or Business plan. See the pricing page for details.
Changes only apply to sessions created after you save. Existing sessions keep the lifetime they were created with. To end them sooner, revoke them.
Get started
You don't need to update your SDK.
In the Clerk Dashboard, navigate to the Sessions page.
Under Native sessions, select Custom maximum lifetime and set a duration.
Select Save.
To make native sessions follow the web browser settings again, select Same as web, then select Save. See native session lifetime settings for details.
Directory Sync sends webhooks for group and membership changes, the Backend API reads a group and its members, and a directory can be paused without removing anyone's access.
Directory Sync has three new capabilities: webhooks for group changes, Backend API reads for a group and its members, and a pause switch for directories. Group pushes from the identity provider also produce fewer events than before.
Group webhooks
Directory Sync keeps Organization memberships and Roles in step with your identity provider, but until now the groups themselves were hard to observe. That matters most when your application maps identity provider groups onto its own objects, such as teams or projects, rather than onto Clerk Organizations alone. The only signal was the user.updated event Directory Sync fires for each member it touches. Your webhook handler fetched the user, read their current groups, and worked out what changed. When an IT admin deleted a group in the identity provider, that produced the same events as every member leaving at once, and nothing in them told the two apart.
Six webhook events now report group changes directly:
directoryGroup.created: the identity provider created a group.
directoryGroup.updated: the identity provider renamed a group. The payload carries the new display_name.
directoryGroup.deleted: the identity provider deleted a group, or it stopped appearing in a pull sync. The payload carries the last known name.
directoryGroup.synced: the identity provider pushed a group in full, whether or not anything changed. Okta sends that push on Push now and on its periodic re-push of unchanged groups, so the event fires once per group per push. It isn't sent for pull-synced directories such as Google Workspace.
directoryGroupMembership.created: a user was added to a group.
directoryGroupMembership.deleted: a user was removed from a group. cause says why: member_removed when the provider took the user out, group_deleted when the whole group went away.
Every payload names the directory_id and the group's id and display_name. Membership payloads also carry the member's directory_user_id and the user_id of the Clerk user they're linked to, which is null until that user has been provisioned.
Webhooks can arrive out of order. When two events describe the same group or membership, keep the one with the later updated_at, which is when the directory recorded the change.
A webhook handler that receives a directoryGroup.* event can fetch the group's current state with these reads instead of keeping its own copy of the directory.
Fewer user.updated events on group pushes
Since October 20, a group push from the identity provider records only the members who joined or left. The per-user events a push produces, such as directoryGroupMembership.created and user.updated, cover those users alone. The group-level events don't depend on who changed: a rename sends directoryGroup.updated, and every push sends directoryGroup.synced, so a push with nothing changed sends that one event and nothing else. Before, every push rewrote the whole group, so every member counted as changed on every push, and large groups that Okta re-pushes every few minutes timed out.
If you relied on that fan-out to replay a group, for example by asking a customer to Push now in Okta so your application could rebuild its memberships, listen for directoryGroup.synced instead and page through the group with the members endpoint. That's one event per group per push, however many members the group has.
Pause a directory
A directory can now be paused, from its page in the Clerk Dashboard or by sending paused to PATCH /v1/directories/{directory_id}. Directory responses include the flag. A paused directory rejects provisioning requests and skips scheduled syncs, but keeps the memberships it granted. After you resume a SCIM directory, trigger a resync from the identity provider so it pushes its current state. Requests it sent while the directory was paused were rejected, not queued. A pull-synced directory catches up on its next sync. Disabling a directory withdraws the access it granted instead, so pause when you want changes to stop landing for a while without touching anyone's access.