BlogDocumentation
Products
Identity ProtectionIdentity ManagementBlogDocumentation
Vincenzo Iozzo
Vincenzo Iozzo
6 Mar, 2024
Introduction Custom claims with webhooks 1. Prerequisites 2. Serve the webhook locally 3. Define and register the webhook 4. Test it on a real application Conclusion
Deep Dives
Adding custom claims to identity tokens

Adding custom claims to JWTs allows you to share identity information without repeated queries to external data sources.

Read on to learn how to customize claims with SlashID's webhooks.

Adding custom claims to identity tokens

Introduction

Identity token claims contain information about the subject, such as email addresses, roles, risk scores, and more, specified as key-value pairs. JWTs support two different types of claim fields:

  • Standard: these claim names are registered and are commonly included in tokens as industry standards.
  • Custom: you can specify additional information to be added to your tokens.

It’s easy to add custom claims to SlashID-issued tokens. For example, you can add meaningful details about the user who is logging in into your web app, such as their name, physical address, or roles.

SlashID provides three ways to add custom claims:

  • Using synchronous webhooks during registration/authentication.
  • Using Gate.
  • Using our token minting API from your backend.

Read on to see an example of token enrichment using webhooks. If you are interested in our other approaches, take a look at the Gate documentation or our token minting API.

We believe our approach has several advantages compared to others, in particular:

  • Testability: it is significantly easier to test custom authentication logic via webhooks compared to hosted scripts or other approaches;
  • Data protection: by using a webhook you never expose key material (e.g., credentials to access a database with the enrichment information) or sensitive data to SlashID.
  • Flexibility: you can customize the token at any step of its journey, including at your backend level when you need to differentially enrich tokens for specific microservices.

You can find the code for this example in our GitHub repo.

Custom claims with webhooks

SlashID supports both synchronous and asynchronous webhooks to hook all interactions between a user and SlashID, such as authentication attempts, registration, changes in attributes, and more.

You can create and manage webhooks using a simple REST API - see the full documentation here.

Webhooks can be attached to multiple triggers, which are either asynchronous (events) or synchronous (sync hooks). To customize token claims, we will need to use the token_minted sync hook. This hook is called for every authentication/registration attempt before a token is issued.

The webhook registered with the token_minted trigger will receive the claims of the token that SlashID is about to mint for a user. The webhook’s response can block the issuance, enrich it with custom claims, or do nothing.

A typical token received by the webhook looks as follows:

{
  "aud": "e2c8a069-7e89-cc7e-b161-3f02681c6804",
  "exp": 1697652845,
  "iat": 1697652545,
  "iss": "https://api.slashid.com",
  "jti": "2479ec0e-aad5-47ca-a12b-214ddaf7fc85",
  "sub": "065301f4-1c74-7636-ad00-da1923dc00f9",
  "target_url": "https://7b9c-206-71-251-221.ngrok.io/pre-auth-user-check",
  "trigger_content": {
    "aud": "e2c8a069-7e89-cc7e-b161-3f02681c6804",
    "authentications": [
      {
        "handle": {
          "type": "email_address",
          "value": "[email protected]"
        },
        "method": "oidc",
        "timestamp": "2023-10-18T18:08:57.9002598Z"
      }
    ],
    "first_token": true,
    "groups_claim_name": "groups",
    "iss": "https://api.slashid.com",
    "region": "europe-belgium",
    "request_metadata": {
      "client_ip_address": "206.71.251.221",
      "origin": "http://localhost:8080",
      "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"
    },
    "sub": "065158a6-33f2-725e-a208-9d773600513a"
  },
  "trigger_name": "token_minted",
  "trigger_type": "sync_hook",
  "webhook_id": "065301dd-b26d-7d7e-b500-6a7f180b2cdb"
}

Using Python’s FastAPI framework, we will add three custom claims to a token: a user name, a fictional department, and a flag stating whether the user is in the office based on their IP address.

1. Prerequisites

  • Python 3.6+
  • ngrok: https://ngrok.com/download
  • A SlashID account. Obtain the SlashID ORG_ID and API_KEY from the Settings page as shown below. Register here for a free account.
Org ID API Key

2. Serve the webhook locally

  • ngrok http 8001: create local tunnel; please take note of the ngrok-provided URL in ngrok’s output, you’ll need to set it as the webhook’s base target_url
  • ORG_ID=[/id Org ID] API_KEY=[/id API key] uvicorn webhook:app --port 8001 --reload: serve the webhook locally

NOTE: Make sure that the port is not used by any other service

3. Define and register the webhook

Let’s first register the webhook and attach it to the token_minted event.

curl -X POST --location 'https://api.slashid.com/organizations/webhooks' \
--header 'SlashID-OrgID: <ORGANIZATION ID>' \
--header 'SlashID-API-Key: <API KEY>' \
--header 'Content-Type: application/json' \
--data '{
    "target_url": "https://ngrok-url/user-auth-hook",
    "name": "user enrichment",
    "description": "Webhook to receive notifications when a user attempts login or registration"
}'

