> ## Documentation Index
> Fetch the complete documentation index at: https://stytch.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Enforcing Permissions

> Enforce RBAC permissions in your application's frontend and backend

export const member = "Represents an individual end user's account within a given Organization, uniquely identified within that Organization by their email address.";

export const jwt = "JSON Web Token: an open standard for securely transmitting information between parties as a compact and self-contained JSON object.";

To enforce RBAC permissions in your application, it is critical to both:

* Gate various UI and <Tooltip tip={member}>Member</Tooltip> actions in your application's frontend
* Confirm authentication and authorization on your backend before honoring requests from the client

## Frontend authorization checks

Use Stytch's frontend SDKs to check user permissions client-side.

<Columns cols={4}>
  <Card title="React SDK" icon="react" href="/api-reference/b2b/frontend-sdks/react/hooks/use-stytch-is-authorized" arrow={true} />

  <Card title="Next.js SDK" icon="triangle" href="/api-reference/b2b/frontend-sdks/nextjs/hooks/use-stytch-is-authorized" arrow={true} />

  <Card title="Vanilla JS SDK" icon="js" href="/api-reference/b2b/frontend-sdks/vanilla-js/methods/rbac/is-authorized" arrow={true} />

  <Card title="React Native" icon="react" href="/api-reference/b2b/mobile-sdks/react-native/hooks/use-stytch-is-authorized" arrow={true} />
</Columns>

### Conditionally render UI based on permissions

It's good practice to adapt UI based on permissions, even if your backend will enforce permissions on the server-side.

<CodeGroup>
  ```jsx React icon="react" theme={null}
  import { useStytchIsAuthorized } from '@stytch/react/b2b';

  const DocumentActions = () => {
    // Use the useStytchIsAuthorized hook to check if the current Member is authorized to perform an action.
    const { isAuthorized: canReadDocument } = useStytchIsAuthorized('documents', 'read');
    const { isAuthorized: canWriteDocument } = useStytchIsAuthorized('documents', 'write');
    return (
      <div>
        { /* Disable a button if the Member is not authorized */ }
        <button disabled={!canReadDocument}>View Document</button>}
        { /* or just hide the button entirely */ }
        {canWriteDocument && <button>Edit Document</button>}
      </div>
    );
  };
  ```

  ```jsx Next.js icon="triangle" theme={null}
  import { useStytchIsAuthorized } from '@stytch/nextjs/b2b';

  const DocumentActions = () => {
  // Use the useStytchIsAuthorized hook to check if the current Member is authorized to perform an action.
  const { isAuthorized: canReadDocument, isInitialized: isReadDocumentInitialized } = useStytchIsAuthorized('documents', 'read');
  const { isAuthorized: canWriteDocument, isInitialized: isWriteDocumentInitialized } = useStytchIsAuthorized('documents', 'write');

  if (!isReadDocumentInitialized || !isWriteDocumentInitialized) {
    return <p>Loading...</p>;
  }

  return (
    <div>
      { /* Disable a button if the Member is not authorized */ }
      <button disabled={!canReadDocument}>View Document</button>}
      { /* or just hide the button entirely */ }
      {canWriteDocument && <button>Edit Document</button>}
    </div>
  );
  };
  ```

  ```jsx Vanilla JS icon="js" theme={null}
  import { StytchB2BClient } from '@stytch/vanilla-js/b2b';

  const stytch = new StytchB2BClient(process.env.STYTCH_PUBLIC_TOKEN);

  // Fetch specific permissions for the current Member.
  const canReadDocument = await stytch.rbac.isAuthorized('documents', 'read');
  const canWriteDocument = await stytch.rbac.isAuthorized('documents', 'write');

  // Or just fetch ALL permissions for the current Member.
  const allPermissions = await stytch.rbac.allPermissions();
  ```
</CodeGroup>

### Check permissions before making API requests

You should also do pre-emptive client-side authorization checks to avoid any unnecessary API requests or ensure the user isn't about to enter a flow they cannot complete.

```jsx theme={null}
const canReadDocument = await stytch.rbac.isAuthorized('documents', 'read');
if (!canReadDocument) {
  throw new Error('You do not have permission to read documents');
}
loadDocument();
```

### Built-in Stytch Resource authorization

Stytch's frontend SDKs offer built-in RBAC protections, allowing you to make requests directly from your public client without proxying through your backend.

When you call methods like `organization.update()` or `magicLinks.email.invite()` directly from the client:

1. The frontend SDK will automatically include the logged in member's session in the request to the Stytch API.
2. The Stytch API will only authorize the request if the session is valid and the Member has at least one Role that grants them permission to take that action.

