### Install Keycloak Extension (Standalone) Source: https://github.com/medihause/keycloak-totp-api/blob/main/README.md Installs the Keycloak TOTP API extension in a standalone Keycloak environment. This involves copying the generated JAR file to the `providers` directory and rebuilding Keycloak using the `kc.sh build` command. ```bash ${KEYCLOAK_HOME}/bin/kc.sh build ``` -------------------------------- ### Install Keycloak Extension (Docker Volume Mount) Source: https://github.com/medihause/keycloak-totp-api/blob/main/README.md Installs the Keycloak TOTP API extension in a Dockerized Keycloak environment by mounting the extension JAR file into the container's providers directory. This makes the extension available to the Keycloak server upon container startup. ```bash -v /path/to/keycloak-totp-api-1.0.0-all.jar:/opt/keycloak/providers/keycloak-totp-api-1.0.0-all.jar ``` -------------------------------- ### Install Keycloak Extension (Docker Custom Image) Source: https://github.com/medihause/keycloak-totp-api/blob/main/README.md Installs the Keycloak TOTP API extension by copying the extension JAR file into a custom Docker image. This is done within the Dockerfile, ensuring the extension is included when the custom Keycloak image is built. ```dockerfile COPY keycloak-totp-api-1.0.0-all.jar /opt/keycloak/providers/ ``` -------------------------------- ### Deploy Keycloak Extension to Standalone Server (Bash) Source: https://context7.com/medihause/keycloak-totp-api/llms.txt Installs the Keycloak TOTP API extension JAR into a standalone Keycloak server's provider directory. It then triggers a Keycloak build to register the new extension. ```bash # Standalone installation cp keycloak-totp-api.jar ${KEYCLOAK_HOME}/providers/ ${KEYCLOAK_HOME}/bin/kc.sh build ``` -------------------------------- ### Build Keycloak Extension with Gradle Source: https://github.com/medihause/keycloak-totp-api/blob/main/README.md Builds the Keycloak TOTP API extension using Gradle. The `shadowJar` task is used to create an executable JAR file containing all necessary dependencies, which is then used for installation. ```bash ./gradlew shadowJar ``` -------------------------------- ### API: Generate TOTP Secret and QR Code Source: https://github.com/medihause/keycloak-totp-api/blob/main/README.md Generates a new TOTP secret and a base64-encoded QR code for a specified user. This endpoint is useful for initial TOTP setup for users. The response contains the `encodedSecret` and `qrCode`. ```json { "encodedSecret": "OFIWESBQGBLFG432HB5G6TTLIVIEGU2O", "qrCode": "iVBO...." } ``` -------------------------------- ### Get Access Token with Service Account (curl) Source: https://context7.com/medihause/keycloak-totp-api/llms.txt Demonstrates how to obtain an access token from Keycloak using the client credentials grant type with a service account. This is essential for authenticating API requests to manage TOTP settings. It requires the Keycloak realm URL, client ID, and client secret. ```curl curl -X POST "https://keycloak.example.com/realms/myrealm/protocol/openid-connect/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=client_credentials" \ -d "client_id=totp-service" \ -d "client_secret=your-client-secret-here" ``` -------------------------------- ### Build Keycloak Extension JAR with Gradle (Bash) Source: https://context7.com/medihause/keycloak-totp-api/llms.txt Clones the project repository and builds a fat JAR with Kotlin runtime dependencies using Gradle. The `shadowJar` task is configured to include necessary dependencies and name the output artifact. ```bash # Clone repository git clone https://github.com/medihause/keycloak-totp-api.git cd keycloak-totp-api # Build fat JAR with dependencies ./gradlew shadowJar # Output: build/libs/keycloak-totp-api.jar ``` -------------------------------- ### Gradle Build Configuration for Keycloak Extension (Kotlin) Source: https://context7.com/medihause/keycloak-totp-api/llms.txt Configures the Gradle build for the Keycloak TOTP API extension using Kotlin DSL. It specifies plugins, group, version, dependencies including Keycloak server and SPI modules, and customizes the `shadowJar` task to include the Kotlin stdlib. ```kotlin plugins { kotlin("jvm") version "2.0.0" id("com.gradleup.shadow") version "8.3.0" } group = "id.medihause" version = "1.0.1-kc26" dependencies { implementation("org.keycloak:keycloak-services:26.0.0") implementation("org.keycloak:keycloak-server-spi:26.0.0") implementation("org.keycloak:keycloak-server-spi-private:26.0.0") implementation("jakarta.ws.rs:jakarta.ws.rs-api:3.1.0") implementation("org.jetbrains.kotlin:kotlin-stdlib:2.0.0") implementation("com.fasterxml.jackson.core:jackson-databind:2.14.2") } tasks { val shadowJar by existing(ShadowJar::class) { dependencies { include(dependency("org.jetbrains.kotlin:kotlin-stdlib:2.0.0")) } archiveFileName.set("keycloak-totp-api.jar") } } ``` -------------------------------- ### Custom Keycloak Dockerfile with Extension Copy (Dockerfile) Source: https://context7.com/medihause/keycloak-totp-api/llms.txt A Dockerfile that builds a custom Keycloak image, copying the TOTP API extension JAR into the providers directory and running the build command. This ensures the extension is available upon container startup. ```dockerfile # Dockerfile for custom Keycloak image FROM quay.io/keycloak/keycloak:26.0.0 COPY keycloak-totp-api.jar /opt/keycloak/providers/ RUN /opt/keycloak/bin/kc.sh build ENTRYPOINT ["/opt/keycloak/bin/kc.sh"] ``` -------------------------------- ### Deploy Keycloak Extension via Docker Volume Mount (Bash) Source: https://context7.com/medihause/keycloak-totp-api/llms.txt Demonstrates deploying the Keycloak TOTP API extension to a Keycloak Docker container using a volume mount. This method is useful for persistent deployment and configuration of Keycloak in containerized environments. ```bash # Docker volume mount docker run -d \ -v /path/to/keycloak-totp-api.jar:/opt/keycloak/providers/keycloak-totp-api.jar \ -e KEYCLOAK_ADMIN=admin \ -e KEYCLOAK_ADMIN_PASSWORD=admin \ quay.io/keycloak/keycloak:26.0.0 start-dev ``` -------------------------------- ### Create Service Account Client and Role using Keycloak Admin CLI (Bash) Source: https://context7.com/medihause/keycloak-totp-api/llms.txt Configures a Keycloak client with service account enabled for API authentication, and assigns a 'manage-totp' role to it. This script uses the `kcadm.sh` utility to interact with the Keycloak Admin API. ```bash # Using Keycloak Admin CLI ${KEYCLOAK_HOME}/bin/kcadm.sh config credentials \ --server http://localhost:8080 \ --realm master \ --user admin # Create confidential client with service accounts enabled ${KEYCLOAK_HOME}/bin/kcadm.sh create clients \ -r myrealm \ -s clientId=totp-service \ -s enabled=true \ -s serviceAccountsEnabled=true \ -s standardFlowEnabled=false \ -s directAccessGrantsEnabled=false # Get client UUID CLIENT_UUID=$(${KEYCLOAK_HOME}/bin/kcadm.sh get clients \ -r myrealm \ -q clientId=totp-service \ --fields id \ --format csv \ --noquotes) # Get service account user ID SERVICE_USER=$(${KEYCLOAK_HOME}/bin/kcadm.sh get clients/${CLIENT_UUID}/service-account-user \ -r myrealm \ --fields id \ --format csv \ --noquotes) # Create manage-totp role ${KEYCLOAK_HOME}/bin/kcadm.sh create roles \ -r myrealm \ -s name=manage-totp # Assign role to service account ${KEYCLOAK_HOME}/bin/kcadm.sh add-roles \ -r myrealm \ --uid ${SERVICE_USER} \ --rolename manage-totp ``` -------------------------------- ### Register Keycloak Realm Resource Provider Factory (Kotlin) Source: https://context7.com/medihause/keycloak-totp-api/llms.txt Registers a custom RealmResourceProviderFactory for Keycloak extensions using the SPI pattern. This involves defining the factory class and specifying its ID, ensuring Keycloak can discover and instantiate the provider. ```kotlin // TOTPApiRealmResourceProviderFactory.kt class TOTPApiRealmResourceProviderFactory: RealmResourceProviderFactory { companion object { const val PROVIDER_ID = "totp-api" } override fun create(session: KeycloakSession?): RealmResourceProvider { return TOTPApiRealmResourceProvider(session!!) } override fun getId(): String = PROVIDER_ID } // META-INF/services/org.keycloak.services.resource.RealmResourceProviderFactory // File contents: id.medihause.keycloak.totp.api.TOTPApiRealmResourceProviderFactory ``` -------------------------------- ### Verify TOTP Code API Endpoint (Bash) Source: https://context7.com/medihause/keycloak-totp-api/llms.txt This bash command demonstrates how to verify a TOTP code for a user using the Keycloak TOTP API. It sends a POST request containing the device name and the TOTP code to be validated. A successful validation returns a 'TOTP code is valid' message, while an invalid code or a non-existent credential will result in an 'Unauthorized' error. ```bash curl -X POST "https://keycloak.example.com/realms/myrealm/totp-api/user-123-uuid/verify" \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5..." \ -H "Content-Type: application/json" \ -d '{ "deviceName": "iPhone Authenticator", "code": "866359" }' ``` -------------------------------- ### Generate TOTP Secret and QR Code (Kotlin) Source: https://context7.com/medihause/keycloak-totp-api/llms.txt Generates a new Base32-encoded TOTP secret and a QR code image for user enrollment. This function authenticates the session, checks for necessary roles, and then uses Keycloak's utilities to create the secret and QR code. It returns a response object containing both the encoded secret and the QR code data. ```kotlin package id.medihause.keycloak.totp.api.api import org.keycloak.models.KeycloakSession import org.keycloak.services.managers.AppAuthManager import org.keycloak.models.utils.Base32 import org.keycloak.models.utils.HmacOTP import org.keycloak.utils.TotpUtils class TOTPResourceApi(private val session: KeycloakSession) { private val totpSecretLength = 20 // Authentication and authorization check private fun authenticateSessionAndGetUser(userId: String): UserModel { val auth = AppAuthManager.BearerTokenAuthenticator(session).authenticate() if (auth == null) { throw NotAuthorizedException("Token not valid", {}) } else if (auth.user.serviceAccountClientLink == null) { throw NotAuthorizedException("User is not a service account", {}) } else if (auth.token.realmAccess == null || !auth.token.realmAccess.isUserInRole("manage-totp")) { throw NotAuthorizedException("User is not an admin", {}) } val user = session.users().getUserById(session.context.realm, userId) ?: throw NotFoundException("User not found") if (user.serviceAccountClientLink != null) { throw BadRequestException("Cannot manage service account") } return user } // Generate TOTP secret and QR code @GET @Path("/{userId}/generate") fun generateTOTP(@PathParam("userId") userId: String): Response { val user = authenticateSessionAndGetUser(userId) val realm = session.context.realm val secret = HmacOTP.generateSecret(totpSecretLength) val qrCode = TotpUtils.qrCode(secret, realm, user) val encodedSecret = Base32.encode(secret.toByteArray()) return Response.ok().entity( GenerateTOTPResponse(encodedSecret, qrCode) ).build() } } ``` -------------------------------- ### Verify TOTP Code Source: https://github.com/medihause/keycloak-totp-api/blob/main/README.md Verifies a provided TOTP code for a user. ```APIDOC ## POST /realms/{{REALM}}/totp-api/{{USER_ID}}/verify ### Description Verifies a TOTP code provided by the user. ### Method POST ### Endpoint `{{BASE_URL}}/realms/{{REALM}}/totp-api/{{USER_ID}}/verify` ### Parameters #### Path Parameters - **USER_ID** (string) - Required - The ID of the user whose TOTP code is being verified. #### Request Body - **deviceName** (string) - Required - The name of the device associated with the TOTP code. - **code** (string) - Required - The TOTP code to verify. ### Request Example ```json { "deviceName": "DeviceOne", "code": "866359" } ``` ### Response #### Success Response (200) - **message** (string) - Confirmation message indicating the TOTP code is valid. #### Response Example ```json { "message": "TOTP code is valid" } ``` ``` -------------------------------- ### Register TOTP Credential API Endpoint (Bash) Source: https://context7.com/medihause/keycloak-totp-api/llms.txt This bash command shows how to register a TOTP credential for a user via the Keycloak TOTP API. It sends a POST request with the user's device name, the encoded secret obtained from the generation endpoint, and an initial verification code. The `overwrite` flag can be set to true to replace an existing credential. The API returns a success message or an error if the credential already exists or the initial code is invalid. ```bash curl -X POST "https://keycloak.example.com/realms/myrealm/totp-api/user-123-uuid/register" \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5..." \ -H "Content-Type: application/json" \ -d '{ "deviceName": "iPhone Authenticator", "encodedSecret": "OFIWESBQGBLFG432HB5G6TTLIVIEGU2O", "initialCode": "128356", "overwrite": true }' ``` -------------------------------- ### Generate TOTP Secret API Endpoint (Bash) Source: https://context7.com/medihause/keycloak-totp-api/llms.txt This bash command demonstrates how to call the Keycloak TOTP API to generate a new TOTP secret and QR code for a specific user. It requires an Authorization header with a valid bearer token that has the 'manage-totp' realm role. The response includes the Base32 encoded secret and the QR code image data. ```bash curl -X GET "https://keycloak.example.com/realms/myrealm/totp-api/user-123-uuid/generate" \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5..." \ -H "Content-Type: application/json" ``` -------------------------------- ### Keycloak TOTP API Data Transfer Objects (Kotlin) Source: https://context7.com/medihause/keycloak-totp-api/llms.txt Defines data transfer objects for Keycloak TOTP API requests, including `RegisterTOTPCredentialRequest` and `VerifyTOTPRequest`. These DTOs use Jackson for JSON serialization and include companion object methods for request validation. ```kotlin // RegisterTOTPCredentialRequest.kt @JsonSerialize data class RegisterTOTPCredentialRequest( @JsonProperty("deviceName") val deviceName: String, @JsonProperty("encodedSecret") val encodedSecret: String, @JsonProperty("initialCode") val initialCode: String, @JsonProperty("overwrite") val overwrite: Boolean = false ) { companion object { fun validate(request: RegisterTOTPCredentialRequest): Boolean { return request.deviceName.isNotEmpty() && request.encodedSecret.isNotEmpty() && request.initialCode.isNotEmpty() } } } // VerifyTOTPRequest.kt @JsonSerialize data class VerifyTOTPRequest( @JsonProperty("deviceName") val deviceName: String, @JsonProperty("code") val code: String ) { companion object { fun validate(request: VerifyTOTPRequest): Boolean { return request.deviceName.isNotEmpty() && request.code.isNotEmpty() } } } ``` -------------------------------- ### Register TOTP Credential Source: https://context7.com/medihause/keycloak-totp-api/llms.txt Registers a TOTP credential for a user. This endpoint requires the device name, the encoded secret, and an initial verification code. ```APIDOC ## Register TOTP Credential ### Description Registers a TOTP credential for a user with device name, secret, and initial verification code. ### Method POST ### Endpoint `/realms/{realm}/totp-api/user-{userId}/register` ### Parameters #### Path Parameters - **realm** (string) - Required - The name of the realm. - **userId** (string) - Required - The UUID of the user. #### Request Body - **deviceName** (string) - Required - The name of the TOTP device (e.g., "iPhone Authenticator"). - **encodedSecret** (string) - Required - The Base32-encoded TOTP secret. - **initialCode** (string) - Required - The initial TOTP code for verification. - **overwrite** (boolean) - Optional - If true, overwrites an existing credential. Defaults to false. ### Request Example ```bash curl -X POST "https://keycloak.example.com/realms/myrealm/totp-api/user-123-uuid/register" \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5..." \ -H "Content-Type: application/json" \ -d '{ "deviceName": "iPhone Authenticator", "encodedSecret": "OFIWESBQGBLFG432HB5G6TTLIVIEGU2O", "initialCode": "128356", "overwrite": true }' ``` ### Response #### Success Response (201 Created) - **message** (string) - Indicates successful registration. #### Response Example ```json { "message": "TOTP credential registered" } ``` #### Error Response (409 Conflict) - **message** (string) - Indicates that the TOTP credential already exists and overwrite was false. #### Error Response (500 Internal Server Error) - **message** (string) - Indicates a failure to create the TOTP credential, possibly due to an invalid initial code. #### Error Response Example (409 Conflict) ```json { "message": "TOTP credential already exists" } ``` #### Error Response Example (500 Internal Server Error) ```json { "message": "Failed to create TOTP credential" } ``` ``` -------------------------------- ### Generate TOTP Secret Source: https://context7.com/medihause/keycloak-totp-api/llms.txt Generates a new TOTP secret for a user. The response includes the Base32-encoded secret and a QR code image for enrollment. ```APIDOC ## Generate TOTP Secret ### Description Generates a new TOTP secret with Base32-encoded string and QR code image for user enrollment. ### Method GET ### Endpoint `/realms/{realm}/totp-api/user-{userId}/generate` ### Parameters #### Path Parameters - **realm** (string) - Required - The name of the realm. - **userId** (string) - Required - The UUID of the user. ### Request Example ```bash curl -X GET "https://keycloak.example.com/realms/myrealm/totp-api/user-123-uuid/generate" \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5..." ``` ### Response #### Success Response (200 OK) - **encodedSecret** (string) - The Base32-encoded TOTP secret. - **qrCode** (string) - A Base64 encoded string representing the QR code image. #### Response Example ```json { "encodedSecret": "OFIWESBQGBLFG432HB5G6TTLIVIEGU2O", "qrCode": "iVBORw0KGgoAAAANSUhEUgAAASwAAAEsAQAAAABRBrPYAAABxElEQVR4Xu2YS46EMAxE..." } ``` ``` -------------------------------- ### Verify TOTP Code Source: https://context7.com/medihause/keycloak-totp-api/llms.txt Validates a provided TOTP code against a user's registered TOTP credential. ```APIDOC ## Verify TOTP Code ### Description Validates a TOTP code against a registered device credential. ### Method POST ### Endpoint `/realms/{realm}/totp-api/user-{userId}/verify` ### Parameters #### Path Parameters - **realm** (string) - Required - The name of the realm. - **userId** (string) - Required - The UUID of the user. #### Request Body - **deviceName** (string) - Required - The name of the TOTP device to verify. - **code** (string) - Required - The TOTP code to validate. ### Request Example ```bash curl -X POST "https://keycloak.example.com/realms/myrealm/totp-api/user-123-uuid/verify" \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5..." \ -H "Content-Type: application/json" \ -d '{ "deviceName": "iPhone Authenticator", "code": "866359" }' ``` ### Response #### Success Response (200 OK) - **message** (string) - Indicates that the TOTP code is valid. #### Response Example ```json { "message": "TOTP code is valid" } ``` #### Error Response (401 Unauthorized) - **message** (string) - Indicates an invalid TOTP code or that the TOTP credential was not found for the specified device. #### Error Response Example (Invalid Code) ```json { "message": "Invalid TOTP code" } ``` #### Error Response Example (Device Not Found) ```json { "message": "TOTP credential not found" } ``` ``` -------------------------------- ### Register TOTP Credential Source: https://github.com/medihause/keycloak-totp-api/blob/main/README.md Registers a TOTP credential for a user, optionally overwriting an existing one. ```APIDOC ## POST /realms/{{REALM}}/totp-api/{{USER_ID}}/register ### Description Registers a TOTP credential for a user. Can overwrite an existing credential if `overwrite` is set to true. ### Method POST ### Endpoint `{{BASE_URL}}/realms/{{REALM}}/totp-api/{{USER_ID}}/register` ### Parameters #### Path Parameters - **USER_ID** (string) - Required - The ID of the user to register the TOTP credential for. #### Request Body - **deviceName** (string) - Required - The name of the device for which the TOTP is registered. - **encodedSecret** (string) - Required - The base32 encoded TOTP secret. - **initialCode** (string) - Required - The initial TOTP code from the user's authenticator app. - **overwrite** (boolean) - Optional - If true, overwrites any existing TOTP credential for the user. ### Request Example ```json { "deviceName": "DeviceOne", "encodedSecret": "OFIWESBQGBLFG432HB5G6TTLIVIEGU2O", "initialCode": "128356", "overwrite": true } ``` ### Response #### Success Response (200) - **message** (string) - Confirmation message indicating successful registration. #### Response Example ```json { "message": "TOTP credential registered" } ``` ``` -------------------------------- ### Generate TOTP Secret Source: https://github.com/medihause/keycloak-totp-api/blob/main/README.md Generates a new TOTP secret and a QR code for a specified user. ```APIDOC ## GET /realms/{{REALM}}/totp-api/{{USER_ID}}/generate ### Description Generates a new TOTP secret and QR code for a user. ### Method GET ### Endpoint `{{BASE_URL}}/realms/{{REALM}}/totp-api/{{USER_ID}}/generate` ### Parameters #### Path Parameters - **USER_ID** (string) - Required - The ID of the user for whom to generate the TOTP secret. ### Request Example (No request body for GET) ### Response #### Success Response (200) - **encodedSecret** (string) - The base32 encoded TOTP secret. - **qrCode** (string) - A base64-encoded string representing the QR code image. #### Response Example ```json { "encodedSecret": "OFIWESBQGBLFG432HB5G6TTLIVIEGU2O", "qrCode": "iVBO...." } ``` ``` -------------------------------- ### POST /realms/{realm}/protocol/openid-connect/token Source: https://context7.com/medihause/keycloak-totp-api/llms.txt Obtain an access token for the 'totp-service' client using the client credentials grant type. This token is required to authenticate subsequent requests to the TOTP API endpoints. ```APIDOC ## POST /realms/{realm}/protocol/openid-connect/token ### Description Requests an access token using the client credentials grant type. This is the initial step for authenticating with the TOTP API. ### Method POST ### Endpoint `https://keycloak.example.com/realms/myrealm/protocol/openid-connect/token` ### Parameters #### Request Body - **grant_type** (string) - Required - Must be `client_credentials`. - **client_id** (string) - Required - The client ID for the TOTP service, typically `totp-service`. - **client_secret** (string) - Required - The client secret associated with the `totp-service` client. ### Request Example ```json { "grant_type": "client_credentials", "client_id": "totp-service", "client_secret": "your-client-secret-here" } ``` ### Response #### Success Response (200) - **access_token** (string) - The obtained Bearer token. - **expires_in** (integer) - The lifetime of the token in seconds. - **token_type** (string) - The type of the token, usually `Bearer`. - **scope** (string) - The scopes granted to the token. #### Response Example ```json { "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI...", "expires_in": 300, "token_type": "Bearer", "scope": "email profile" } ``` ``` -------------------------------- ### API: Verify TOTP Code Source: https://github.com/medihause/keycloak-totp-api/blob/main/README.md Verifies a provided TOTP code for a user's registered device. This endpoint is used to confirm the validity of a time-based one-time password during authentication flows. The response indicates whether the code is valid. ```json { "deviceName": "DeviceOne", "code": "866359" } ``` -------------------------------- ### API: Register TOTP Credential Source: https://github.com/medihause/keycloak-totp-api/blob/main/README.md Registers a TOTP credential for a user with a given device name, encoded secret, and initial code. An optional `overwrite` flag can be set to `true` to replace an existing TOTP credential for the user. The response confirms successful registration. ```json { "deviceName": "DeviceOne", "encodedSecret": "OFIWESBQGBLFG432HB5G6TTLIVIEGU2O", "initialCode": "128356", "overwrite": true } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.