{
    "result": {

        "description": "Webhook to receive notifications when a user attempts login or registration",
        "id": "16475b49-2b12-78d7-9012-cfe0e174dcd3",
        "name": "user enrichment",
        "target_url": "https://ngrok-url/user-auth-hook"
    }
}
curl -X POST --location 'https://api.slashid.com/organizations/webhooks/16475b49-2b12-78d7-9012-cfe0e174dcd3/triggers' \
--header 'SlashID-OrgID: <ORGANIZATION ID>' \
--header 'SlashID-API-Key: <API KEY>' \
--header 'Content-Type: application/json' \
--data '{
    "trigger_type": "sync_hook",
    "trigger_name": "token_minted"
}'

Now that the webhook is registered, let’s take a look at a toy example for https://api.example.com/slashid-webhooks/user-auth-hook.

import os
from fastapi import FastAPI, Depends, HTTPException, Request, status
from fastapi.responses import JSONResponse
import jwt
import requests
from datetime import datetime
import json

def verify_extract_token(request_body):
    jwks_client = jwt.PyJWKClient("https://api.slashid.com/organizations/webhooks/verification-jwks", headers={"SlashID-OrgID": "<ORGANIZATION ID>"})
    webhookURL = ""

    try:
        header = jwt.get_unverified_header(request_body)
        key = jwks_client.get_signing_key(header["kid"]).key
        token = jwt.decode(request_body, key, audience="<SLASHID_ORGANIZATION ID>", algorithms=["ES256"])

        if token['target_url'] != webhookURL:
            raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=f"Token {token} is invalid: {e}",
        )
    except Exception as e:
        raise HTTPException(
          status_code=status.HTTP_401_UNAUTHORIZED,
          detail=f"Token {token} is invalid: {e}",
      )
    return token

app = FastAPI()

@app.post("/user-auth-hook")
def hook_function(request: Request):

    request_body = await request.body()

    # Now the request has been validated
    token = verify_extract_token(request_body)

    print(json.dumps(token, indent=4))

    #extract the email address of the user
    handle = token['trigger_content']['authentications'][0]['handle']['value']
    ip_address = token['trigger_content']['request_metadata']['client_ip_address']

    print(f"User handle {handle} and IP address {ip_address}\n")

    if handle == "[email protected]":
        in_office = False
        if ip_address == "10.20.30.40":
            in_office = True

        return JSONResponse(status_code=status.HTTP_200_OK, content={
            "department": "R&D",
            "name": "Alex Singh",
            "in_office": in_office
        })
    else:
        return JSONResponse(status_code=status.HTTP_200_OK, content={})

4. Test it on a real application

You can use one of the SlashID sample applications to test this live.

If everything works as expected, you’ll see the customized token with your claims in the context bar on the left once the user logs in.

Conclusion

In this guide, we’ve shown you how to add custom claims to your tokens via synchronous webhooks. We’d love to hear any feedback you may have: please reach out to us at [email protected]!

Try out SlashID with a free account.

Related articles

A deep dive in the AWS credential leaks reported by Palo Alto Networks

Deep Dives

/ 22 Aug, 2024

A deep dive in the AWS credential leaks reported by Palo Alto Networks

Thousands of credentials were exfiltrated from exposed .env files in the latest large-scale attack uncovered by Palo Alto.

Protecting cloud services and non-human identities spread across many vendors and environments is now table-stakes: SlashID can help.

Vincenzo Iozzo
Vincenzo Iozzo
Passkeys Adoption Trends: Survey from Large Deployments

Deep Dives

/ 31 Jan, 2024

Passkeys Adoption Trends: Survey from Large Deployments

In this comprehensive blog post, we delve into the publicly available data on large-scale passkeys rollouts, examining results, conversion rates, and implementation challenges as documented in engineering blogs by companies like Kayak and Yahoo Japan.

Vincenzo Iozzo
Vincenzo Iozzo
Backend Authentication and Authorization Patterns: Benefits and Pitfalls of Each

Deep Dives

/ 28 Sep, 2023

Backend Authentication and Authorization Patterns: Benefits and Pitfalls of Each

Identity in distributed applications is hard. In large and complex environments with multiple services, a number of patterns have emerged to authenticate and authorize traffic.

In this article, we’ll discuss the most common ones, how to implement them, and their pros and cons.

Vincenzo Iozzo
Vincenzo Iozzo

Ready to start a top-tier security upgrade?

Terms · Privacy · System Status
© 2025 SlashID® Inc. All Rights Reserved.

Products

Identity Protection Identity Management

Resources

Blog Get in touch

We use cookies to improve your experience. Read our cookie policy.