├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── LICENSE ├── README.md ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── mozen │ │ └── springbootkeycloakadminapi │ │ ├── Application.java │ │ ├── ApplicationConfiguration.java │ │ └── initializer │ │ ├── KeycloakInitializer.java │ │ ├── KeycloakInitializerConfigurationProperties.java │ │ ├── KeycloakInitializerController.java │ │ └── KeycloakUser.java └── resources │ ├── application.yml │ └── initializer │ ├── init-keycloak-users.json │ └── init-keycloak.json └── test └── java └── com └── example └── springbootkeycloakadminapi └── ApplicationTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mozenn/spring-boot-keycloak-admin-api/56a800d4ec6dde5e4c9a85a17679010291d05320/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.5/apache-maven-3.8.5-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Gauthier Cassany 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Companion repository for the blog post : "Set up Keycloak in Spring Boot using the Keycloak Admin API" 2 | 3 | Checkout the blog post for more details : https://gauthier-cassany.com/posts/spring-boot-keycloak-admin-api 4 | -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # https://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /usr/local/etc/mavenrc ] ; then 40 | . /usr/local/etc/mavenrc 41 | fi 42 | 43 | if [ -f /etc/mavenrc ] ; then 44 | . /etc/mavenrc 45 | fi 46 | 47 | if [ -f "$HOME/.mavenrc" ] ; then 48 | . "$HOME/.mavenrc" 49 | fi 50 | 51 | fi 52 | 53 | # OS specific support. $var _must_ be set to either true or false. 54 | cygwin=false; 55 | darwin=false; 56 | mingw=false 57 | case "`uname`" in 58 | CYGWIN*) cygwin=true ;; 59 | MINGW*) mingw=true;; 60 | Darwin*) darwin=true 61 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 62 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 63 | if [ -z "$JAVA_HOME" ]; then 64 | if [ -x "/usr/libexec/java_home" ]; then 65 | export JAVA_HOME="`/usr/libexec/java_home`" 66 | else 67 | export JAVA_HOME="/Library/Java/Home" 68 | fi 69 | fi 70 | ;; 71 | esac 72 | 73 | if [ -z "$JAVA_HOME" ] ; then 74 | if [ -r /etc/gentoo-release ] ; then 75 | JAVA_HOME=`java-config --jre-home` 76 | fi 77 | fi 78 | 79 | if [ -z "$M2_HOME" ] ; then 80 | ## resolve links - $0 may be a link to maven's home 81 | PRG="$0" 82 | 83 | # need this for relative symlinks 84 | while [ -h "$PRG" ] ; do 85 | ls=`ls -ld "$PRG"` 86 | link=`expr "$ls" : '.*-> \(.*\)$'` 87 | if expr "$link" : '/.*' > /dev/null; then 88 | PRG="$link" 89 | else 90 | PRG="`dirname "$PRG"`/$link" 91 | fi 92 | done 93 | 94 | saveddir=`pwd` 95 | 96 | M2_HOME=`dirname "$PRG"`/.. 97 | 98 | # make it fully qualified 99 | M2_HOME=`cd "$M2_HOME" && pwd` 100 | 101 | cd "$saveddir" 102 | # echo Using m2 at $M2_HOME 103 | fi 104 | 105 | # For Cygwin, ensure paths are in UNIX format before anything is touched 106 | if $cygwin ; then 107 | [ -n "$M2_HOME" ] && 108 | M2_HOME=`cygpath --unix "$M2_HOME"` 109 | [ -n "$JAVA_HOME" ] && 110 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 111 | [ -n "$CLASSPATH" ] && 112 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 113 | fi 114 | 115 | # For Mingw, ensure paths are in UNIX format before anything is touched 116 | if $mingw ; then 117 | [ -n "$M2_HOME" ] && 118 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 119 | [ -n "$JAVA_HOME" ] && 120 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 121 | fi 122 | 123 | if [ -z "$JAVA_HOME" ]; then 124 | javaExecutable="`which javac`" 125 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 126 | # readlink(1) is not available as standard on Solaris 10. 127 | readLink=`which readlink` 128 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 129 | if $darwin ; then 130 | javaHome="`dirname \"$javaExecutable\"`" 131 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 132 | else 133 | javaExecutable="`readlink -f \"$javaExecutable\"`" 134 | fi 135 | javaHome="`dirname \"$javaExecutable\"`" 136 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 137 | JAVA_HOME="$javaHome" 138 | export JAVA_HOME 139 | fi 140 | fi 141 | fi 142 | 143 | if [ -z "$JAVACMD" ] ; then 144 | if [ -n "$JAVA_HOME" ] ; then 145 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 146 | # IBM's JDK on AIX uses strange locations for the executables 147 | JAVACMD="$JAVA_HOME/jre/sh/java" 148 | else 149 | JAVACMD="$JAVA_HOME/bin/java" 150 | fi 151 | else 152 | JAVACMD="`\\unset -f command; \\command -v java`" 153 | fi 154 | fi 155 | 156 | if [ ! -x "$JAVACMD" ] ; then 157 | echo "Error: JAVA_HOME is not defined correctly." >&2 158 | echo " We cannot execute $JAVACMD" >&2 159 | exit 1 160 | fi 161 | 162 | if [ -z "$JAVA_HOME" ] ; then 163 | echo "Warning: JAVA_HOME environment variable is not set." 164 | fi 165 | 166 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 167 | 168 | # traverses directory structure from process work directory to filesystem root 169 | # first directory with .mvn subdirectory is considered project base directory 170 | find_maven_basedir() { 171 | 172 | if [ -z "$1" ] 173 | then 174 | echo "Path not specified to find_maven_basedir" 175 | return 1 176 | fi 177 | 178 | basedir="$1" 179 | wdir="$1" 180 | while [ "$wdir" != '/' ] ; do 181 | if [ -d "$wdir"/.mvn ] ; then 182 | basedir=$wdir 183 | break 184 | fi 185 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 186 | if [ -d "${wdir}" ]; then 187 | wdir=`cd "$wdir/.."; pwd` 188 | fi 189 | # end of workaround 190 | done 191 | echo "${basedir}" 192 | } 193 | 194 | # concatenates all lines of a file 195 | concat_lines() { 196 | if [ -f "$1" ]; then 197 | echo "$(tr -s '\n' ' ' < "$1")" 198 | fi 199 | } 200 | 201 | BASE_DIR=`find_maven_basedir "$(pwd)"` 202 | if [ -z "$BASE_DIR" ]; then 203 | exit 1; 204 | fi 205 | 206 | ########################################################################################## 207 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 208 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 209 | ########################################################################################## 210 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 211 | if [ "$MVNW_VERBOSE" = true ]; then 212 | echo "Found .mvn/wrapper/maven-wrapper.jar" 213 | fi 214 | else 215 | if [ "$MVNW_VERBOSE" = true ]; then 216 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 217 | fi 218 | if [ -n "$MVNW_REPOURL" ]; then 219 | jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 220 | else 221 | jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 222 | fi 223 | while IFS="=" read key value; do 224 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 225 | esac 226 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 227 | if [ "$MVNW_VERBOSE" = true ]; then 228 | echo "Downloading from: $jarUrl" 229 | fi 230 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 231 | if $cygwin; then 232 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` 233 | fi 234 | 235 | if command -v wget > /dev/null; then 236 | if [ "$MVNW_VERBOSE" = true ]; then 237 | echo "Found wget ... using wget" 238 | fi 239 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 240 | wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 241 | else 242 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 243 | fi 244 | elif command -v curl > /dev/null; then 245 | if [ "$MVNW_VERBOSE" = true ]; then 246 | echo "Found curl ... using curl" 247 | fi 248 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 249 | curl -o "$wrapperJarPath" "$jarUrl" -f 250 | else 251 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f 252 | fi 253 | 254 | else 255 | if [ "$MVNW_VERBOSE" = true ]; then 256 | echo "Falling back to using Java to download" 257 | fi 258 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 259 | # For Cygwin, switch paths to Windows format before running javac 260 | if $cygwin; then 261 | javaClass=`cygpath --path --windows "$javaClass"` 262 | fi 263 | if [ -e "$javaClass" ]; then 264 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 265 | if [ "$MVNW_VERBOSE" = true ]; then 266 | echo " - Compiling MavenWrapperDownloader.java ..." 267 | fi 268 | # Compiling the Java class 269 | ("$JAVA_HOME/bin/javac" "$javaClass") 270 | fi 271 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 272 | # Running the downloader 273 | if [ "$MVNW_VERBOSE" = true ]; then 274 | echo " - Running MavenWrapperDownloader.java ..." 275 | fi 276 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 277 | fi 278 | fi 279 | fi 280 | fi 281 | ########################################################################################## 282 | # End of extension 283 | ########################################################################################## 284 | 285 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 286 | if [ "$MVNW_VERBOSE" = true ]; then 287 | echo $MAVEN_PROJECTBASEDIR 288 | fi 289 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 290 | 291 | # For Cygwin, switch paths to Windows format before running java 292 | if $cygwin; then 293 | [ -n "$M2_HOME" ] && 294 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 295 | [ -n "$JAVA_HOME" ] && 296 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 297 | [ -n "$CLASSPATH" ] && 298 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 299 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 300 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 301 | fi 302 | 303 | # Provide a "standardized" way to retrieve the CLI args that will 304 | # work with both Windows and non-Windows executions. 305 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 306 | export MAVEN_CMD_LINE_ARGS 307 | 308 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 309 | 310 | exec "$JAVACMD" \ 311 | $MAVEN_OPTS \ 312 | $MAVEN_DEBUG_OPTS \ 313 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 314 | "-Dmaven.home=${M2_HOME}" \ 315 | "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 316 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 317 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* 50 | if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 124 | 125 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% ^ 162 | %JVM_CONFIG_MAVEN_PROPS% ^ 163 | %MAVEN_OPTS% ^ 164 | %MAVEN_DEBUG_OPTS% ^ 165 | -classpath %WRAPPER_JAR% ^ 166 | "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ 167 | %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 168 | if ERRORLEVEL 1 goto error 169 | goto end 170 | 171 | :error 172 | set ERROR_CODE=1 173 | 174 | :end 175 | @endlocal & set ERROR_CODE=%ERROR_CODE% 176 | 177 | if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost 178 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 179 | if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" 180 | if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" 181 | :skipRcPost 182 | 183 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 184 | if "%MAVEN_BATCH_PAUSE%"=="on" pause 185 | 186 | if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% 187 | 188 | cmd /C exit /B %ERROR_CODE% 189 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.7.1 9 | 10 | 11 | com.mozen 12 | spring-boot-keycloak-admin-api 13 | 1.0.0-SNAPSHOT 14 | demo 15 | Demo project for Spring Boot 16 | 17 | 17 18 | 18.0.2 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-web 24 | 25 | 26 | 27 | org.projectlombok 28 | lombok 29 | true 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-test 34 | test 35 | 36 | 37 | 38 | org.keycloak 39 | keycloak-admin-client 40 | 18.0.2 41 | 42 | 43 | 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-maven-plugin 49 | 50 | 51 | 52 | org.projectlombok 53 | lombok 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /src/main/java/com/mozen/springbootkeycloakadminapi/Application.java: -------------------------------------------------------------------------------- 1 | package com.mozen.springbootkeycloakadminapi; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; 6 | import org.springframework.boot.context.properties.ConfigurationPropertiesScan; 7 | 8 | @ConfigurationPropertiesScan("com.mozen.springbootkeycloakadminapi") 9 | @SpringBootApplication(exclude={DataSourceAutoConfiguration.class}) 10 | public class Application { 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(Application.class, args); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/mozen/springbootkeycloakadminapi/ApplicationConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.mozen.springbootkeycloakadminapi; 2 | 3 | import com.mozen.springbootkeycloakadminapi.initializer.KeycloakInitializerConfigurationProperties; 4 | import org.keycloak.OAuth2Constants; 5 | import org.keycloak.admin.client.Keycloak; 6 | import org.keycloak.admin.client.KeycloakBuilder; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | 11 | @Configuration 12 | public class ApplicationConfiguration { 13 | 14 | @Autowired 15 | KeycloakInitializerConfigurationProperties keycloakInitializerConfigurationProperties; 16 | 17 | @Bean 18 | protected Keycloak keycloak() { 19 | return KeycloakBuilder.builder() 20 | .grantType(OAuth2Constants.PASSWORD) 21 | .realm(keycloakInitializerConfigurationProperties.getMasterRealm()) 22 | .clientId(keycloakInitializerConfigurationProperties.getClientId()) 23 | .username(keycloakInitializerConfigurationProperties.getUsername()) 24 | .password(keycloakInitializerConfigurationProperties.getPassword()) 25 | .serverUrl(keycloakInitializerConfigurationProperties.getUrl()) 26 | .build(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/mozen/springbootkeycloakadminapi/initializer/KeycloakInitializer.java: -------------------------------------------------------------------------------- 1 | package com.mozen.springbootkeycloakadminapi.initializer; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.keycloak.admin.client.Keycloak; 6 | import org.keycloak.admin.client.resource.UserResource; 7 | import org.keycloak.representations.idm.CredentialRepresentation; 8 | import org.keycloak.representations.idm.RealmRepresentation; 9 | import org.keycloak.representations.idm.RoleRepresentation; 10 | import org.keycloak.representations.idm.UserRepresentation; 11 | import org.springframework.beans.factory.InitializingBean; 12 | import org.springframework.core.io.ClassPathResource; 13 | import org.springframework.core.io.Resource; 14 | import org.springframework.stereotype.Service; 15 | 16 | import javax.ws.rs.NotFoundException; 17 | import java.io.IOException; 18 | import java.util.ArrayList; 19 | import java.util.Arrays; 20 | import java.util.List; 21 | 22 | @Slf4j 23 | @Service 24 | public class KeycloakInitializer implements InitializingBean { 25 | 26 | private final Keycloak keycloak; 27 | 28 | private final KeycloakInitializerConfigurationProperties keycloakInitializerConfigurationProperties; 29 | 30 | private final ObjectMapper mapper; 31 | 32 | private static String REALM_ID; 33 | 34 | private static final String INIT_KEYCLOAK_PATH = "initializer/init-keycloak.json"; 35 | private static final String INIT_KEYCLOAK_USERS_PATH = 36 | "initializer/init-keycloak-users.json"; 37 | 38 | public KeycloakInitializer(Keycloak keycloak, 39 | KeycloakInitializerConfigurationProperties keycloakInitializerConfigurationProperties, 40 | ObjectMapper mapper) { 41 | this.keycloak = keycloak; 42 | this.keycloakInitializerConfigurationProperties = keycloakInitializerConfigurationProperties; 43 | this.mapper = mapper; 44 | } 45 | 46 | @Override 47 | public void afterPropertiesSet() throws Exception { 48 | REALM_ID = keycloakInitializerConfigurationProperties.getApplicationRealm(); 49 | 50 | if (keycloakInitializerConfigurationProperties.initializeOnStartup()) { 51 | init(false); 52 | } 53 | } 54 | 55 | public void init(boolean overwrite) { 56 | 57 | log.info("Initializer start"); 58 | 59 | List realms = keycloak.realms().findAll(); 60 | boolean isAlreadyInitialized = 61 | realms.stream().anyMatch(realm -> realm.getId().equals(REALM_ID)); 62 | 63 | if (isAlreadyInitialized && overwrite) { 64 | reset(); 65 | } 66 | 67 | if (!isAlreadyInitialized || overwrite) { 68 | 69 | initKeycloak(); 70 | 71 | log.info("Keycloak initialized successfully"); 72 | } else { 73 | log.warn("Keycloak initialization cancelled: realm already exist"); 74 | } 75 | } 76 | 77 | private void initKeycloak() { 78 | 79 | initKeycloakRealm(); 80 | initKeycloakUsers(); 81 | } 82 | 83 | private void initKeycloakRealm() { 84 | RealmRepresentation realmRepresentation = new RealmRepresentation(); 85 | realmRepresentation.setRealm(REALM_ID); 86 | realmRepresentation.setId(REALM_ID); 87 | 88 | Resource resource = new ClassPathResource(INIT_KEYCLOAK_PATH); 89 | try { 90 | RealmRepresentation realmRepresentationToImport = 91 | mapper.readValue(resource.getFile(), RealmRepresentation.class); 92 | keycloak.realms().create(realmRepresentationToImport); 93 | } catch (IOException e) { 94 | String errorMessage = 95 | String.format("Failed to import keycloak realm representation : %s", e.getMessage()); 96 | log.error(errorMessage); 97 | throw new RuntimeException(errorMessage, e); 98 | } 99 | } 100 | 101 | private void initKeycloakUsers() { 102 | 103 | List users = null; 104 | try { 105 | Resource resource = new ClassPathResource(INIT_KEYCLOAK_USERS_PATH); 106 | users = 107 | mapper.readValue( 108 | resource.getFile(), 109 | mapper.getTypeFactory().constructCollectionType(ArrayList.class, KeycloakUser.class)); 110 | } catch (IOException e) { 111 | String errorMessage = String.format("Failed to read keycloak users : %s", e.getMessage()); 112 | log.error(errorMessage); 113 | throw new RuntimeException(errorMessage, e); 114 | } 115 | 116 | users.stream().forEach(u -> initKeycloakUser(u)); 117 | } 118 | 119 | private void initKeycloakUser(KeycloakUser user) { 120 | 121 | UserRepresentation userRepresentation = new UserRepresentation(); 122 | userRepresentation.setEmail(user.getEmail()); 123 | userRepresentation.setUsername(user.getUsername()); 124 | userRepresentation.setEnabled(true); 125 | userRepresentation.setEmailVerified(true); 126 | CredentialRepresentation userCredentialRepresentation = new CredentialRepresentation(); 127 | userCredentialRepresentation.setType(CredentialRepresentation.PASSWORD); 128 | userCredentialRepresentation.setTemporary(false); 129 | userCredentialRepresentation.setValue(user.getPassword()); 130 | userRepresentation.setCredentials(Arrays.asList(userCredentialRepresentation)); 131 | keycloak.realm(REALM_ID).users().create(userRepresentation); 132 | 133 | if (user.isAdmin()) { 134 | userRepresentation = 135 | keycloak.realm(REALM_ID).users().search(user.getUsername()).get(0); 136 | UserResource userResource = 137 | keycloak.realm(REALM_ID).users().get(userRepresentation.getId()); 138 | List rolesToAdd = 139 | Arrays.asList(keycloak.realm(REALM_ID).roles().get("admin").toRepresentation()); 140 | userResource.roles().realmLevel().add(rolesToAdd); 141 | } 142 | } 143 | 144 | public void reset() { 145 | try { 146 | keycloak.realm(REALM_ID).remove(); 147 | } catch (NotFoundException e) { 148 | log.error("Failed to reset Keycloak", e); 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/main/java/com/mozen/springbootkeycloakadminapi/initializer/KeycloakInitializerConfigurationProperties.java: -------------------------------------------------------------------------------- 1 | package com.mozen.springbootkeycloakadminapi.initializer; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.Data; 5 | import lombok.Getter; 6 | import org.springframework.boot.context.properties.ConfigurationProperties; 7 | 8 | @Data 9 | @ConfigurationProperties(prefix = "keycloak-initializer") 10 | public class KeycloakInitializerConfigurationProperties { 11 | 12 | @Getter(AccessLevel.NONE) 13 | private boolean initializeOnStartup; 14 | 15 | public boolean initializeOnStartup() { 16 | return initializeOnStartup; 17 | } 18 | 19 | private String masterRealm; 20 | 21 | private String applicationRealm; 22 | 23 | private String clientId; 24 | 25 | private String username; 26 | 27 | private String password; 28 | 29 | private String url; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/mozen/springbootkeycloakadminapi/initializer/KeycloakInitializerController.java: -------------------------------------------------------------------------------- 1 | package com.mozen.springbootkeycloakadminapi.initializer; 2 | 3 | import org.springframework.web.bind.annotation.*; 4 | 5 | @RestController 6 | @RequestMapping("/keycloak") 7 | public class KeycloakInitializerController { 8 | 9 | private KeycloakInitializer keycloakInitializer; 10 | 11 | public KeycloakInitializerController(KeycloakInitializer keycloakInitializer) { 12 | this.keycloakInitializer = keycloakInitializer; 13 | } 14 | 15 | @PostMapping("/init") 16 | public void init(@RequestParam boolean overwrite) { 17 | keycloakInitializer.init(overwrite); 18 | } 19 | 20 | @DeleteMapping("/reset") 21 | public void reset() { 22 | keycloakInitializer.reset(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/mozen/springbootkeycloakadminapi/initializer/KeycloakUser.java: -------------------------------------------------------------------------------- 1 | package com.mozen.springbootkeycloakadminapi.initializer; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | 6 | @Data 7 | @AllArgsConstructor 8 | public class KeycloakUser { 9 | 10 | private String username; 11 | 12 | private String password; 13 | 14 | private String email; 15 | 16 | private boolean isAdmin; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9000 3 | 4 | keycloak-initializer: 5 | initializeOnStartup: true 6 | masterRealm: master 7 | applicationRealm: SpringBootKeycloakAdminAPI 8 | client-id: admin-cli 9 | username: admin 10 | password: password 11 | url: http://${KEYCLOAK_HOST:localhost}:${KEYCLOAK_PORT:8180}/auth/ -------------------------------------------------------------------------------- /src/main/resources/initializer/init-keycloak-users.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "username": "admin", 4 | "password": "admin", 5 | "email": "admin@gmail.com", 6 | "isAdmin": true 7 | }, 8 | { 9 | "username": "user", 10 | "password": "password", 11 | "email": "user@gmail.com", 12 | "isAdmin": false 13 | } 14 | ] -------------------------------------------------------------------------------- /src/main/resources/initializer/init-keycloak.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "SpringBootKeycloakAdminAPI", 3 | "realm": "SpringBootKeycloakAdminAPI", 4 | "notBefore": 0, 5 | "defaultSignatureAlgorithm": "RS256", 6 | "revokeRefreshToken": false, 7 | "refreshTokenMaxReuse": 0, 8 | "accessTokenLifespan": 300, 9 | "accessTokenLifespanForImplicitFlow": 900, 10 | "ssoSessionIdleTimeout": 1800, 11 | "ssoSessionMaxLifespan": 36000, 12 | "ssoSessionIdleTimeoutRememberMe": 0, 13 | "ssoSessionMaxLifespanRememberMe": 0, 14 | "offlineSessionIdleTimeout": 2592000, 15 | "offlineSessionMaxLifespanEnabled": false, 16 | "offlineSessionMaxLifespan": 5184000, 17 | "clientSessionIdleTimeout": 0, 18 | "clientSessionMaxLifespan": 0, 19 | "clientOfflineSessionIdleTimeout": 0, 20 | "clientOfflineSessionMaxLifespan": 0, 21 | "accessCodeLifespan": 60, 22 | "accessCodeLifespanUserAction": 300, 23 | "accessCodeLifespanLogin": 1800, 24 | "actionTokenGeneratedByAdminLifespan": 43200, 25 | "actionTokenGeneratedByUserLifespan": 300, 26 | "oauth2DeviceCodeLifespan": 600, 27 | "oauth2DevicePollingInterval": 5, 28 | "enabled": true, 29 | "sslRequired": "external", 30 | "registrationAllowed": false, 31 | "registrationEmailAsUsername": false, 32 | "rememberMe": false, 33 | "verifyEmail": false, 34 | "loginWithEmailAllowed": true, 35 | "duplicateEmailsAllowed": false, 36 | "resetPasswordAllowed": false, 37 | "editUsernameAllowed": false, 38 | "bruteForceProtected": false, 39 | "permanentLockout": false, 40 | "maxFailureWaitSeconds": 900, 41 | "minimumQuickLoginWaitSeconds": 60, 42 | "waitIncrementSeconds": 60, 43 | "quickLoginCheckMilliSeconds": 1000, 44 | "maxDeltaTimeSeconds": 43200, 45 | "failureFactor": 30, 46 | "roles": { 47 | "realm": [ 48 | { 49 | "id": "09e83b6c-874a-46e1-a5f1-404b758c9358", 50 | "name": "default-roles-springbootkeycloakadminapi", 51 | "description": "${role_default-roles}", 52 | "composite": true, 53 | "composites": { 54 | "realm": [ 55 | "offline_access", 56 | "uma_authorization" 57 | ], 58 | "client": { 59 | "account": [ 60 | "manage-account", 61 | "view-profile" 62 | ] 63 | } 64 | }, 65 | "clientRole": false, 66 | "containerId": "SpringBootKeycloakAdminAPI", 67 | "attributes": {} 68 | }, 69 | { 70 | "id": "4767a116-81c2-4f9e-b914-4089010143a9", 71 | "name": "offline_access", 72 | "description": "${role_offline-access}", 73 | "composite": false, 74 | "clientRole": false, 75 | "containerId": "SpringBootKeycloakAdminAPI", 76 | "attributes": {} 77 | }, 78 | { 79 | "id": "950d97be-0734-4a34-89d0-c882d23bf8ba", 80 | "name": "admin", 81 | "composite": false, 82 | "clientRole": false, 83 | "containerId": "SpringBootKeycloakAdminAPI", 84 | "attributes": {} 85 | }, 86 | { 87 | "id": "9799ba20-c39a-477c-a2c2-ec66b2ee3c93", 88 | "name": "uma_authorization", 89 | "description": "${role_uma_authorization}", 90 | "composite": false, 91 | "clientRole": false, 92 | "containerId": "SpringBootKeycloakAdminAPI", 93 | "attributes": {} 94 | } 95 | ], 96 | "client": { 97 | "realm-management": [ 98 | { 99 | "id": "15abfe47-1bd9-41bd-9b6e-b4e396f2f243", 100 | "name": "create-client", 101 | "description": "${role_create-client}", 102 | "composite": false, 103 | "clientRole": true, 104 | "containerId": "1b024c36-0193-4c5b-8030-b9536db34fdf", 105 | "attributes": {} 106 | }, 107 | { 108 | "id": "4e339f03-50a6-409d-8ba7-beff1aed87a9", 109 | "name": "manage-events", 110 | "description": "${role_manage-events}", 111 | "composite": false, 112 | "clientRole": true, 113 | "containerId": "1b024c36-0193-4c5b-8030-b9536db34fdf", 114 | "attributes": {} 115 | }, 116 | { 117 | "id": "0517284c-ce04-4230-b758-167182838c7d", 118 | "name": "query-clients", 119 | "description": "${role_query-clients}", 120 | "composite": false, 121 | "clientRole": true, 122 | "containerId": "1b024c36-0193-4c5b-8030-b9536db34fdf", 123 | "attributes": {} 124 | }, 125 | { 126 | "id": "1affe43a-418f-4a42-93bf-609e213ee63a", 127 | "name": "query-users", 128 | "description": "${role_query-users}", 129 | "composite": false, 130 | "clientRole": true, 131 | "containerId": "1b024c36-0193-4c5b-8030-b9536db34fdf", 132 | "attributes": {} 133 | }, 134 | { 135 | "id": "7d5594f4-864a-456e-8c11-b3a8b669aac3", 136 | "name": "query-realms", 137 | "description": "${role_query-realms}", 138 | "composite": false, 139 | "clientRole": true, 140 | "containerId": "1b024c36-0193-4c5b-8030-b9536db34fdf", 141 | "attributes": {} 142 | }, 143 | { 144 | "id": "7b4c767a-4fa4-4c81-a7f0-53487e071560", 145 | "name": "view-users", 146 | "description": "${role_view-users}", 147 | "composite": true, 148 | "composites": { 149 | "client": { 150 | "realm-management": [ 151 | "query-groups", 152 | "query-users" 153 | ] 154 | } 155 | }, 156 | "clientRole": true, 157 | "containerId": "1b024c36-0193-4c5b-8030-b9536db34fdf", 158 | "attributes": {} 159 | }, 160 | { 161 | "id": "98fda5d6-2003-4ffa-a066-bba292f07730", 162 | "name": "manage-identity-providers", 163 | "description": "${role_manage-identity-providers}", 164 | "composite": false, 165 | "clientRole": true, 166 | "containerId": "1b024c36-0193-4c5b-8030-b9536db34fdf", 167 | "attributes": {} 168 | }, 169 | { 170 | "id": "a02a81a8-6639-4dba-a45d-a8b3e0bb5ded", 171 | "name": "manage-realm", 172 | "description": "${role_manage-realm}", 173 | "composite": false, 174 | "clientRole": true, 175 | "containerId": "1b024c36-0193-4c5b-8030-b9536db34fdf", 176 | "attributes": {} 177 | }, 178 | { 179 | "id": "c80848c9-833d-4c66-aa29-fa6ebae3e3ce", 180 | "name": "view-events", 181 | "description": "${role_view-events}", 182 | "composite": false, 183 | "clientRole": true, 184 | "containerId": "1b024c36-0193-4c5b-8030-b9536db34fdf", 185 | "attributes": {} 186 | }, 187 | { 188 | "id": "81d35256-b9ba-4238-9acd-622b73443129", 189 | "name": "realm-admin", 190 | "description": "${role_realm-admin}", 191 | "composite": true, 192 | "composites": { 193 | "client": { 194 | "realm-management": [ 195 | "create-client", 196 | "manage-events", 197 | "query-clients", 198 | "query-users", 199 | "query-realms", 200 | "view-users", 201 | "manage-identity-providers", 202 | "manage-realm", 203 | "view-events", 204 | "view-realm", 205 | "view-identity-providers", 206 | "query-groups", 207 | "impersonation", 208 | "manage-users", 209 | "view-authorization", 210 | "manage-clients", 211 | "view-clients", 212 | "manage-authorization" 213 | ] 214 | } 215 | }, 216 | "clientRole": true, 217 | "containerId": "1b024c36-0193-4c5b-8030-b9536db34fdf", 218 | "attributes": {} 219 | }, 220 | { 221 | "id": "05c8970e-5f29-45f0-815e-420c82804ec1", 222 | "name": "view-realm", 223 | "description": "${role_view-realm}", 224 | "composite": false, 225 | "clientRole": true, 226 | "containerId": "1b024c36-0193-4c5b-8030-b9536db34fdf", 227 | "attributes": {} 228 | }, 229 | { 230 | "id": "c398959e-22d5-4afc-b4cc-e034441becb2", 231 | "name": "query-groups", 232 | "description": "${role_query-groups}", 233 | "composite": false, 234 | "clientRole": true, 235 | "containerId": "1b024c36-0193-4c5b-8030-b9536db34fdf", 236 | "attributes": {} 237 | }, 238 | { 239 | "id": "1365306b-2582-4082-882f-eea84bc8d2b3", 240 | "name": "view-identity-providers", 241 | "description": "${role_view-identity-providers}", 242 | "composite": false, 243 | "clientRole": true, 244 | "containerId": "1b024c36-0193-4c5b-8030-b9536db34fdf", 245 | "attributes": {} 246 | }, 247 | { 248 | "id": "0d9bfb23-2e8e-4562-8af1-11aa92b24311", 249 | "name": "impersonation", 250 | "description": "${role_impersonation}", 251 | "composite": false, 252 | "clientRole": true, 253 | "containerId": "1b024c36-0193-4c5b-8030-b9536db34fdf", 254 | "attributes": {} 255 | }, 256 | { 257 | "id": "055c8f6f-268c-4065-bd78-40efc53107fa", 258 | "name": "manage-users", 259 | "description": "${role_manage-users}", 260 | "composite": false, 261 | "clientRole": true, 262 | "containerId": "1b024c36-0193-4c5b-8030-b9536db34fdf", 263 | "attributes": {} 264 | }, 265 | { 266 | "id": "4441dbec-3842-4a7a-853b-b369208ab371", 267 | "name": "manage-clients", 268 | "description": "${role_manage-clients}", 269 | "composite": false, 270 | "clientRole": true, 271 | "containerId": "1b024c36-0193-4c5b-8030-b9536db34fdf", 272 | "attributes": {} 273 | }, 274 | { 275 | "id": "9f4a7706-75d7-47eb-97e6-3ceb473c9710", 276 | "name": "view-authorization", 277 | "description": "${role_view-authorization}", 278 | "composite": false, 279 | "clientRole": true, 280 | "containerId": "1b024c36-0193-4c5b-8030-b9536db34fdf", 281 | "attributes": {} 282 | }, 283 | { 284 | "id": "c98f856a-c0be-439c-b22f-422953291fd2", 285 | "name": "manage-authorization", 286 | "description": "${role_manage-authorization}", 287 | "composite": false, 288 | "clientRole": true, 289 | "containerId": "1b024c36-0193-4c5b-8030-b9536db34fdf", 290 | "attributes": {} 291 | }, 292 | { 293 | "id": "2926e629-715f-4cf6-8a2f-4984f2b87b25", 294 | "name": "view-clients", 295 | "description": "${role_view-clients}", 296 | "composite": true, 297 | "composites": { 298 | "client": { 299 | "realm-management": [ 300 | "query-clients" 301 | ] 302 | } 303 | }, 304 | "clientRole": true, 305 | "containerId": "1b024c36-0193-4c5b-8030-b9536db34fdf", 306 | "attributes": {} 307 | } 308 | ], 309 | "security-admin-console": [], 310 | "admin-cli": [], 311 | "account-console": [], 312 | "broker": [ 313 | { 314 | "id": "62364646-55ad-4428-b7ba-909fed7eb727", 315 | "name": "read-token", 316 | "description": "${role_read-token}", 317 | "composite": false, 318 | "clientRole": true, 319 | "containerId": "54abba39-84ab-4d37-87c9-864dda16f7ee", 320 | "attributes": {} 321 | } 322 | ], 323 | "account": [ 324 | { 325 | "id": "c34ff867-4326-4e3b-b091-422db48fe63c", 326 | "name": "view-applications", 327 | "description": "${role_view-applications}", 328 | "composite": false, 329 | "clientRole": true, 330 | "containerId": "edd9455b-9993-4d2d-b793-e12abb1f4127", 331 | "attributes": {} 332 | }, 333 | { 334 | "id": "c7502250-d5d9-470e-ae8e-ecf67ac5440a", 335 | "name": "view-consent", 336 | "description": "${role_view-consent}", 337 | "composite": false, 338 | "clientRole": true, 339 | "containerId": "edd9455b-9993-4d2d-b793-e12abb1f4127", 340 | "attributes": {} 341 | }, 342 | { 343 | "id": "21ff2807-7614-431e-8a2a-eeb3ce613848", 344 | "name": "delete-account", 345 | "description": "${role_delete-account}", 346 | "composite": false, 347 | "clientRole": true, 348 | "containerId": "edd9455b-9993-4d2d-b793-e12abb1f4127", 349 | "attributes": {} 350 | }, 351 | { 352 | "id": "af99088f-40d5-4395-8fb9-4fd8fcfe0173", 353 | "name": "manage-account", 354 | "description": "${role_manage-account}", 355 | "composite": true, 356 | "composites": { 357 | "client": { 358 | "account": [ 359 | "manage-account-links" 360 | ] 361 | } 362 | }, 363 | "clientRole": true, 364 | "containerId": "edd9455b-9993-4d2d-b793-e12abb1f4127", 365 | "attributes": {} 366 | }, 367 | { 368 | "id": "8b635393-31e1-42a7-9cb4-4c6dae588c36", 369 | "name": "manage-account-links", 370 | "description": "${role_manage-account-links}", 371 | "composite": false, 372 | "clientRole": true, 373 | "containerId": "edd9455b-9993-4d2d-b793-e12abb1f4127", 374 | "attributes": {} 375 | }, 376 | { 377 | "id": "741d0783-3f6e-403f-9b85-b210552f3359", 378 | "name": "manage-consent", 379 | "description": "${role_manage-consent}", 380 | "composite": true, 381 | "composites": { 382 | "client": { 383 | "account": [ 384 | "view-consent" 385 | ] 386 | } 387 | }, 388 | "clientRole": true, 389 | "containerId": "edd9455b-9993-4d2d-b793-e12abb1f4127", 390 | "attributes": {} 391 | }, 392 | { 393 | "id": "c2135632-5d56-4186-ba48-09d30c23b0a3", 394 | "name": "view-profile", 395 | "description": "${role_view-profile}", 396 | "composite": false, 397 | "clientRole": true, 398 | "containerId": "edd9455b-9993-4d2d-b793-e12abb1f4127", 399 | "attributes": {} 400 | } 401 | ] 402 | } 403 | }, 404 | "groups": [], 405 | "defaultRole": { 406 | "id": "09e83b6c-874a-46e1-a5f1-404b758c9358", 407 | "name": "default-roles-springbootkeycloakadminapi", 408 | "description": "${role_default-roles}", 409 | "composite": true, 410 | "clientRole": false, 411 | "containerId": "SpringBootKeycloakAdminAPI" 412 | }, 413 | "requiredCredentials": [ 414 | "password" 415 | ], 416 | "otpPolicyType": "totp", 417 | "otpPolicyAlgorithm": "HmacSHA1", 418 | "otpPolicyInitialCounter": 0, 419 | "otpPolicyDigits": 6, 420 | "otpPolicyLookAheadWindow": 1, 421 | "otpPolicyPeriod": 30, 422 | "otpSupportedApplications": [ 423 | "FreeOTP", 424 | "Google Authenticator" 425 | ], 426 | "webAuthnPolicyRpEntityName": "keycloak", 427 | "webAuthnPolicySignatureAlgorithms": [ 428 | "ES256" 429 | ], 430 | "webAuthnPolicyRpId": "", 431 | "webAuthnPolicyAttestationConveyancePreference": "not specified", 432 | "webAuthnPolicyAuthenticatorAttachment": "not specified", 433 | "webAuthnPolicyRequireResidentKey": "not specified", 434 | "webAuthnPolicyUserVerificationRequirement": "not specified", 435 | "webAuthnPolicyCreateTimeout": 0, 436 | "webAuthnPolicyAvoidSameAuthenticatorRegister": false, 437 | "webAuthnPolicyAcceptableAaguids": [], 438 | "webAuthnPolicyPasswordlessRpEntityName": "keycloak", 439 | "webAuthnPolicyPasswordlessSignatureAlgorithms": [ 440 | "ES256" 441 | ], 442 | "webAuthnPolicyPasswordlessRpId": "", 443 | "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified", 444 | "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified", 445 | "webAuthnPolicyPasswordlessRequireResidentKey": "not specified", 446 | "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified", 447 | "webAuthnPolicyPasswordlessCreateTimeout": 0, 448 | "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false, 449 | "webAuthnPolicyPasswordlessAcceptableAaguids": [], 450 | "scopeMappings": [ 451 | { 452 | "clientScope": "offline_access", 453 | "roles": [ 454 | "offline_access" 455 | ] 456 | } 457 | ], 458 | "clientScopeMappings": { 459 | "account": [ 460 | { 461 | "client": "account-console", 462 | "roles": [ 463 | "manage-account" 464 | ] 465 | } 466 | ] 467 | }, 468 | "clients": [ 469 | { 470 | "id": "edd9455b-9993-4d2d-b793-e12abb1f4127", 471 | "clientId": "account", 472 | "name": "${client_account}", 473 | "rootUrl": "${authBaseUrl}", 474 | "baseUrl": "/realms/SpringBootKeycloakAdminAPI/account/", 475 | "surrogateAuthRequired": false, 476 | "enabled": true, 477 | "alwaysDisplayInConsole": false, 478 | "clientAuthenticatorType": "client-secret", 479 | "redirectUris": [ 480 | "/realms/SpringBootKeycloakAdminAPI/account/*" 481 | ], 482 | "webOrigins": [], 483 | "notBefore": 0, 484 | "bearerOnly": false, 485 | "consentRequired": false, 486 | "standardFlowEnabled": true, 487 | "implicitFlowEnabled": false, 488 | "directAccessGrantsEnabled": false, 489 | "serviceAccountsEnabled": false, 490 | "publicClient": true, 491 | "frontchannelLogout": false, 492 | "protocol": "openid-connect", 493 | "attributes": {}, 494 | "authenticationFlowBindingOverrides": {}, 495 | "fullScopeAllowed": false, 496 | "nodeReRegistrationTimeout": 0, 497 | "defaultClientScopes": [ 498 | "web-origins", 499 | "profile", 500 | "roles", 501 | "email" 502 | ], 503 | "optionalClientScopes": [ 504 | "address", 505 | "phone", 506 | "offline_access", 507 | "microprofile-jwt" 508 | ] 509 | }, 510 | { 511 | "id": "4e3cb07c-7571-4eb5-8b82-9479cdd74219", 512 | "clientId": "account-console", 513 | "name": "${client_account-console}", 514 | "rootUrl": "${authBaseUrl}", 515 | "baseUrl": "/realms/SpringBootKeycloakAdminAPI/account/", 516 | "surrogateAuthRequired": false, 517 | "enabled": true, 518 | "alwaysDisplayInConsole": false, 519 | "clientAuthenticatorType": "client-secret", 520 | "redirectUris": [ 521 | "/realms/SpringBootKeycloakAdminAPI/account/*" 522 | ], 523 | "webOrigins": [], 524 | "notBefore": 0, 525 | "bearerOnly": false, 526 | "consentRequired": false, 527 | "standardFlowEnabled": true, 528 | "implicitFlowEnabled": false, 529 | "directAccessGrantsEnabled": false, 530 | "serviceAccountsEnabled": false, 531 | "publicClient": true, 532 | "frontchannelLogout": false, 533 | "protocol": "openid-connect", 534 | "attributes": { 535 | "pkce.code.challenge.method": "S256" 536 | }, 537 | "authenticationFlowBindingOverrides": {}, 538 | "fullScopeAllowed": false, 539 | "nodeReRegistrationTimeout": 0, 540 | "protocolMappers": [ 541 | { 542 | "id": "1b0d0fd1-899f-4d10-8418-7420d60c9cc0", 543 | "name": "audience resolve", 544 | "protocol": "openid-connect", 545 | "protocolMapper": "oidc-audience-resolve-mapper", 546 | "consentRequired": false, 547 | "config": {} 548 | } 549 | ], 550 | "defaultClientScopes": [ 551 | "web-origins", 552 | "profile", 553 | "roles", 554 | "email" 555 | ], 556 | "optionalClientScopes": [ 557 | "address", 558 | "phone", 559 | "offline_access", 560 | "microprofile-jwt" 561 | ] 562 | }, 563 | { 564 | "id": "37f896eb-21f3-4feb-90a6-929dfab143a0", 565 | "clientId": "admin-cli", 566 | "name": "${client_admin-cli}", 567 | "surrogateAuthRequired": false, 568 | "enabled": true, 569 | "alwaysDisplayInConsole": false, 570 | "clientAuthenticatorType": "client-secret", 571 | "redirectUris": [], 572 | "webOrigins": [], 573 | "notBefore": 0, 574 | "bearerOnly": false, 575 | "consentRequired": false, 576 | "standardFlowEnabled": false, 577 | "implicitFlowEnabled": false, 578 | "directAccessGrantsEnabled": true, 579 | "serviceAccountsEnabled": false, 580 | "publicClient": true, 581 | "frontchannelLogout": false, 582 | "protocol": "openid-connect", 583 | "attributes": {}, 584 | "authenticationFlowBindingOverrides": {}, 585 | "fullScopeAllowed": false, 586 | "nodeReRegistrationTimeout": 0, 587 | "defaultClientScopes": [ 588 | "web-origins", 589 | "profile", 590 | "roles", 591 | "email" 592 | ], 593 | "optionalClientScopes": [ 594 | "address", 595 | "phone", 596 | "offline_access", 597 | "microprofile-jwt" 598 | ] 599 | }, 600 | { 601 | "id": "54abba39-84ab-4d37-87c9-864dda16f7ee", 602 | "clientId": "broker", 603 | "name": "${client_broker}", 604 | "surrogateAuthRequired": false, 605 | "enabled": true, 606 | "alwaysDisplayInConsole": false, 607 | "clientAuthenticatorType": "client-secret", 608 | "redirectUris": [], 609 | "webOrigins": [], 610 | "notBefore": 0, 611 | "bearerOnly": true, 612 | "consentRequired": false, 613 | "standardFlowEnabled": true, 614 | "implicitFlowEnabled": false, 615 | "directAccessGrantsEnabled": false, 616 | "serviceAccountsEnabled": false, 617 | "publicClient": false, 618 | "frontchannelLogout": false, 619 | "protocol": "openid-connect", 620 | "attributes": {}, 621 | "authenticationFlowBindingOverrides": {}, 622 | "fullScopeAllowed": false, 623 | "nodeReRegistrationTimeout": 0, 624 | "defaultClientScopes": [ 625 | "web-origins", 626 | "profile", 627 | "roles", 628 | "email" 629 | ], 630 | "optionalClientScopes": [ 631 | "address", 632 | "phone", 633 | "offline_access", 634 | "microprofile-jwt" 635 | ] 636 | }, 637 | { 638 | "id": "1b024c36-0193-4c5b-8030-b9536db34fdf", 639 | "clientId": "realm-management", 640 | "name": "${client_realm-management}", 641 | "surrogateAuthRequired": false, 642 | "enabled": true, 643 | "alwaysDisplayInConsole": false, 644 | "clientAuthenticatorType": "client-secret", 645 | "redirectUris": [], 646 | "webOrigins": [], 647 | "notBefore": 0, 648 | "bearerOnly": true, 649 | "consentRequired": false, 650 | "standardFlowEnabled": true, 651 | "implicitFlowEnabled": false, 652 | "directAccessGrantsEnabled": false, 653 | "serviceAccountsEnabled": false, 654 | "publicClient": false, 655 | "frontchannelLogout": false, 656 | "protocol": "openid-connect", 657 | "attributes": {}, 658 | "authenticationFlowBindingOverrides": {}, 659 | "fullScopeAllowed": false, 660 | "nodeReRegistrationTimeout": 0, 661 | "defaultClientScopes": [ 662 | "web-origins", 663 | "profile", 664 | "roles", 665 | "email" 666 | ], 667 | "optionalClientScopes": [ 668 | "address", 669 | "phone", 670 | "offline_access", 671 | "microprofile-jwt" 672 | ] 673 | }, 674 | { 675 | "id": "e9dc45bc-6005-4ba8-9dde-095892d7f905", 676 | "clientId": "security-admin-console", 677 | "name": "${client_security-admin-console}", 678 | "rootUrl": "${authAdminUrl}", 679 | "baseUrl": "/admin/SpringBootKeycloakAdminAPI/console/", 680 | "surrogateAuthRequired": false, 681 | "enabled": true, 682 | "alwaysDisplayInConsole": false, 683 | "clientAuthenticatorType": "client-secret", 684 | "redirectUris": [ 685 | "/admin/SpringBootKeycloakAdminAPI/console/*" 686 | ], 687 | "webOrigins": [ 688 | "+" 689 | ], 690 | "notBefore": 0, 691 | "bearerOnly": false, 692 | "consentRequired": false, 693 | "standardFlowEnabled": true, 694 | "implicitFlowEnabled": false, 695 | "directAccessGrantsEnabled": false, 696 | "serviceAccountsEnabled": false, 697 | "publicClient": true, 698 | "frontchannelLogout": false, 699 | "protocol": "openid-connect", 700 | "attributes": { 701 | "pkce.code.challenge.method": "S256" 702 | }, 703 | "authenticationFlowBindingOverrides": {}, 704 | "fullScopeAllowed": false, 705 | "nodeReRegistrationTimeout": 0, 706 | "protocolMappers": [ 707 | { 708 | "id": "9152c80c-bbae-45d6-944c-495e175f4858", 709 | "name": "locale", 710 | "protocol": "openid-connect", 711 | "protocolMapper": "oidc-usermodel-attribute-mapper", 712 | "consentRequired": false, 713 | "config": { 714 | "userinfo.token.claim": "true", 715 | "user.attribute": "locale", 716 | "id.token.claim": "true", 717 | "access.token.claim": "true", 718 | "claim.name": "locale", 719 | "jsonType.label": "String" 720 | } 721 | } 722 | ], 723 | "defaultClientScopes": [ 724 | "web-origins", 725 | "profile", 726 | "roles", 727 | "email" 728 | ], 729 | "optionalClientScopes": [ 730 | "address", 731 | "phone", 732 | "offline_access", 733 | "microprofile-jwt" 734 | ] 735 | } 736 | ], 737 | "clientScopes": [ 738 | { 739 | "id": "1cfe6822-0f9a-4b84-a7d0-234835e8e57f", 740 | "name": "profile", 741 | "description": "OpenID Connect built-in scope: profile", 742 | "protocol": "openid-connect", 743 | "attributes": { 744 | "include.in.token.scope": "true", 745 | "display.on.consent.screen": "true", 746 | "consent.screen.text": "${profileScopeConsentText}" 747 | }, 748 | "protocolMappers": [ 749 | { 750 | "id": "25604eb4-7ca0-4e93-95d5-78d822dd7a5f", 751 | "name": "family name", 752 | "protocol": "openid-connect", 753 | "protocolMapper": "oidc-usermodel-property-mapper", 754 | "consentRequired": false, 755 | "config": { 756 | "userinfo.token.claim": "true", 757 | "user.attribute": "lastName", 758 | "id.token.claim": "true", 759 | "access.token.claim": "true", 760 | "claim.name": "family_name", 761 | "jsonType.label": "String" 762 | } 763 | }, 764 | { 765 | "id": "21911c61-fa03-4f8a-b9ab-5f402bf955ed", 766 | "name": "picture", 767 | "protocol": "openid-connect", 768 | "protocolMapper": "oidc-usermodel-attribute-mapper", 769 | "consentRequired": false, 770 | "config": { 771 | "userinfo.token.claim": "true", 772 | "user.attribute": "picture", 773 | "id.token.claim": "true", 774 | "access.token.claim": "true", 775 | "claim.name": "picture", 776 | "jsonType.label": "String" 777 | } 778 | }, 779 | { 780 | "id": "1ae44bc1-92bb-4079-9f12-d9f698e473ed", 781 | "name": "zoneinfo", 782 | "protocol": "openid-connect", 783 | "protocolMapper": "oidc-usermodel-attribute-mapper", 784 | "consentRequired": false, 785 | "config": { 786 | "userinfo.token.claim": "true", 787 | "user.attribute": "zoneinfo", 788 | "id.token.claim": "true", 789 | "access.token.claim": "true", 790 | "claim.name": "zoneinfo", 791 | "jsonType.label": "String" 792 | } 793 | }, 794 | { 795 | "id": "01ac4077-4248-4dd8-a917-414fb3bb41aa", 796 | "name": "username", 797 | "protocol": "openid-connect", 798 | "protocolMapper": "oidc-usermodel-property-mapper", 799 | "consentRequired": false, 800 | "config": { 801 | "userinfo.token.claim": "true", 802 | "user.attribute": "username", 803 | "id.token.claim": "true", 804 | "access.token.claim": "true", 805 | "claim.name": "preferred_username", 806 | "jsonType.label": "String" 807 | } 808 | }, 809 | { 810 | "id": "72bd716b-b73b-450a-a208-e490f1a6a27e", 811 | "name": "gender", 812 | "protocol": "openid-connect", 813 | "protocolMapper": "oidc-usermodel-attribute-mapper", 814 | "consentRequired": false, 815 | "config": { 816 | "userinfo.token.claim": "true", 817 | "user.attribute": "gender", 818 | "id.token.claim": "true", 819 | "access.token.claim": "true", 820 | "claim.name": "gender", 821 | "jsonType.label": "String" 822 | } 823 | }, 824 | { 825 | "id": "9443ddae-bc7e-4824-9977-81dedf1e04f9", 826 | "name": "nickname", 827 | "protocol": "openid-connect", 828 | "protocolMapper": "oidc-usermodel-attribute-mapper", 829 | "consentRequired": false, 830 | "config": { 831 | "userinfo.token.claim": "true", 832 | "user.attribute": "nickname", 833 | "id.token.claim": "true", 834 | "access.token.claim": "true", 835 | "claim.name": "nickname", 836 | "jsonType.label": "String" 837 | } 838 | }, 839 | { 840 | "id": "c83ea903-c6d2-4378-9fb1-e321577ae342", 841 | "name": "middle name", 842 | "protocol": "openid-connect", 843 | "protocolMapper": "oidc-usermodel-attribute-mapper", 844 | "consentRequired": false, 845 | "config": { 846 | "userinfo.token.claim": "true", 847 | "user.attribute": "middleName", 848 | "id.token.claim": "true", 849 | "access.token.claim": "true", 850 | "claim.name": "middle_name", 851 | "jsonType.label": "String" 852 | } 853 | }, 854 | { 855 | "id": "e817c6e6-3e46-4229-af33-9c9bfa6839ad", 856 | "name": "birthdate", 857 | "protocol": "openid-connect", 858 | "protocolMapper": "oidc-usermodel-attribute-mapper", 859 | "consentRequired": false, 860 | "config": { 861 | "userinfo.token.claim": "true", 862 | "user.attribute": "birthdate", 863 | "id.token.claim": "true", 864 | "access.token.claim": "true", 865 | "claim.name": "birthdate", 866 | "jsonType.label": "String" 867 | } 868 | }, 869 | { 870 | "id": "20254a9e-e935-41ea-b3fa-bb98b83a162a", 871 | "name": "website", 872 | "protocol": "openid-connect", 873 | "protocolMapper": "oidc-usermodel-attribute-mapper", 874 | "consentRequired": false, 875 | "config": { 876 | "userinfo.token.claim": "true", 877 | "user.attribute": "website", 878 | "id.token.claim": "true", 879 | "access.token.claim": "true", 880 | "claim.name": "website", 881 | "jsonType.label": "String" 882 | } 883 | }, 884 | { 885 | "id": "7d8e08e0-38eb-4ff5-a799-63109cd6a65c", 886 | "name": "locale", 887 | "protocol": "openid-connect", 888 | "protocolMapper": "oidc-usermodel-attribute-mapper", 889 | "consentRequired": false, 890 | "config": { 891 | "userinfo.token.claim": "true", 892 | "user.attribute": "locale", 893 | "id.token.claim": "true", 894 | "access.token.claim": "true", 895 | "claim.name": "locale", 896 | "jsonType.label": "String" 897 | } 898 | }, 899 | { 900 | "id": "f76042eb-4238-4373-9aee-71e62869adaf", 901 | "name": "given name", 902 | "protocol": "openid-connect", 903 | "protocolMapper": "oidc-usermodel-property-mapper", 904 | "consentRequired": false, 905 | "config": { 906 | "userinfo.token.claim": "true", 907 | "user.attribute": "firstName", 908 | "id.token.claim": "true", 909 | "access.token.claim": "true", 910 | "claim.name": "given_name", 911 | "jsonType.label": "String" 912 | } 913 | }, 914 | { 915 | "id": "732fb9cb-0b72-434a-b74d-302d44e431d2", 916 | "name": "profile", 917 | "protocol": "openid-connect", 918 | "protocolMapper": "oidc-usermodel-attribute-mapper", 919 | "consentRequired": false, 920 | "config": { 921 | "userinfo.token.claim": "true", 922 | "user.attribute": "profile", 923 | "id.token.claim": "true", 924 | "access.token.claim": "true", 925 | "claim.name": "profile", 926 | "jsonType.label": "String" 927 | } 928 | }, 929 | { 930 | "id": "0336778f-45b1-4983-a0ad-c6f5063a05f4", 931 | "name": "updated at", 932 | "protocol": "openid-connect", 933 | "protocolMapper": "oidc-usermodel-attribute-mapper", 934 | "consentRequired": false, 935 | "config": { 936 | "userinfo.token.claim": "true", 937 | "user.attribute": "updatedAt", 938 | "id.token.claim": "true", 939 | "access.token.claim": "true", 940 | "claim.name": "updated_at", 941 | "jsonType.label": "String" 942 | } 943 | }, 944 | { 945 | "id": "084bb4ca-a90a-44e9-99d9-2879e4f66ef3", 946 | "name": "full name", 947 | "protocol": "openid-connect", 948 | "protocolMapper": "oidc-full-name-mapper", 949 | "consentRequired": false, 950 | "config": { 951 | "id.token.claim": "true", 952 | "access.token.claim": "true", 953 | "userinfo.token.claim": "true" 954 | } 955 | } 956 | ] 957 | }, 958 | { 959 | "id": "efc9d154-322d-413c-8ba3-dd6e00989abd", 960 | "name": "offline_access", 961 | "description": "OpenID Connect built-in scope: offline_access", 962 | "protocol": "openid-connect", 963 | "attributes": { 964 | "consent.screen.text": "${offlineAccessScopeConsentText}", 965 | "display.on.consent.screen": "true" 966 | } 967 | }, 968 | { 969 | "id": "344d37d1-f2be-4083-b7ab-dcd21258f844", 970 | "name": "email", 971 | "description": "OpenID Connect built-in scope: email", 972 | "protocol": "openid-connect", 973 | "attributes": { 974 | "include.in.token.scope": "true", 975 | "display.on.consent.screen": "true", 976 | "consent.screen.text": "${emailScopeConsentText}" 977 | }, 978 | "protocolMappers": [ 979 | { 980 | "id": "78b50680-3c3a-4b12-ba5d-2a6ab92d9a79", 981 | "name": "email", 982 | "protocol": "openid-connect", 983 | "protocolMapper": "oidc-usermodel-property-mapper", 984 | "consentRequired": false, 985 | "config": { 986 | "userinfo.token.claim": "true", 987 | "user.attribute": "email", 988 | "id.token.claim": "true", 989 | "access.token.claim": "true", 990 | "claim.name": "email", 991 | "jsonType.label": "String" 992 | } 993 | }, 994 | { 995 | "id": "38affbd3-917b-43a7-accd-9e0740d4638b", 996 | "name": "email verified", 997 | "protocol": "openid-connect", 998 | "protocolMapper": "oidc-usermodel-property-mapper", 999 | "consentRequired": false, 1000 | "config": { 1001 | "userinfo.token.claim": "true", 1002 | "user.attribute": "emailVerified", 1003 | "id.token.claim": "true", 1004 | "access.token.claim": "true", 1005 | "claim.name": "email_verified", 1006 | "jsonType.label": "boolean" 1007 | } 1008 | } 1009 | ] 1010 | }, 1011 | { 1012 | "id": "a49f564d-f4ca-46c5-ba24-590422b85841", 1013 | "name": "microprofile-jwt", 1014 | "description": "Microprofile - JWT built-in scope", 1015 | "protocol": "openid-connect", 1016 | "attributes": { 1017 | "include.in.token.scope": "true", 1018 | "display.on.consent.screen": "false" 1019 | }, 1020 | "protocolMappers": [ 1021 | { 1022 | "id": "2ee7dab1-468f-4a46-9d5c-0f8fbe43ee0d", 1023 | "name": "groups", 1024 | "protocol": "openid-connect", 1025 | "protocolMapper": "oidc-usermodel-realm-role-mapper", 1026 | "consentRequired": false, 1027 | "config": { 1028 | "multivalued": "true", 1029 | "user.attribute": "foo", 1030 | "id.token.claim": "true", 1031 | "access.token.claim": "true", 1032 | "claim.name": "groups", 1033 | "jsonType.label": "String" 1034 | } 1035 | }, 1036 | { 1037 | "id": "16f51463-0aaf-4605-a234-9ce0438b273c", 1038 | "name": "upn", 1039 | "protocol": "openid-connect", 1040 | "protocolMapper": "oidc-usermodel-property-mapper", 1041 | "consentRequired": false, 1042 | "config": { 1043 | "userinfo.token.claim": "true", 1044 | "user.attribute": "username", 1045 | "id.token.claim": "true", 1046 | "access.token.claim": "true", 1047 | "claim.name": "upn", 1048 | "jsonType.label": "String" 1049 | } 1050 | } 1051 | ] 1052 | }, 1053 | { 1054 | "id": "45a2426d-e87c-4c9b-9a14-085bcfd1fe0a", 1055 | "name": "web-origins", 1056 | "description": "OpenID Connect scope for add allowed web origins to the access token", 1057 | "protocol": "openid-connect", 1058 | "attributes": { 1059 | "include.in.token.scope": "false", 1060 | "display.on.consent.screen": "false", 1061 | "consent.screen.text": "" 1062 | }, 1063 | "protocolMappers": [ 1064 | { 1065 | "id": "09e77576-38ec-4392-9f24-2ab57b31cb04", 1066 | "name": "allowed web origins", 1067 | "protocol": "openid-connect", 1068 | "protocolMapper": "oidc-allowed-origins-mapper", 1069 | "consentRequired": false, 1070 | "config": {} 1071 | } 1072 | ] 1073 | }, 1074 | { 1075 | "id": "31494e11-da14-4c9d-9026-89b359c208c6", 1076 | "name": "role_list", 1077 | "description": "SAML role list", 1078 | "protocol": "saml", 1079 | "attributes": { 1080 | "consent.screen.text": "${samlRoleListScopeConsentText}", 1081 | "display.on.consent.screen": "true" 1082 | }, 1083 | "protocolMappers": [ 1084 | { 1085 | "id": "0ba413b3-808b-4e8d-9319-3a7e246e2272", 1086 | "name": "role list", 1087 | "protocol": "saml", 1088 | "protocolMapper": "saml-role-list-mapper", 1089 | "consentRequired": false, 1090 | "config": { 1091 | "single": "false", 1092 | "attribute.nameformat": "Basic", 1093 | "attribute.name": "Role" 1094 | } 1095 | } 1096 | ] 1097 | }, 1098 | { 1099 | "id": "67c8c6b8-2d23-40d1-b0c8-47c85a1520c0", 1100 | "name": "phone", 1101 | "description": "OpenID Connect built-in scope: phone", 1102 | "protocol": "openid-connect", 1103 | "attributes": { 1104 | "include.in.token.scope": "true", 1105 | "display.on.consent.screen": "true", 1106 | "consent.screen.text": "${phoneScopeConsentText}" 1107 | }, 1108 | "protocolMappers": [ 1109 | { 1110 | "id": "2a84982a-a12d-4792-87be-c7e1e3b07a93", 1111 | "name": "phone number", 1112 | "protocol": "openid-connect", 1113 | "protocolMapper": "oidc-usermodel-attribute-mapper", 1114 | "consentRequired": false, 1115 | "config": { 1116 | "userinfo.token.claim": "true", 1117 | "user.attribute": "phoneNumber", 1118 | "id.token.claim": "true", 1119 | "access.token.claim": "true", 1120 | "claim.name": "phone_number", 1121 | "jsonType.label": "String" 1122 | } 1123 | }, 1124 | { 1125 | "id": "65288970-410f-48f0-9351-d8dab0888949", 1126 | "name": "phone number verified", 1127 | "protocol": "openid-connect", 1128 | "protocolMapper": "oidc-usermodel-attribute-mapper", 1129 | "consentRequired": false, 1130 | "config": { 1131 | "userinfo.token.claim": "true", 1132 | "user.attribute": "phoneNumberVerified", 1133 | "id.token.claim": "true", 1134 | "access.token.claim": "true", 1135 | "claim.name": "phone_number_verified", 1136 | "jsonType.label": "boolean" 1137 | } 1138 | } 1139 | ] 1140 | }, 1141 | { 1142 | "id": "2757cf35-6d5a-4db1-ad38-e76100220e3f", 1143 | "name": "address", 1144 | "description": "OpenID Connect built-in scope: address", 1145 | "protocol": "openid-connect", 1146 | "attributes": { 1147 | "include.in.token.scope": "true", 1148 | "display.on.consent.screen": "true", 1149 | "consent.screen.text": "${addressScopeConsentText}" 1150 | }, 1151 | "protocolMappers": [ 1152 | { 1153 | "id": "cf7b49cd-7c34-460b-b533-c0e7d5438a5b", 1154 | "name": "address", 1155 | "protocol": "openid-connect", 1156 | "protocolMapper": "oidc-address-mapper", 1157 | "consentRequired": false, 1158 | "config": { 1159 | "user.attribute.formatted": "formatted", 1160 | "user.attribute.country": "country", 1161 | "user.attribute.postal_code": "postal_code", 1162 | "userinfo.token.claim": "true", 1163 | "user.attribute.street": "street", 1164 | "id.token.claim": "true", 1165 | "user.attribute.region": "region", 1166 | "access.token.claim": "true", 1167 | "user.attribute.locality": "locality" 1168 | } 1169 | } 1170 | ] 1171 | }, 1172 | { 1173 | "id": "340f7c94-a1fd-41a5-8b94-1e683ea87075", 1174 | "name": "roles", 1175 | "description": "OpenID Connect scope for add user roles to the access token", 1176 | "protocol": "openid-connect", 1177 | "attributes": { 1178 | "include.in.token.scope": "false", 1179 | "display.on.consent.screen": "true", 1180 | "consent.screen.text": "${rolesScopeConsentText}" 1181 | }, 1182 | "protocolMappers": [ 1183 | { 1184 | "id": "cc98eaaf-c097-4ce5-92a2-b7323c9e63ec", 1185 | "name": "realm roles", 1186 | "protocol": "openid-connect", 1187 | "protocolMapper": "oidc-usermodel-realm-role-mapper", 1188 | "consentRequired": false, 1189 | "config": { 1190 | "user.attribute": "foo", 1191 | "access.token.claim": "true", 1192 | "claim.name": "realm_access.roles", 1193 | "jsonType.label": "String", 1194 | "multivalued": "true" 1195 | } 1196 | }, 1197 | { 1198 | "id": "b8b94531-9519-45e2-a04c-0cb24bd6ee3d", 1199 | "name": "audience resolve", 1200 | "protocol": "openid-connect", 1201 | "protocolMapper": "oidc-audience-resolve-mapper", 1202 | "consentRequired": false, 1203 | "config": {} 1204 | }, 1205 | { 1206 | "id": "c1a269dc-1dbd-4d50-b34f-610cfc3f2713", 1207 | "name": "client roles", 1208 | "protocol": "openid-connect", 1209 | "protocolMapper": "oidc-usermodel-client-role-mapper", 1210 | "consentRequired": false, 1211 | "config": { 1212 | "user.attribute": "foo", 1213 | "access.token.claim": "true", 1214 | "claim.name": "resource_access.${client_id}.roles", 1215 | "jsonType.label": "String", 1216 | "multivalued": "true" 1217 | } 1218 | } 1219 | ] 1220 | } 1221 | ], 1222 | "defaultDefaultClientScopes": [ 1223 | "role_list", 1224 | "profile", 1225 | "email", 1226 | "roles", 1227 | "web-origins" 1228 | ], 1229 | "defaultOptionalClientScopes": [ 1230 | "offline_access", 1231 | "address", 1232 | "phone", 1233 | "microprofile-jwt" 1234 | ], 1235 | "browserSecurityHeaders": { 1236 | "contentSecurityPolicyReportOnly": "", 1237 | "xContentTypeOptions": "nosniff", 1238 | "xRobotsTag": "none", 1239 | "xFrameOptions": "SAMEORIGIN", 1240 | "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", 1241 | "xXSSProtection": "1; mode=block", 1242 | "strictTransportSecurity": "max-age=31536000; includeSubDomains" 1243 | }, 1244 | "smtpServer": {}, 1245 | "eventsEnabled": false, 1246 | "eventsListeners": [ 1247 | "jboss-logging" 1248 | ], 1249 | "enabledEventTypes": [], 1250 | "adminEventsEnabled": false, 1251 | "adminEventsDetailsEnabled": false, 1252 | "identityProviders": [], 1253 | "identityProviderMappers": [], 1254 | "components": { 1255 | "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ 1256 | { 1257 | "id": "ef0b4c72-1b3b-4760-9e61-a1786f51fcb0", 1258 | "name": "Consent Required", 1259 | "providerId": "consent-required", 1260 | "subType": "anonymous", 1261 | "subComponents": {}, 1262 | "config": {} 1263 | }, 1264 | { 1265 | "id": "13c56126-c0d7-485e-b89a-0cd3f95e6da2", 1266 | "name": "Allowed Protocol Mapper Types", 1267 | "providerId": "allowed-protocol-mappers", 1268 | "subType": "authenticated", 1269 | "subComponents": {}, 1270 | "config": { 1271 | "allowed-protocol-mapper-types": [ 1272 | "oidc-usermodel-attribute-mapper", 1273 | "oidc-sha256-pairwise-sub-mapper", 1274 | "saml-user-property-mapper", 1275 | "saml-role-list-mapper", 1276 | "oidc-usermodel-property-mapper", 1277 | "oidc-address-mapper", 1278 | "oidc-full-name-mapper", 1279 | "saml-user-attribute-mapper" 1280 | ] 1281 | } 1282 | }, 1283 | { 1284 | "id": "48454321-5206-4226-92b8-a853dd74de73", 1285 | "name": "Max Clients Limit", 1286 | "providerId": "max-clients", 1287 | "subType": "anonymous", 1288 | "subComponents": {}, 1289 | "config": { 1290 | "max-clients": [ 1291 | "200" 1292 | ] 1293 | } 1294 | }, 1295 | { 1296 | "id": "462581b7-c9fb-4ac8-bf49-96ee244c8760", 1297 | "name": "Trusted Hosts", 1298 | "providerId": "trusted-hosts", 1299 | "subType": "anonymous", 1300 | "subComponents": {}, 1301 | "config": { 1302 | "host-sending-registration-request-must-match": [ 1303 | "true" 1304 | ], 1305 | "client-uris-must-match": [ 1306 | "true" 1307 | ] 1308 | } 1309 | }, 1310 | { 1311 | "id": "02baa388-ebbf-453a-8dd3-4634d70f9772", 1312 | "name": "Allowed Client Scopes", 1313 | "providerId": "allowed-client-templates", 1314 | "subType": "anonymous", 1315 | "subComponents": {}, 1316 | "config": { 1317 | "allow-default-scopes": [ 1318 | "true" 1319 | ] 1320 | } 1321 | }, 1322 | { 1323 | "id": "b5a0c9b2-0863-4c29-aefd-8c6f9a753bd8", 1324 | "name": "Allowed Client Scopes", 1325 | "providerId": "allowed-client-templates", 1326 | "subType": "authenticated", 1327 | "subComponents": {}, 1328 | "config": { 1329 | "allow-default-scopes": [ 1330 | "true" 1331 | ] 1332 | } 1333 | }, 1334 | { 1335 | "id": "8b7ec3ff-e741-475e-8fc0-e49a83b8e233", 1336 | "name": "Full Scope Disabled", 1337 | "providerId": "scope", 1338 | "subType": "anonymous", 1339 | "subComponents": {}, 1340 | "config": {} 1341 | }, 1342 | { 1343 | "id": "d2d65562-9d67-4ca0-ba3f-9e0cd2dc77fb", 1344 | "name": "Allowed Protocol Mapper Types", 1345 | "providerId": "allowed-protocol-mappers", 1346 | "subType": "anonymous", 1347 | "subComponents": {}, 1348 | "config": { 1349 | "allowed-protocol-mapper-types": [ 1350 | "oidc-usermodel-property-mapper", 1351 | "oidc-full-name-mapper", 1352 | "saml-user-attribute-mapper", 1353 | "oidc-address-mapper", 1354 | "oidc-usermodel-attribute-mapper", 1355 | "oidc-sha256-pairwise-sub-mapper", 1356 | "saml-user-property-mapper", 1357 | "saml-role-list-mapper" 1358 | ] 1359 | } 1360 | } 1361 | ], 1362 | "org.keycloak.keys.KeyProvider": [ 1363 | { 1364 | "id": "bc3a36ef-db95-4432-ba5d-9a808efb4123", 1365 | "name": "rsa-enc-generated", 1366 | "providerId": "rsa-enc-generated", 1367 | "subComponents": {}, 1368 | "config": { 1369 | "priority": [ 1370 | "100" 1371 | ], 1372 | "algorithm": [ 1373 | "RSA-OAEP" 1374 | ] 1375 | } 1376 | }, 1377 | { 1378 | "id": "9c3e4d64-d3e1-41bd-93cb-65db843afec7", 1379 | "name": "hmac-generated", 1380 | "providerId": "hmac-generated", 1381 | "subComponents": {}, 1382 | "config": { 1383 | "priority": [ 1384 | "100" 1385 | ], 1386 | "algorithm": [ 1387 | "HS256" 1388 | ] 1389 | } 1390 | }, 1391 | { 1392 | "id": "f70cb07b-0f32-4c43-96cd-d3fc478ced79", 1393 | "name": "aes-generated", 1394 | "providerId": "aes-generated", 1395 | "subComponents": {}, 1396 | "config": { 1397 | "priority": [ 1398 | "100" 1399 | ] 1400 | } 1401 | }, 1402 | { 1403 | "id": "ce037ab8-2450-4a26-9cf4-325a847ba492", 1404 | "name": "rsa-generated", 1405 | "providerId": "rsa-generated", 1406 | "subComponents": {}, 1407 | "config": { 1408 | "priority": [ 1409 | "100" 1410 | ] 1411 | } 1412 | } 1413 | ] 1414 | }, 1415 | "internationalizationEnabled": false, 1416 | "supportedLocales": [], 1417 | "authenticationFlows": [ 1418 | { 1419 | "id": "8ad484e3-d780-43b1-9f66-629730777562", 1420 | "alias": "Account verification options", 1421 | "description": "Method with which to verity the existing account", 1422 | "providerId": "basic-flow", 1423 | "topLevel": false, 1424 | "builtIn": true, 1425 | "authenticationExecutions": [ 1426 | { 1427 | "authenticator": "idp-email-verification", 1428 | "authenticatorFlow": false, 1429 | "requirement": "ALTERNATIVE", 1430 | "priority": 10, 1431 | "userSetupAllowed": false, 1432 | "autheticatorFlow": false 1433 | }, 1434 | { 1435 | "authenticatorFlow": true, 1436 | "requirement": "ALTERNATIVE", 1437 | "priority": 20, 1438 | "flowAlias": "Verify Existing Account by Re-authentication", 1439 | "userSetupAllowed": false, 1440 | "autheticatorFlow": true 1441 | } 1442 | ] 1443 | }, 1444 | { 1445 | "id": "d7879e81-99a8-4187-bbf6-22b8fa3b0f30", 1446 | "alias": "Authentication Options", 1447 | "description": "Authentication options.", 1448 | "providerId": "basic-flow", 1449 | "topLevel": false, 1450 | "builtIn": true, 1451 | "authenticationExecutions": [ 1452 | { 1453 | "authenticator": "basic-auth", 1454 | "authenticatorFlow": false, 1455 | "requirement": "REQUIRED", 1456 | "priority": 10, 1457 | "userSetupAllowed": false, 1458 | "autheticatorFlow": false 1459 | }, 1460 | { 1461 | "authenticator": "basic-auth-otp", 1462 | "authenticatorFlow": false, 1463 | "requirement": "DISABLED", 1464 | "priority": 20, 1465 | "userSetupAllowed": false, 1466 | "autheticatorFlow": false 1467 | }, 1468 | { 1469 | "authenticator": "auth-spnego", 1470 | "authenticatorFlow": false, 1471 | "requirement": "DISABLED", 1472 | "priority": 30, 1473 | "userSetupAllowed": false, 1474 | "autheticatorFlow": false 1475 | } 1476 | ] 1477 | }, 1478 | { 1479 | "id": "d2e179fb-3004-4402-9623-fb41b27fd05a", 1480 | "alias": "Browser - Conditional OTP", 1481 | "description": "Flow to determine if the OTP is required for the authentication", 1482 | "providerId": "basic-flow", 1483 | "topLevel": false, 1484 | "builtIn": true, 1485 | "authenticationExecutions": [ 1486 | { 1487 | "authenticator": "conditional-user-configured", 1488 | "authenticatorFlow": false, 1489 | "requirement": "REQUIRED", 1490 | "priority": 10, 1491 | "userSetupAllowed": false, 1492 | "autheticatorFlow": false 1493 | }, 1494 | { 1495 | "authenticator": "auth-otp-form", 1496 | "authenticatorFlow": false, 1497 | "requirement": "REQUIRED", 1498 | "priority": 20, 1499 | "userSetupAllowed": false, 1500 | "autheticatorFlow": false 1501 | } 1502 | ] 1503 | }, 1504 | { 1505 | "id": "b06a5a36-6183-4e5e-8f08-f047bf556b90", 1506 | "alias": "Direct Grant - Conditional OTP", 1507 | "description": "Flow to determine if the OTP is required for the authentication", 1508 | "providerId": "basic-flow", 1509 | "topLevel": false, 1510 | "builtIn": true, 1511 | "authenticationExecutions": [ 1512 | { 1513 | "authenticator": "conditional-user-configured", 1514 | "authenticatorFlow": false, 1515 | "requirement": "REQUIRED", 1516 | "priority": 10, 1517 | "userSetupAllowed": false, 1518 | "autheticatorFlow": false 1519 | }, 1520 | { 1521 | "authenticator": "direct-grant-validate-otp", 1522 | "authenticatorFlow": false, 1523 | "requirement": "REQUIRED", 1524 | "priority": 20, 1525 | "userSetupAllowed": false, 1526 | "autheticatorFlow": false 1527 | } 1528 | ] 1529 | }, 1530 | { 1531 | "id": "9018f050-7e08-4800-b7fd-6f3f29ac559b", 1532 | "alias": "First broker login - Conditional OTP", 1533 | "description": "Flow to determine if the OTP is required for the authentication", 1534 | "providerId": "basic-flow", 1535 | "topLevel": false, 1536 | "builtIn": true, 1537 | "authenticationExecutions": [ 1538 | { 1539 | "authenticator": "conditional-user-configured", 1540 | "authenticatorFlow": false, 1541 | "requirement": "REQUIRED", 1542 | "priority": 10, 1543 | "userSetupAllowed": false, 1544 | "autheticatorFlow": false 1545 | }, 1546 | { 1547 | "authenticator": "auth-otp-form", 1548 | "authenticatorFlow": false, 1549 | "requirement": "REQUIRED", 1550 | "priority": 20, 1551 | "userSetupAllowed": false, 1552 | "autheticatorFlow": false 1553 | } 1554 | ] 1555 | }, 1556 | { 1557 | "id": "2ff609eb-63b3-419e-a9f2-2d9d7a6a5f2a", 1558 | "alias": "Handle Existing Account", 1559 | "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider", 1560 | "providerId": "basic-flow", 1561 | "topLevel": false, 1562 | "builtIn": true, 1563 | "authenticationExecutions": [ 1564 | { 1565 | "authenticator": "idp-confirm-link", 1566 | "authenticatorFlow": false, 1567 | "requirement": "REQUIRED", 1568 | "priority": 10, 1569 | "userSetupAllowed": false, 1570 | "autheticatorFlow": false 1571 | }, 1572 | { 1573 | "authenticatorFlow": true, 1574 | "requirement": "REQUIRED", 1575 | "priority": 20, 1576 | "flowAlias": "Account verification options", 1577 | "userSetupAllowed": false, 1578 | "autheticatorFlow": true 1579 | } 1580 | ] 1581 | }, 1582 | { 1583 | "id": "177d0497-fb58-4f74-ba5c-4bf162df682f", 1584 | "alias": "Reset - Conditional OTP", 1585 | "description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", 1586 | "providerId": "basic-flow", 1587 | "topLevel": false, 1588 | "builtIn": true, 1589 | "authenticationExecutions": [ 1590 | { 1591 | "authenticator": "conditional-user-configured", 1592 | "authenticatorFlow": false, 1593 | "requirement": "REQUIRED", 1594 | "priority": 10, 1595 | "userSetupAllowed": false, 1596 | "autheticatorFlow": false 1597 | }, 1598 | { 1599 | "authenticator": "reset-otp", 1600 | "authenticatorFlow": false, 1601 | "requirement": "REQUIRED", 1602 | "priority": 20, 1603 | "userSetupAllowed": false, 1604 | "autheticatorFlow": false 1605 | } 1606 | ] 1607 | }, 1608 | { 1609 | "id": "daf0f8c6-48fb-4a41-a7ca-a28d70feefc7", 1610 | "alias": "User creation or linking", 1611 | "description": "Flow for the existing/non-existing user alternatives", 1612 | "providerId": "basic-flow", 1613 | "topLevel": false, 1614 | "builtIn": true, 1615 | "authenticationExecutions": [ 1616 | { 1617 | "authenticatorConfig": "create unique user config", 1618 | "authenticator": "idp-create-user-if-unique", 1619 | "authenticatorFlow": false, 1620 | "requirement": "ALTERNATIVE", 1621 | "priority": 10, 1622 | "userSetupAllowed": false, 1623 | "autheticatorFlow": false 1624 | }, 1625 | { 1626 | "authenticatorFlow": true, 1627 | "requirement": "ALTERNATIVE", 1628 | "priority": 20, 1629 | "flowAlias": "Handle Existing Account", 1630 | "userSetupAllowed": false, 1631 | "autheticatorFlow": true 1632 | } 1633 | ] 1634 | }, 1635 | { 1636 | "id": "0231915c-3a12-4b8f-a389-3ce58a434f50", 1637 | "alias": "Verify Existing Account by Re-authentication", 1638 | "description": "Reauthentication of existing account", 1639 | "providerId": "basic-flow", 1640 | "topLevel": false, 1641 | "builtIn": true, 1642 | "authenticationExecutions": [ 1643 | { 1644 | "authenticator": "idp-username-password-form", 1645 | "authenticatorFlow": false, 1646 | "requirement": "REQUIRED", 1647 | "priority": 10, 1648 | "userSetupAllowed": false, 1649 | "autheticatorFlow": false 1650 | }, 1651 | { 1652 | "authenticatorFlow": true, 1653 | "requirement": "CONDITIONAL", 1654 | "priority": 20, 1655 | "flowAlias": "First broker login - Conditional OTP", 1656 | "userSetupAllowed": false, 1657 | "autheticatorFlow": true 1658 | } 1659 | ] 1660 | }, 1661 | { 1662 | "id": "a37718d5-0345-4b94-9be5-1fe1ef7caee6", 1663 | "alias": "browser", 1664 | "description": "browser based authentication", 1665 | "providerId": "basic-flow", 1666 | "topLevel": true, 1667 | "builtIn": true, 1668 | "authenticationExecutions": [ 1669 | { 1670 | "authenticator": "auth-cookie", 1671 | "authenticatorFlow": false, 1672 | "requirement": "ALTERNATIVE", 1673 | "priority": 10, 1674 | "userSetupAllowed": false, 1675 | "autheticatorFlow": false 1676 | }, 1677 | { 1678 | "authenticator": "auth-spnego", 1679 | "authenticatorFlow": false, 1680 | "requirement": "DISABLED", 1681 | "priority": 20, 1682 | "userSetupAllowed": false, 1683 | "autheticatorFlow": false 1684 | }, 1685 | { 1686 | "authenticator": "identity-provider-redirector", 1687 | "authenticatorFlow": false, 1688 | "requirement": "ALTERNATIVE", 1689 | "priority": 25, 1690 | "userSetupAllowed": false, 1691 | "autheticatorFlow": false 1692 | }, 1693 | { 1694 | "authenticatorFlow": true, 1695 | "requirement": "ALTERNATIVE", 1696 | "priority": 30, 1697 | "flowAlias": "forms", 1698 | "userSetupAllowed": false, 1699 | "autheticatorFlow": true 1700 | } 1701 | ] 1702 | }, 1703 | { 1704 | "id": "e1fdeb97-a91c-4b4e-82a3-0a67cbb722f7", 1705 | "alias": "clients", 1706 | "description": "Base authentication for clients", 1707 | "providerId": "client-flow", 1708 | "topLevel": true, 1709 | "builtIn": true, 1710 | "authenticationExecutions": [ 1711 | { 1712 | "authenticator": "client-secret", 1713 | "authenticatorFlow": false, 1714 | "requirement": "ALTERNATIVE", 1715 | "priority": 10, 1716 | "userSetupAllowed": false, 1717 | "autheticatorFlow": false 1718 | }, 1719 | { 1720 | "authenticator": "client-jwt", 1721 | "authenticatorFlow": false, 1722 | "requirement": "ALTERNATIVE", 1723 | "priority": 20, 1724 | "userSetupAllowed": false, 1725 | "autheticatorFlow": false 1726 | }, 1727 | { 1728 | "authenticator": "client-secret-jwt", 1729 | "authenticatorFlow": false, 1730 | "requirement": "ALTERNATIVE", 1731 | "priority": 30, 1732 | "userSetupAllowed": false, 1733 | "autheticatorFlow": false 1734 | }, 1735 | { 1736 | "authenticator": "client-x509", 1737 | "authenticatorFlow": false, 1738 | "requirement": "ALTERNATIVE", 1739 | "priority": 40, 1740 | "userSetupAllowed": false, 1741 | "autheticatorFlow": false 1742 | } 1743 | ] 1744 | }, 1745 | { 1746 | "id": "93625cc8-4064-475a-a470-677a91c94a99", 1747 | "alias": "direct grant", 1748 | "description": "OpenID Connect Resource Owner Grant", 1749 | "providerId": "basic-flow", 1750 | "topLevel": true, 1751 | "builtIn": true, 1752 | "authenticationExecutions": [ 1753 | { 1754 | "authenticator": "direct-grant-validate-username", 1755 | "authenticatorFlow": false, 1756 | "requirement": "REQUIRED", 1757 | "priority": 10, 1758 | "userSetupAllowed": false, 1759 | "autheticatorFlow": false 1760 | }, 1761 | { 1762 | "authenticator": "direct-grant-validate-password", 1763 | "authenticatorFlow": false, 1764 | "requirement": "REQUIRED", 1765 | "priority": 20, 1766 | "userSetupAllowed": false, 1767 | "autheticatorFlow": false 1768 | }, 1769 | { 1770 | "authenticatorFlow": true, 1771 | "requirement": "CONDITIONAL", 1772 | "priority": 30, 1773 | "flowAlias": "Direct Grant - Conditional OTP", 1774 | "userSetupAllowed": false, 1775 | "autheticatorFlow": true 1776 | } 1777 | ] 1778 | }, 1779 | { 1780 | "id": "01533acd-0c26-439e-84b7-deb5638fc9ad", 1781 | "alias": "docker auth", 1782 | "description": "Used by Docker clients to authenticate against the IDP", 1783 | "providerId": "basic-flow", 1784 | "topLevel": true, 1785 | "builtIn": true, 1786 | "authenticationExecutions": [ 1787 | { 1788 | "authenticator": "docker-http-basic-authenticator", 1789 | "authenticatorFlow": false, 1790 | "requirement": "REQUIRED", 1791 | "priority": 10, 1792 | "userSetupAllowed": false, 1793 | "autheticatorFlow": false 1794 | } 1795 | ] 1796 | }, 1797 | { 1798 | "id": "143e5450-6e74-48e1-9240-66a99e68a09f", 1799 | "alias": "first broker login", 1800 | "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", 1801 | "providerId": "basic-flow", 1802 | "topLevel": true, 1803 | "builtIn": true, 1804 | "authenticationExecutions": [ 1805 | { 1806 | "authenticatorConfig": "review profile config", 1807 | "authenticator": "idp-review-profile", 1808 | "authenticatorFlow": false, 1809 | "requirement": "REQUIRED", 1810 | "priority": 10, 1811 | "userSetupAllowed": false, 1812 | "autheticatorFlow": false 1813 | }, 1814 | { 1815 | "authenticatorFlow": true, 1816 | "requirement": "REQUIRED", 1817 | "priority": 20, 1818 | "flowAlias": "User creation or linking", 1819 | "userSetupAllowed": false, 1820 | "autheticatorFlow": true 1821 | } 1822 | ] 1823 | }, 1824 | { 1825 | "id": "d16ff004-a2b4-44e4-a07e-9f8411b5686e", 1826 | "alias": "forms", 1827 | "description": "Username, password, otp and other auth forms.", 1828 | "providerId": "basic-flow", 1829 | "topLevel": false, 1830 | "builtIn": true, 1831 | "authenticationExecutions": [ 1832 | { 1833 | "authenticator": "auth-username-password-form", 1834 | "authenticatorFlow": false, 1835 | "requirement": "REQUIRED", 1836 | "priority": 10, 1837 | "userSetupAllowed": false, 1838 | "autheticatorFlow": false 1839 | }, 1840 | { 1841 | "authenticatorFlow": true, 1842 | "requirement": "CONDITIONAL", 1843 | "priority": 20, 1844 | "flowAlias": "Browser - Conditional OTP", 1845 | "userSetupAllowed": false, 1846 | "autheticatorFlow": true 1847 | } 1848 | ] 1849 | }, 1850 | { 1851 | "id": "7ae94347-b36b-41a1-b97d-1e0577a60234", 1852 | "alias": "http challenge", 1853 | "description": "An authentication flow based on challenge-response HTTP Authentication Schemes", 1854 | "providerId": "basic-flow", 1855 | "topLevel": true, 1856 | "builtIn": true, 1857 | "authenticationExecutions": [ 1858 | { 1859 | "authenticator": "no-cookie-redirect", 1860 | "authenticatorFlow": false, 1861 | "requirement": "REQUIRED", 1862 | "priority": 10, 1863 | "userSetupAllowed": false, 1864 | "autheticatorFlow": false 1865 | }, 1866 | { 1867 | "authenticatorFlow": true, 1868 | "requirement": "REQUIRED", 1869 | "priority": 20, 1870 | "flowAlias": "Authentication Options", 1871 | "userSetupAllowed": false, 1872 | "autheticatorFlow": true 1873 | } 1874 | ] 1875 | }, 1876 | { 1877 | "id": "4b198fe2-be73-4c84-84e5-3ae52136d03d", 1878 | "alias": "registration", 1879 | "description": "registration flow", 1880 | "providerId": "basic-flow", 1881 | "topLevel": true, 1882 | "builtIn": true, 1883 | "authenticationExecutions": [ 1884 | { 1885 | "authenticator": "registration-page-form", 1886 | "authenticatorFlow": true, 1887 | "requirement": "REQUIRED", 1888 | "priority": 10, 1889 | "flowAlias": "registration form", 1890 | "userSetupAllowed": false, 1891 | "autheticatorFlow": true 1892 | } 1893 | ] 1894 | }, 1895 | { 1896 | "id": "9a246b44-8a6d-42a0-8db0-f6f39c6ec094", 1897 | "alias": "registration form", 1898 | "description": "registration form", 1899 | "providerId": "form-flow", 1900 | "topLevel": false, 1901 | "builtIn": true, 1902 | "authenticationExecutions": [ 1903 | { 1904 | "authenticator": "registration-user-creation", 1905 | "authenticatorFlow": false, 1906 | "requirement": "REQUIRED", 1907 | "priority": 20, 1908 | "userSetupAllowed": false, 1909 | "autheticatorFlow": false 1910 | }, 1911 | { 1912 | "authenticator": "registration-profile-action", 1913 | "authenticatorFlow": false, 1914 | "requirement": "REQUIRED", 1915 | "priority": 40, 1916 | "userSetupAllowed": false, 1917 | "autheticatorFlow": false 1918 | }, 1919 | { 1920 | "authenticator": "registration-password-action", 1921 | "authenticatorFlow": false, 1922 | "requirement": "REQUIRED", 1923 | "priority": 50, 1924 | "userSetupAllowed": false, 1925 | "autheticatorFlow": false 1926 | }, 1927 | { 1928 | "authenticator": "registration-recaptcha-action", 1929 | "authenticatorFlow": false, 1930 | "requirement": "DISABLED", 1931 | "priority": 60, 1932 | "userSetupAllowed": false, 1933 | "autheticatorFlow": false 1934 | } 1935 | ] 1936 | }, 1937 | { 1938 | "id": "df7c6398-4bca-4098-a143-9941a2600cad", 1939 | "alias": "reset credentials", 1940 | "description": "Reset credentials for a user if they forgot their password or something", 1941 | "providerId": "basic-flow", 1942 | "topLevel": true, 1943 | "builtIn": true, 1944 | "authenticationExecutions": [ 1945 | { 1946 | "authenticator": "reset-credentials-choose-user", 1947 | "authenticatorFlow": false, 1948 | "requirement": "REQUIRED", 1949 | "priority": 10, 1950 | "userSetupAllowed": false, 1951 | "autheticatorFlow": false 1952 | }, 1953 | { 1954 | "authenticator": "reset-credential-email", 1955 | "authenticatorFlow": false, 1956 | "requirement": "REQUIRED", 1957 | "priority": 20, 1958 | "userSetupAllowed": false, 1959 | "autheticatorFlow": false 1960 | }, 1961 | { 1962 | "authenticator": "reset-password", 1963 | "authenticatorFlow": false, 1964 | "requirement": "REQUIRED", 1965 | "priority": 30, 1966 | "userSetupAllowed": false, 1967 | "autheticatorFlow": false 1968 | }, 1969 | { 1970 | "authenticatorFlow": true, 1971 | "requirement": "CONDITIONAL", 1972 | "priority": 40, 1973 | "flowAlias": "Reset - Conditional OTP", 1974 | "userSetupAllowed": false, 1975 | "autheticatorFlow": true 1976 | } 1977 | ] 1978 | }, 1979 | { 1980 | "id": "894e681c-4e69-40d0-889e-c654b2253679", 1981 | "alias": "saml ecp", 1982 | "description": "SAML ECP Profile Authentication Flow", 1983 | "providerId": "basic-flow", 1984 | "topLevel": true, 1985 | "builtIn": true, 1986 | "authenticationExecutions": [ 1987 | { 1988 | "authenticator": "http-basic-authenticator", 1989 | "authenticatorFlow": false, 1990 | "requirement": "REQUIRED", 1991 | "priority": 10, 1992 | "userSetupAllowed": false, 1993 | "autheticatorFlow": false 1994 | } 1995 | ] 1996 | } 1997 | ], 1998 | "authenticatorConfig": [ 1999 | { 2000 | "id": "d7e1544b-2a79-49e1-85ce-db56ba7fd683", 2001 | "alias": "create unique user config", 2002 | "config": { 2003 | "require.password.update.after.registration": "false" 2004 | } 2005 | }, 2006 | { 2007 | "id": "748c904d-4ad2-4126-838c-4e44a2c9b263", 2008 | "alias": "review profile config", 2009 | "config": { 2010 | "update.profile.on.first.login": "missing" 2011 | } 2012 | } 2013 | ], 2014 | "requiredActions": [ 2015 | { 2016 | "alias": "CONFIGURE_TOTP", 2017 | "name": "Configure OTP", 2018 | "providerId": "CONFIGURE_TOTP", 2019 | "enabled": true, 2020 | "defaultAction": false, 2021 | "priority": 10, 2022 | "config": {} 2023 | }, 2024 | { 2025 | "alias": "terms_and_conditions", 2026 | "name": "Terms and Conditions", 2027 | "providerId": "terms_and_conditions", 2028 | "enabled": false, 2029 | "defaultAction": false, 2030 | "priority": 20, 2031 | "config": {} 2032 | }, 2033 | { 2034 | "alias": "UPDATE_PASSWORD", 2035 | "name": "Update Password", 2036 | "providerId": "UPDATE_PASSWORD", 2037 | "enabled": true, 2038 | "defaultAction": false, 2039 | "priority": 30, 2040 | "config": {} 2041 | }, 2042 | { 2043 | "alias": "UPDATE_PROFILE", 2044 | "name": "Update Profile", 2045 | "providerId": "UPDATE_PROFILE", 2046 | "enabled": true, 2047 | "defaultAction": false, 2048 | "priority": 40, 2049 | "config": {} 2050 | }, 2051 | { 2052 | "alias": "VERIFY_EMAIL", 2053 | "name": "Verify Email", 2054 | "providerId": "VERIFY_EMAIL", 2055 | "enabled": true, 2056 | "defaultAction": false, 2057 | "priority": 50, 2058 | "config": {} 2059 | }, 2060 | { 2061 | "alias": "delete_account", 2062 | "name": "Delete Account", 2063 | "providerId": "delete_account", 2064 | "enabled": false, 2065 | "defaultAction": false, 2066 | "priority": 60, 2067 | "config": {} 2068 | }, 2069 | { 2070 | "alias": "update_user_locale", 2071 | "name": "Update User Locale", 2072 | "providerId": "update_user_locale", 2073 | "enabled": true, 2074 | "defaultAction": false, 2075 | "priority": 1000, 2076 | "config": {} 2077 | } 2078 | ], 2079 | "browserFlow": "browser", 2080 | "registrationFlow": "registration", 2081 | "directGrantFlow": "direct grant", 2082 | "resetCredentialsFlow": "reset credentials", 2083 | "clientAuthenticationFlow": "clients", 2084 | "dockerAuthenticationFlow": "docker auth", 2085 | "attributes": { 2086 | "cibaBackchannelTokenDeliveryMode": "poll", 2087 | "cibaExpiresIn": "120", 2088 | "cibaAuthRequestedUserHint": "login_hint", 2089 | "oauth2DeviceCodeLifespan": "600", 2090 | "oauth2DevicePollingInterval": "5", 2091 | "parRequestUriLifespan": "60", 2092 | "cibaInterval": "5" 2093 | }, 2094 | "keycloakVersion": "16.1.1", 2095 | "userManagedAccessAllowed": false, 2096 | "clientProfiles": { 2097 | "profiles": [] 2098 | }, 2099 | "clientPolicies": { 2100 | "policies": [] 2101 | } 2102 | } -------------------------------------------------------------------------------- /src/test/java/com/example/springbootkeycloakadminapi/ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.springbootkeycloakadminapi; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | --------------------------------------------------------------------------------