Skip to main content

Authorization checks

It's best practice to always verify whether or not a user is authorized to access sensitive information, important content, or exclusive features. Authorization is the process of determining the access rights and privileges of a user, ensuring they have the necessary permissions to perform specific actions.

Clerk provides two main features that can be used to implement authorization checks:

  • Organizations
  • Billing
    • Users can subscribe to Plans and Features
    • Useful for Subscription-based and Feature-based access control

In your Android application, use Clerk.has() to check whether the signed-in user is authorized. It returns false when no user is signed in, and when the session isn't active, for example while the user still has session tasks to complete.

Important considerations

  • When doing authorization checks, it's recommended to use Permission-based over Role-based, and Feature-based over Plan-based authorization, as these approaches are more granular, flexible, and more secure.
  • Checking for a Role or Permission depends on the user having an . Without an Active Organization, Role and Permission checks return false.
  • has() runs on the device and only controls what your app shows. Always check authorization again on your backend before returning protected data or performing a protected action. See the Backend has() helper.

Check Roles and Permissions

if (Clerk.has(permission = "org:invoices:create")) {
    // Create the invoice.
}

if (Clerk.has(role = "org:admin")) {
    // Show admin actions.
}

Clerk.has() reads the session at the moment you call it. In a composable, collect Clerk.sessionFlow and call checkAuthorization() on the session so the UI updates when the session changes. checkAuthorization() doesn't check the session's status, so only call it on an active session to match Clerk.has().

@Composable
fun InvoiceActions() {
    val session by Clerk.sessionFlow.collectAsState()
    val activeSession = session?.takeIf { it.status == Session.SessionStatus.ACTIVE }

    if (activeSession?.checkAuthorization(permission = "org:invoices:create") == true) {
        Button(onClick = { /* Create the invoice. */ }) {
            Text("Create invoice")
        }
    }
}

Check Plans and Features

A Plan or Feature slug without a prefix matches either the user's or the Subscription. Prefix it with user: or org: to check only one of them.

if (Clerk.has(feature = "widgets")) {
    // Show the widgets Feature.
}

if (Clerk.has(plan = "org:gold")) {
    // Show content for Organizations on the Gold Plan.
}

Plan and Feature checks read the current session token, so a Subscription change is reflected after the session token refreshes. To read Subscription details, use the Billing APIs.

Require recent reverification

Pass a reverification requirement to check whether the user has reverified recently. You can check it on its own, or together with other conditions. When you pass more than one condition, has() returns true only if all of them pass.

if (Clerk.has(reverification = ReverificationConfig.Strict)) {
    // The user reverified in the last 10 minutes.
}

if (Clerk.has(permission = "org:invoices:delete", reverification = ReverificationConfig.Moderate)) {
    // Show the Delete invoice button.
}

val recentlyVerified =
    Clerk.has(
        reverification = ReverificationConfig.Custom(
            level = SessionVerification.Level.FIRST_FACTOR,
            afterMinutes = 30,
        ),
    )

The reverification presets are:

PresetLevelMaximum age
ReverificationConfig.StrictMfaMulti-factor10 minutes
ReverificationConfig.StrictSecond factor10 minutes
ReverificationConfig.ModerateSecond factor1 hour
ReverificationConfig.LaxSecond factor1 day

For a user who hasn't set up a second factor, the second-factor and multi-factor presets accept a recent first factor instead.

Check a specific session

Clerk.has() checks the current session, and only when it's active. To check another session, for example in an app that supports multiple sessions, call checkAuthorization() on that Session with the same arguments.

Feedback

What did you think of this content?

Last updated on