To enable the SDK to make these requests, enable **Member actions & organization modifications** in the [Stytch Dashboard](https://stytch.com/dashboard/sdk-configuration).

## Backend authorization checks

Regardless of if you are using Stytch's frontend SDKs, you must always perform server-side authorization checks before proceeding with a request by authorizing a valid Session Token or <Tooltip tip={jwt}>JWT</Tooltip>.

<Tabs>
  <Tab title="Session Tokens">
    If you are using **Session Tokens**, [session authentication](/api-reference/b2b/api/sessions/authenticate-session) will trigger an outbound call to Stytch and authorization will be done on Stytch's servers.

    ```mermaid theme={null}
    sequenceDiagram
        participant Client
        participant You Application
        participant Stytch API
        Client->>You Application: POST api/document with session_token
        You Application->>Stytch API: sessions.authenticate() with authorization_check
        Note over Stytch API: Verifies session_token is valid and does authorization check
        Stytch API->>You Application: Returns authorized:true and a fresh session_token
        Note over You Application: Save document edits
        You Application->>Client: 200 response, set session_token in cookies
    ```

    For example to check authorization in a python backend:

    ```python theme={null}
    resp = stytch_client.sessions.authenticate(
      session_token='mZAYn5aLEqKUlZ_Ad9U_fWr38GaAQ1oFAhT8ds245v7Q',
      authorization_check={
        'organization_id': 'organization-test-07971b06-ac8b-4cdb-9c15-63b17e653931',
        'resource_id': 'documents',
        'action': 'edit',
      }
    )

    if resp.status_code != 200: # The Member is not authenticated, redirect to login page
        return 'not authenticated', 401

    if not resp.authorized: # The Member is authenticated, but does not have permission to edit the document
        return 'unauthorized', 403

    # Member is authenticated and has permission to edit the document
    save_document_edits()
    ```
  </Tab>

  <Tab title="JWTs">
    If you are using **Session JWTs**, the Member's Roles are contained in the JWT.

    When using [`authenticateJwt()`](/api-reference/b2b/api/sessions/authenticate-jwt), authorization checks will be done locally during the lifetime of the JWT without incurring any additional latency of an outbound call.  Stytch's backend SDKs will cache your Project's RBAC policy and refresh it every five minutes, ensuring that any RBAC policy changes are incorporated into local evaluations within 5 minutes.

    If `authenticateJwt()` method detects the JWT is expired, it will make an outbound call to Stytch to refresh the JWT. This ensures that any changes to the Member's Role will take effect within five minutes and that the underlying session has not been revoked.

    ```mermaid theme={null}
    sequenceDiagram
        participant Client
        participant You Application
        participant Stytch Backend SDK
        participant Stytch API
        Client->>You Application: POST api/document<br />with session_jwt
        Stytch Backend SDK-->>Stytch API: Periodic refresh of RBAC policy
        You Application->>Stytch Backend SDK: sessions.authenticateJwt()<br />with authorization_check
        Note over Stytch Backend SDK: sessions.authenticateJwtLocal()
        opt If JWT is expired
          Stytch Backend SDK->>Stytch API: sessions.authenticateJwt()<br />with authorization_check
          Note over Stytch API: Verifies session_jwt is valid<br />and does authorization check
          Stytch API->>Stytch Backend SDK: Returns fresh JWT and AuthZ verdict
        end
        Stytch Backend SDK->>You Application: returns authorized:true<br />and session_jwt
        Note over You Application: Save document edits
        You Application->>Client: 200 response,<br />set session_jwt in cookies
    ```

    ```python theme={null}
    resp = stytch_client.sessions.authenticateJwt(
      session_jwt="eyJ...",
      authorization_check={
        'organization_id': 'organization-test-07971b06-ac8b-4cdb-9c15-63b17e653931',
        'resource_id': 'documents',
        'action': 'edit',
      }
    )

    if resp.status_code != 200: # The Member is not authenticated, redirect to login page
        return 'not authenticated', 401

    if not resp.authorized: # The Member is authenticated, but does not have permission to edit the document
        return 'unauthorized', 403

    # Member is authenticated and has permission to edit the document
    save_document_edits()
    ```
  </Tab>
</Tabs>

### Built-in Stytch Resource authorization

Any Stytch API endpoints and Backend SDK methods that act on a [default Stytch Resource](/multi-tenant-auth/enterprise-ready/rbac/create-rbac-policy#default-roles-and-resources) (e.g. `stytch.self` or `stytch.organization`) support passing the Member's Session Token or Session JWT to have Stytch perform authentication *and* authorization prior to honoring the request.

This allows the authentication and authorization checks to occur as close as possible to the action being taken, streamlining your handling.

For example, if a Member makes a request to delete another Member from an Organization, you can pass their Session Token or JWT into the `organizations.members.delete()` call. Stytch will authenticate the session and perform an authorization check prior to honoring the call.

<CodeGroup>
  ```python Python icon="python" highlight={4-8} theme={null}
  resp = stytch_client.organizations.members.delete(
    organization_id="organization-test-07971b06-ac8b-4cdb-9c15-63b17e653931",
      member_id="member-test-32fc5024-9c09-4da3-bd2e-c9ce4da9375f",
      method_options=DeleteRequestOptions( # [!code ++:5]
          authorization=Authorization(
              session_token="<session_token>",
          ),
      ),
  )
  ```

  ```bash cURL icon="https://d3gk2c5xim1je2.cloudfront.net/devicon/bash.svg" theme={null}
  curl --request DELETE \
    --url https://test.stytch.com/v1/b2b/organizations/organization-test-07971b06-ac8b-4cdb-9c15-63b17e653931/members/member-test-32fc5024-9c09-4da3-bd2e-c9ce4da9375f \
    -u '<project_id>:<project_secret>' \
    -H 'Content-Type: application/json' \
    -H "X-Stytch-Member-Session: <session_token>" # [!code ++]
  ```
</CodeGroup>
