CINXE.COM

Server Administration Guide

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]--> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="generator" content="Asciidoctor 1.5.8"> <title>Server Administration Guide</title> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700"> <style> /* Asciidoctor default stylesheet | MIT License | http://asciidoctor.org */ /* Uncomment @import statement below to use as custom stylesheet */ /*@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700";*/ article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block} audio,canvas,video{display:inline-block} audio:not([controls]){display:none;height:0} script{display:none!important} html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%} a{background:transparent} a:focus{outline:thin dotted} a:active,a:hover{outline:0} h1{font-size:2em;margin:.67em 0} abbr[title]{border-bottom:1px dotted} b,strong{font-weight:bold} dfn{font-style:italic} hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0} mark{background:#ff0;color:#000} code,kbd,pre,samp{font-family:monospace;font-size:1em} pre{white-space:pre-wrap} q{quotes:"\201C" "\201D" "\2018" "\2019"} small{font-size:80%} sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline} sup{top:-.5em} sub{bottom:-.25em} img{border:0} svg:not(:root){overflow:hidden} figure{margin:0} fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em} legend{border:0;padding:0} button,input,select,textarea{font-family:inherit;font-size:100%;margin:0} button,input{line-height:normal} button,select{text-transform:none} button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer} button[disabled],html input[disabled]{cursor:default} input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0} button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0} textarea{overflow:auto;vertical-align:top} table{border-collapse:collapse;border-spacing:0} *,*::before,*::after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box} html,body{font-size:100%} body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto;tab-size:4;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased} a:hover{cursor:pointer} img,object,embed{max-width:100%;height:auto} object,embed{height:100%} img{-ms-interpolation-mode:bicubic} .left{float:left!important} .right{float:right!important} .text-left{text-align:left!important} .text-right{text-align:right!important} .text-center{text-align:center!important} .text-justify{text-align:justify!important} .hide{display:none} img,object,svg{display:inline-block;vertical-align:middle} textarea{height:auto;min-height:50px} select{width:100%} .center{margin-left:auto;margin-right:auto} .stretch{width:100%} .subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em} div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0;direction:ltr} a{color:#2156a5;text-decoration:underline;line-height:inherit} a:hover,a:focus{color:#1d4b8f} a img{border:none} p{font-family:inherit;font-weight:400;font-size:1em;line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility} p aside{font-size:.875em;line-height:1.35;font-style:italic} h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em} h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0} h1{font-size:2.125em} h2{font-size:1.6875em} h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em} h4,h5{font-size:1.125em} h6{font-size:1em} hr{border:solid #dddddf;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0} em,i{font-style:italic;line-height:inherit} strong,b{font-weight:bold;line-height:inherit} small{font-size:60%;line-height:inherit} code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)} ul,ol,dl{font-size:1em;line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit} ul,ol{margin-left:1.5em} ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em} ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit} ul.square{list-style-type:square} ul.circle{list-style-type:circle} ul.disc{list-style-type:disc} ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0} dl dt{margin-bottom:.3125em;font-weight:bold} dl dd{margin-bottom:1.25em} abbr,acronym{text-transform:uppercase;font-size:90%;color:rgba(0,0,0,.8);border-bottom:1px dotted #ddd;cursor:help} abbr{text-transform:none} blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd} blockquote cite{display:block;font-size:.9375em;color:rgba(0,0,0,.6)} blockquote cite::before{content:"\2014 \0020"} blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,.6)} blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)} @media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2} h1{font-size:2.75em} h2{font-size:2.3125em} h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em} h4{font-size:1.4375em}} table{background:#fff;margin-bottom:1.25em;border:solid 1px #dedede} table thead,table tfoot{background:#f7f8f7} table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left} table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)} table tr.even,table tr.alt,table tr:nth-of-type(even){background:#f8f8f7} table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{display:table-cell;line-height:1.6} h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em} h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400} .clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table} .clearfix::after,.float-group::after{clear:both} *:not(pre)>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background-color:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed;word-wrap:break-word} *:not(pre)>code.nobreak{word-wrap:normal} *:not(pre)>code.nowrap{white-space:nowrap} pre,pre>code{line-height:1.45;color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;text-rendering:optimizeSpeed} em em{font-style:normal} strong strong{font-weight:400} .keyseq{color:rgba(51,51,51,.8)} kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background-color:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap} .keyseq kbd:first-child{margin-left:0} .keyseq kbd:last-child{margin-right:0} .menuseq,.menuref{color:#000} .menuseq b:not(.caret),.menuref{font-weight:inherit} .menuseq{word-spacing:-.02em} .menuseq b.caret{font-size:1.25em;line-height:.8} .menuseq i.caret{font-weight:bold;text-align:center;width:.45em} b.button::before,b.button::after{position:relative;top:-1px;font-weight:400} b.button::before{content:"[";padding:0 3px 0 2px} b.button::after{content:"]";padding:0 2px 0 3px} p a>code:hover{color:rgba(0,0,0,.9)} #header,#content,#footnotes,#footer{width:100%;margin-left:auto;margin-right:auto;margin-top:0;margin-bottom:0;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em} #header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table} #header::after,#content::after,#footnotes::after,#footer::after{clear:both} #content{margin-top:1.25em} #content::before{content:none} #header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0} #header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf} #header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px} #header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap} #header .details span:first-child{margin-left:-.125em} #header .details span.email a{color:rgba(0,0,0,.85)} #header .details br{display:none} #header .details br+span::before{content:"\00a0\2013\00a0"} #header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)} #header .details br+span#revremark::before{content:"\00a0|\00a0"} #header #revnumber{text-transform:capitalize} #header #revnumber::after{content:"\00a0"} #content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #dddddf;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem} #toc{border-bottom:1px solid #e7e7e9;padding-bottom:.5em} #toc>ul{margin-left:.125em} #toc ul.sectlevel0>li>a{font-style:italic} #toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0} #toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none} #toc li{line-height:1.3334;margin-top:.3334em} #toc a{text-decoration:none} #toc a:active{text-decoration:underline} #toctitle{color:#7a2518;font-size:1.2em} @media screen and (min-width:768px){#toctitle{font-size:1.375em} body.toc2{padding-left:15em;padding-right:0} #toc.toc2{margin-top:0!important;background-color:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto} #toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em} #toc.toc2>ul{font-size:.9em;margin-bottom:0} #toc.toc2 ul ul{margin-left:0;padding-left:1em} #toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em} body.toc2.toc-right{padding-left:0;padding-right:15em} body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #e7e7e9;left:auto;right:0}} @media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0} #toc.toc2{width:20em} #toc.toc2 #toctitle{font-size:1.375em} #toc.toc2>ul{font-size:.95em} #toc.toc2 ul ul{padding-left:1.25em} body.toc2.toc-right{padding-left:0;padding-right:20em}} #content #toc{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px} #content #toc>:first-child{margin-top:0} #content #toc>:last-child{margin-bottom:0} #footer{max-width:100%;background-color:rgba(0,0,0,.8);padding:1.25em} #footer-text{color:rgba(255,255,255,.8);line-height:1.44} #content{margin-bottom:.625em} .sect1{padding-bottom:.625em} @media screen and (min-width:768px){#content{margin-bottom:1.25em} .sect1{padding-bottom:1.25em}} .sect1:last-child{padding-bottom:0} .sect1+.sect1{border-top:1px solid #e7e7e9} #content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400} #content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em} #content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible} #content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none} #content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221} .audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em} .admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic} table.tableblock.fit-content>caption.title{white-space:nowrap;width:0} .paragraph.lead>p,#preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)} table.tableblock #preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:inherit} .admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%} .admonitionblock>table td.icon{text-align:center;width:80px} .admonitionblock>table td.icon img{max-width:none} .admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase} .admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #dddddf;color:rgba(0,0,0,.6)} .admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0} .exampleblock>.content{border-style:solid;border-width:1px;border-color:#e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;-webkit-border-radius:4px;border-radius:4px} .exampleblock>.content>:first-child{margin-top:0} .exampleblock>.content>:last-child{margin-bottom:0} .sidebarblock{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px} .sidebarblock>:first-child{margin-top:0} .sidebarblock>:last-child{margin-bottom:0} .sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center} .exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0} .literalblock pre,.listingblock pre:not(.highlight),.listingblock pre[class="highlight"],.listingblock pre[class^="highlight "],.listingblock pre.CodeRay,.listingblock pre.prettyprint{background:#f7f7f8} .sidebarblock .literalblock pre,.sidebarblock .listingblock pre:not(.highlight),.sidebarblock .listingblock pre[class="highlight"],.sidebarblock .listingblock pre[class^="highlight "],.sidebarblock .listingblock pre.CodeRay,.sidebarblock .listingblock pre.prettyprint{background:#f2f1f1} .literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{-webkit-border-radius:4px;border-radius:4px;word-wrap:break-word;overflow-x:auto;padding:1em;font-size:.8125em} @media screen and (min-width:768px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:.90625em}} @media screen and (min-width:1280px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:1em}} .literalblock pre.nowrap,.literalblock pre.nowrap pre,.listingblock pre.nowrap,.listingblock pre.nowrap pre{white-space:pre;word-wrap:normal} .literalblock.output pre{color:#f7f7f8;background-color:rgba(0,0,0,.9)} .listingblock pre.highlightjs{padding:0} .listingblock pre.highlightjs>code{padding:1em;-webkit-border-radius:4px;border-radius:4px} .listingblock pre.prettyprint{border-width:0} .listingblock>.content{position:relative} .listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:#999} .listingblock:hover code[data-lang]::before{display:block} .listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:#999} .listingblock.terminal pre .command:not([data-prompt])::before{content:"$"} table.pyhltable{border-collapse:separate;border:0;margin-bottom:0;background:none} table.pyhltable td{vertical-align:top;padding-top:0;padding-bottom:0;line-height:1.45} table.pyhltable td.code{padding-left:.75em;padding-right:0} pre.pygments .lineno,table.pyhltable td:not(.code){color:#999;padding-left:0;padding-right:.5em;border-right:1px solid #dddddf} pre.pygments .lineno{display:inline-block;margin-right:.25em} table.pyhltable .linenodiv{background:none!important;padding-right:0!important} .quoteblock{margin:0 1em 1.25em 1.5em;display:table} .quoteblock>.title{margin-left:-1.5em;margin-bottom:.75em} .quoteblock blockquote,.quoteblock p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify} .quoteblock blockquote{margin:0;padding:0;border:0} .quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)} .quoteblock blockquote>.paragraph:last-child p{margin-bottom:0} .quoteblock .attribution{margin-top:.75em;margin-right:.5ex;text-align:right} .verseblock{margin:0 1em 1.25em} .verseblock pre{font-family:"Open Sans","DejaVu Sans",sans;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility} .verseblock pre strong{font-weight:400} .verseblock .attribution{margin-top:1.25rem;margin-left:.5ex} .quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic} .quoteblock .attribution br,.verseblock .attribution br{display:none} .quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)} .quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none} .quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:1.6;word-spacing:0} .quoteblock.abstract{margin:0 1em 1.25em;display:block} .quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center} .quoteblock.excerpt,.quoteblock .quoteblock{margin:0 0 1.25em;padding:0 0 .25em 1em;border-left:.25em solid #dddddf} .quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:1.0625rem} .quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;text-align:left;margin-right:0} table.tableblock{max-width:100%;border-collapse:separate} p.tableblock:last-child{margin-bottom:0} td.tableblock>.content{margin-bottom:-1.25em} table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede} table.grid-all>thead>tr>.tableblock,table.grid-all>tbody>tr>.tableblock{border-width:0 1px 1px 0} table.grid-all>tfoot>tr>.tableblock{border-width:1px 1px 0 0} table.grid-cols>*>tr>.tableblock{border-width:0 1px 0 0} table.grid-rows>thead>tr>.tableblock,table.grid-rows>tbody>tr>.tableblock{border-width:0 0 1px} table.grid-rows>tfoot>tr>.tableblock{border-width:1px 0 0} table.grid-all>*>tr>.tableblock:last-child,table.grid-cols>*>tr>.tableblock:last-child{border-right-width:0} table.grid-all>tbody>tr:last-child>.tableblock,table.grid-all>thead:last-child>tr>.tableblock,table.grid-rows>tbody>tr:last-child>.tableblock,table.grid-rows>thead:last-child>tr>.tableblock{border-bottom-width:0} table.frame-all{border-width:1px} table.frame-sides{border-width:0 1px} table.frame-topbot,table.frame-ends{border-width:1px 0} table.stripes-all tr,table.stripes-odd tr:nth-of-type(odd){background:#f8f8f7} table.stripes-none tr,table.stripes-odd tr:nth-of-type(even){background:none} th.halign-left,td.halign-left{text-align:left} th.halign-right,td.halign-right{text-align:right} th.halign-center,td.halign-center{text-align:center} th.valign-top,td.valign-top{vertical-align:top} th.valign-bottom,td.valign-bottom{vertical-align:bottom} th.valign-middle,td.valign-middle{vertical-align:middle} table thead th,table tfoot th{font-weight:bold} tbody tr th{display:table-cell;line-height:1.6;background:#f7f8f7} tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold} p.tableblock>code:only-child{background:none;padding:0} p.tableblock{font-size:1em} td>div.verse{white-space:pre} ol{margin-left:1.75em} ul li ol{margin-left:1.5em} dl dd{margin-left:1.125em} dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0} ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em} ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none} ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em} ul.unstyled,ol.unstyled{margin-left:0} ul.checklist{margin-left:.625em} ul.checklist li>p:first-child>.fa-square-o:first-child,ul.checklist li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em} ul.checklist li>p:first-child>input[type="checkbox"]:first-child{margin-right:.25em} ul.inline{display:-ms-flexbox;display:-webkit-box;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em} ul.inline>li{margin-left:1.25em} .unstyled dl dt{font-weight:400;font-style:normal} ol.arabic{list-style-type:decimal} ol.decimal{list-style-type:decimal-leading-zero} ol.loweralpha{list-style-type:lower-alpha} ol.upperalpha{list-style-type:upper-alpha} ol.lowerroman{list-style-type:lower-roman} ol.upperroman{list-style-type:upper-roman} ol.lowergreek{list-style-type:lower-greek} .hdlist>table,.colist>table{border:0;background:none} .hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none} td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em} td.hdlist1{font-weight:bold;padding-bottom:1.25em} .literalblock+.colist,.listingblock+.colist{margin-top:-.5em} .colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top} .colist td:not([class]):first-child img{max-width:none} .colist td:not([class]):last-child{padding:.25em 0} .thumb,.th{line-height:0;display:inline-block;border:solid 4px #fff;-webkit-box-shadow:0 0 0 1px #ddd;box-shadow:0 0 0 1px #ddd} .imageblock.left{margin:.25em .625em 1.25em 0} .imageblock.right{margin:.25em 0 1.25em .625em} .imageblock>.title{margin-bottom:0} .imageblock.thumb,.imageblock.th{border-width:6px} .imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em} .image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0} .image.left{margin-right:.625em} .image.right{margin-left:.625em} a.image{text-decoration:none;display:inline-block} a.image object{pointer-events:none} sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super} sup.footnote a,sup.footnoteref a{text-decoration:none} sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline} #footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em} #footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0} #footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em} #footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em} #footnotes .footnote:last-of-type{margin-bottom:0} #content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0} .gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0} .gist .file-data>table td.line-data{width:99%} div.unbreakable{page-break-inside:avoid} .big{font-size:larger} .small{font-size:smaller} .underline{text-decoration:underline} .overline{text-decoration:overline} .line-through{text-decoration:line-through} .aqua{color:#00bfbf} .aqua-background{background-color:#00fafa} .black{color:#000} .black-background{background-color:#000} .blue{color:#0000bf} .blue-background{background-color:#0000fa} .fuchsia{color:#bf00bf} .fuchsia-background{background-color:#fa00fa} .gray{color:#606060} .gray-background{background-color:#7d7d7d} .green{color:#006000} .green-background{background-color:#007d00} .lime{color:#00bf00} .lime-background{background-color:#00fa00} .maroon{color:#600000} .maroon-background{background-color:#7d0000} .navy{color:#000060} .navy-background{background-color:#00007d} .olive{color:#606000} .olive-background{background-color:#7d7d00} .purple{color:#600060} .purple-background{background-color:#7d007d} .red{color:#bf0000} .red-background{background-color:#fa0000} .silver{color:#909090} .silver-background{background-color:#bcbcbc} .teal{color:#006060} .teal-background{background-color:#007d7d} .white{color:#bfbfbf} .white-background{background-color:#fafafa} .yellow{color:#bfbf00} .yellow-background{background-color:#fafa00} span.icon>.fa{cursor:default} a span.icon>.fa{cursor:inherit} .admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default} .admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c} .admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111} .admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900} .admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400} .admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000} .conum[data-value]{display:inline-block;color:#fff!important;background-color:rgba(0,0,0,.8);-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold} .conum[data-value] *{color:#fff!important} .conum[data-value]+b{display:none} .conum[data-value]::after{content:attr(data-value)} pre .conum[data-value]{position:relative;top:-.125em} b.conum *{color:inherit!important} .conum:not([data-value]):empty{display:none} dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility} h1,h2,p,td.content,span.alt{letter-spacing:-.01em} p strong,td.content strong,div.footnote strong{letter-spacing:-.005em} p,blockquote,dt,td.content,span.alt{font-size:1.0625rem} p{margin-bottom:1.25rem} .sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em} .exampleblock>.content{background-color:#fffef7;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc} .print-only{display:none!important} @page{margin:1.25cm .75cm} @media print{*{-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important} html{font-size:80%} a{color:inherit!important;text-decoration:underline!important} a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important} a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em} abbr[title]::after{content:" (" attr(title) ")"} pre,blockquote,tr,img,object,svg{page-break-inside:avoid} thead{display:table-header-group} svg{max-width:100%} p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3} h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid} #toc,.sidebarblock,.exampleblock>.content{background:none!important} #toc{border-bottom:1px solid #dddddf!important;padding-bottom:0!important} body.book #header{text-align:center} body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em} body.book #header .details{border:0!important;display:block;padding:0!important} body.book #header .details span:first-child{margin-left:0!important} body.book #header .details br{display:block} body.book #header .details br+span::before{content:none!important} body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important} body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always} .listingblock code[data-lang]::before{display:block} #footer{padding:0 .9375em} .hide-on-print{display:none!important} .print-only{display:block!important} .hide-for-print{display:none!important} .show-for-print{display:inherit!important}} @media print,amzn-kf8{#header>h1:first-child{margin-top:1.25rem} .sect1{padding:0!important} .sect1+.sect1{border:0} #footer{background:none} #footer-text{color:rgba(0,0,0,.6);font-size:.9em}} @media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}} </style> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> <style> /* Stylesheet for CodeRay to match GitHub theme | MIT License | http://foundation.zurb.com */ /*pre.CodeRay {background-color:#f7f7f8;}*/ .CodeRay .line-numbers{border-right:1px solid #d8d8d8;padding:0 0.5em 0 .25em} .CodeRay span.line-numbers{display:inline-block;margin-right:.5em;color:rgba(0,0,0,.3)} .CodeRay .line-numbers strong{color:rgba(0,0,0,.4)} table.CodeRay{border-collapse:separate;border-spacing:0;margin-bottom:0;border:0;background:none} table.CodeRay td{vertical-align: top;line-height:1.45} table.CodeRay td.line-numbers{text-align:right} table.CodeRay td.line-numbers>pre{padding:0;color:rgba(0,0,0,.3)} table.CodeRay td.code{padding:0 0 0 .5em} table.CodeRay td.code>pre{padding:0} .CodeRay .debug{color:#fff !important;background:#000080 !important} .CodeRay .annotation{color:#007} .CodeRay .attribute-name{color:#000080} .CodeRay .attribute-value{color:#700} .CodeRay .binary{color:#509} .CodeRay .comment{color:#998;font-style:italic} .CodeRay .char{color:#04d} .CodeRay .char .content{color:#04d} .CodeRay .char .delimiter{color:#039} .CodeRay .class{color:#458;font-weight:bold} .CodeRay .complex{color:#a08} .CodeRay .constant,.CodeRay .predefined-constant{color:#008080} .CodeRay .color{color:#099} .CodeRay .class-variable{color:#369} .CodeRay .decorator{color:#b0b} .CodeRay .definition{color:#099} .CodeRay .delimiter{color:#000} .CodeRay .doc{color:#970} .CodeRay .doctype{color:#34b} .CodeRay .doc-string{color:#d42} .CodeRay .escape{color:#666} .CodeRay .entity{color:#800} .CodeRay .error{color:#808} .CodeRay .exception{color:inherit} .CodeRay .filename{color:#099} .CodeRay .function{color:#900;font-weight:bold} .CodeRay .global-variable{color:#008080} .CodeRay .hex{color:#058} .CodeRay .integer,.CodeRay .float{color:#099} .CodeRay .include{color:#555} .CodeRay .inline{color:#000} .CodeRay .inline .inline{background:#ccc} .CodeRay .inline .inline .inline{background:#bbb} .CodeRay .inline .inline-delimiter{color:#d14} .CodeRay .inline-delimiter{color:#d14} .CodeRay .important{color:#555;font-weight:bold} .CodeRay .interpreted{color:#b2b} .CodeRay .instance-variable{color:#008080} .CodeRay .label{color:#970} .CodeRay .local-variable{color:#963} .CodeRay .octal{color:#40e} .CodeRay .predefined{color:#369} .CodeRay .preprocessor{color:#579} .CodeRay .pseudo-class{color:#555} .CodeRay .directive{font-weight:bold} .CodeRay .type{font-weight:bold} .CodeRay .predefined-type{color:inherit} .CodeRay .reserved,.CodeRay .keyword {color:#000;font-weight:bold} .CodeRay .key{color:#808} .CodeRay .key .delimiter{color:#606} .CodeRay .key .char{color:#80f} .CodeRay .value{color:#088} .CodeRay .regexp .delimiter{color:#808} .CodeRay .regexp .content{color:#808} .CodeRay .regexp .modifier{color:#808} .CodeRay .regexp .char{color:#d14} .CodeRay .regexp .function{color:#404;font-weight:bold} .CodeRay .string{color:#d20} .CodeRay .string .string .string{background:#ffd0d0} .CodeRay .string .content{color:#d14} .CodeRay .string .char{color:#d14} .CodeRay .string .delimiter{color:#d14} .CodeRay .shell{color:#d14} .CodeRay .shell .delimiter{color:#d14} .CodeRay .symbol{color:#990073} .CodeRay .symbol .content{color:#a60} .CodeRay .symbol .delimiter{color:#630} .CodeRay .tag{color:#008080} .CodeRay .tag-special{color:#d70} .CodeRay .variable{color:#036} .CodeRay .insert{background:#afa} .CodeRay .delete{background:#faa} .CodeRay .change{color:#aaf;background:#007} .CodeRay .head{color:#f8f;background:#505} .CodeRay .insert .insert{color:#080} .CodeRay .delete .delete{color:#800} .CodeRay .change .change{color:#66f} .CodeRay .head .head{color:#f4f} </style> <style> /* Top menu */ @media only screen and (min-width: 768px) { div.top-menu-guides { position: fixed; display: inline-block; top: 0; left: 0; z-index: 9999; } div.top-menu-guides p { margin: 0; padding: 0; } div.top-menu-guides .content { margin: 0; padding: 7px 20px 0 20px; background-color: #ededed; height: 48px; width: 20em; } @media only screen and (max-width: 1280px) { div.top-menu-guides .content { width: 15em; } } div.top-menu-guides .ulist { display: none; position: absolute; background-color: #f9f9f9; min-width: 160px; box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); padding: 0px; margin-top: 12px; } div.top-menu-guides .ulist ul { list-style: none; padding: 5px; margin: 0; } div.top-menu-guides .ulist li { padding: 5px 10px; } div.top-menu-guides:hover .ulist { display: block; } div.top-menu-version { position: fixed; top: 0; z-index: 9999; } div.top-menu-version .content { padding: 0; margin: 0; background-color: #eee; height: 48px; padding: 7px; } div.top-menu-version p { margin: 0; padding: 2px 5px 2px 10px; } } /* TOC */ #tocbot a.toc-link.node-name--H1{ font-style: italic } @media screen{ #tocbot > ul.toc-list{ margin-bottom: 0.5em; margin-left: 0.125em } #tocbot ul.sectlevel0, #tocbot a.toc-link.node-name--H1 + ul{ padding-left: 0 } #tocbot a.toc-link{ height:100% } .is-collapsible{ max-height:3000px; overflow:hidden; } .is-collapsed{ max-height:0 } .is-active-link{ font-weight:700 } } @media print{ #tocbot a.toc-link.node-name--H4{ display:none } } /* Fix scroll to anchor hides title */ h1::before, h2::before, h3::before, h4::before, h5::before, h6::before { display: block; content: " "; height: 70px; margin-top: -70px; } h1 { border-bottom: none !important } #toc.toc2 { top: 30px; bottom: 0px; height: unset; } body.toc2 { padding-top: 30px; } @media only screen and (min-width:768px) { #toc.toc2 { top: 40px; } body.toc2 { padding-top: 40px; } } @media only screen and (min-width:1280px) { #toc.toc2 { top: 48px; } body.toc2 { padding-top: 48px; } } /* General Changes */ h1, h2, h3, #toctitle, .sidebarblock>.content>.title, h4, h5, h6 { color: #444444; font-weight: 500; } a { color: #004670; text-decoration: none; } a:hover { color: #7da1dc; } body { font-family: "Open Sans","DejaVu Sans",sans-serif; color: #444444; } .subheader, .admonitionblock td.content>.title, .audioblock>.title, .exampleblock>.title, .imageblock>.title, .listingblock>.title, .literalblock>.title, .stemblock>.title, .openblock>.title, .paragraph>.title, .quoteblock>.title, table.tableblock>.title, .verseblock>.title, .videoblock>.title, .dlist>.title, .olist>.title, .ulist>.title, .qlist>.title, .hdlist>.title { color: #444444; } .admonitionblock td.content>.title, .audioblock>.title, .exampleblock>.title, .imageblock>.title, .listingblock>.title, .literalblock>.title, .stemblock>.title, .openblock>.title, .paragraph>.title, .quoteblock>.title, table.tableblock>.title, .verseblock>.title, .videoblock>.title, .dlist>.title, .olist>.title, .ulist>.title, .qlist>.title, .hdlist>.title { font-family: "Open Sans","DejaVu Sans",sans-serif; font-style: normal; } span.image img { border:1px solid #ccc; -webkit-box-shadow: 3px 3px 15px 0px rgba(0,0,0,0.5); -moz-box-shadow: 3px 3px 15px 0px rgba(0,0,0,0.5); box-shadow: 3px 3px 15px 0px rgba(0,0,0,0.5); } .sect1+.sect1 { border-top: none; } .page-links { border-bottom: 1px solid #efefed; border-top: none; background: none; position: relative; left: 0em; width: 100%; top: -5em; height: 0; margin: 0; padding: 0; } .sect2 .page-links { top: -3.5em; } .page-links .content { background: #f8f8f7; border: 1px solid #e0e0dc; float: right; font-size: 0.8em; margin: 0; padding: 5px; } .page-links a { display: block; padding: 5px; } </style> </head> <body class="article toc2 toc-left"> <div id="header"> <h1>Server Administration Guide</h1> <div id="toc" class="toc2"> <div id="toctitle">Table of Contents</div> <ul class="sectlevel1"> <li><a href="#keycloak-features-and-concepts">Keycloak features and concepts</a> <ul class="sectlevel2"> <li><a href="#features">Features</a></li> <li><a href="#basic-keycloak-operations">Basic Keycloak operations</a></li> <li><a href="#core-concepts-and-terms">Core concepts and terms</a></li> </ul> </li> <li><a href="#creating-first-admin_server_administration_guide">Creating the first administrator</a> <ul class="sectlevel2"> <li><a href="#creating-the-account-on-the-local-host">Creating the account on the local host</a></li> <li><a href="#creating-the-account-remotely">Creating the account remotely</a></li> </ul> </li> <li><a href="#_configuring-realms">Configuring realms</a> <ul class="sectlevel2"> <li><a href="#using-the-admin-console">Using the Admin Console</a></li> <li><a href="#the-master-realm">The master realm</a></li> <li><a href="#proc-creating-a-realm_server_administration_guide">Creating a realm</a></li> <li><a href="#_ssl_modes">Configuring SSL for a realm</a></li> <li><a href="#_email">Configuring email for a realm</a></li> <li><a href="#_themes">Configuring themes</a></li> <li><a href="#enabling-internationalization">Enabling internationalization</a> <ul class="sectlevel3"> <li><a href="#_user_locale_selection">User locale selection</a></li> </ul> </li> <li><a href="#controlling-login-options">Controlling login options</a> <ul class="sectlevel3"> <li><a href="#enabling-forgot-password">Enabling forgot password</a></li> <li><a href="#enabling-remember-me">Enabling Remember Me</a></li> <li><a href="#_mapping-acr-to-loa-realm">ACR to Level of Authentication (LoA) Mapping</a></li> <li><a href="#_update-email-workflow">Update Email Workflow (UpdateEmail)</a></li> </ul> </li> <li><a href="#realm_keys">Configuring realm keys</a> <ul class="sectlevel3"> <li><a href="#rotating-keys">Rotating keys</a></li> <li><a href="#adding-a-generated-key-pair">Adding a generated key pair</a></li> <li><a href="#rotating-keys-by-extracting-a-certificate">Rotating keys by extracting a certificate</a></li> <li><a href="#adding-an-existing-key-pair-and-certificate">Adding an existing key pair and certificate</a></li> <li><a href="#loading-keys-from-a-java-keystore">Loading keys from a Java Keystore</a></li> <li><a href="#making-keys-passive">Making keys passive</a></li> <li><a href="#disabling-keys">Disabling keys</a></li> <li><a href="#compromised-keys">Compromised keys</a></li> </ul> </li> </ul> </li> <li><a href="#_user-storage-federation">Using external storage</a> <ul class="sectlevel2"> <li><a href="#adding-a-provider">Adding a provider</a></li> <li><a href="#dealing-with-provider-failures">Dealing with provider failures</a></li> <li><a href="#_ldap">Lightweight Directory Access Protocol (LDAP) and Active Directory</a> <ul class="sectlevel3"> <li><a href="#configuring-federated-ldap-storage">Configuring federated LDAP storage</a></li> <li><a href="#storage-mode">Storage mode</a></li> <li><a href="#edit-mode">Edit mode</a></li> <li><a href="#other-configuration-options">Other configuration options</a></li> <li><a href="#connecting-to-ldap-over-ssl">Connecting to LDAP over SSL</a></li> <li><a href="#synchronizing-ldap-users-to-keycloak">Synchronizing LDAP users to Keycloak</a></li> <li><a href="#_ldap_mappers">LDAP mappers</a></li> <li><a href="#_ldap_password_hashing">Password hashing</a></li> <li><a href="#_ldap_connection_pool">Configuring the connection pool</a></li> <li><a href="#_ldap_troubleshooting">Troubleshooting</a></li> </ul> </li> <li><a href="#_sssd">SSSD and FreeIPA Identity Management integration</a> <ul class="sectlevel3"> <li><a href="#freeipaidm-server">FreeIPA/IdM server</a></li> <li><a href="#sssd-and-d-bus">SSSD and D-Bus</a></li> <li><a href="#enabling-the-sssd-federation-provider">Enabling the SSSD federation provider</a></li> <li><a href="#configuring-a-federated-sssd-store">Configuring a federated SSSD store</a></li> </ul> </li> <li><a href="#custom-providers">Custom providers</a></li> </ul> </li> <li><a href="#assembly-managing-users_server_administration_guide">Managing users</a> <ul class="sectlevel2"> <li><a href="#proc-creating-user_server_administration_guide">Creating users</a></li> <li><a href="#user-profile">Managing user attributes</a> <ul class="sectlevel3"> <li><a href="#understanding-the-default-configuration">Understanding the Default Configuration</a></li> <li><a href="#understanding-the-user-profile-contexts">Understanding the User Profile Contexts</a></li> <li><a href="#_understanding-managed-and-unmanaged-attributes">Understanding Managed and Unmanaged Attributes</a></li> <li><a href="#managing-the-user-profile">Managing the User Profile</a></li> <li><a href="#managing-attributes">Managing Attributes</a></li> <li><a href="#_validating-attributes">Validating Attributes</a></li> <li><a href="#_defining-ui-annotations">Defining UI Annotations</a></li> <li><a href="#managing-attribute-groups">Managing Attribute Groups</a></li> <li><a href="#_user-profile-json-configuration">Using the JSON configuration</a></li> <li><a href="#customizing-how-uis-are-rendered">Customizing How UIs are Rendered</a></li> <li><a href="#enabling-progressive-profiling">Enabling Progressive Profiling</a></li> <li><a href="#_using-internationalized-messages">Using Internationalized Messages</a></li> </ul> </li> <li><a href="#ref-user-credentials_server_administration_guide">Defining user credentials</a> <ul class="sectlevel3"> <li><a href="#proc-setting-password-user_server_administration_guide">Setting a password for a user</a></li> <li><a href="#requesting-a-user-reset-a-password">Requesting a user reset a password</a></li> <li><a href="#proc_creating-otp_server_administration_guide">Creating an OTP</a></li> </ul> </li> <li><a href="#con-user-registration_server_administration_guide">Allowing users to self-register</a> <ul class="sectlevel3"> <li><a href="#proc-enabling-user-registration_server_administration_guide">Enabling user registration</a></li> <li><a href="#proc-registering-new-user_server_administration_guide">Registering as a new user</a></li> <li><a href="#proc-requiring-tac-agreement-at-registration_server_administration_guide">Requiring user to agree to terms and conditions during registration</a></li> </ul> </li> <li><a href="#con-required-actions_server_administration_guide">Defining actions required at login</a> <ul class="sectlevel3"> <li><a href="#proc-setting-required-actions_server_administration_guide">Setting required actions for one user</a></li> <li><a href="#proc-setting-default-required-actions_server_administration_guide">Setting required actions for all users</a></li> <li><a href="#proc-enabling-terms-conditions_server_administration_guide">Enabling terms and conditions as a required action</a></li> </ul> </li> <li><a href="#con-aia_server_administration_guide">Application initiated actions</a> <ul class="sectlevel3"> <li><a href="#con-aia-reauth_server_administration_guide">Re-authentication during AIA</a></li> <li><a href="#con-aia-parameterized_server_administration_guide">Parameterized AIA</a></li> <li><a href="#con-aia-available-actions_server_administration_guide">Available actions</a></li> </ul> </li> <li><a href="#proc-searching-user_server_administration_guide">Searching for a user</a> <ul class="sectlevel3"> <li><a href="#default-search">Default search</a></li> <li><a href="#attribute-search">Attribute search</a></li> </ul> </li> <li><a href="#proc-deleting-user_server_administration_guide">Deleting a user</a></li> <li><a href="#proc-allow-user-to-delete-account_server_administration_guide">Enabling account deletion by users</a> <ul class="sectlevel3"> <li><a href="#enabling-the-delete-account-capability">Enabling the Delete Account Capability</a></li> <li><a href="#giving-a-user-the-delete-account-role">Giving a user the <strong>delete-account</strong> role</a></li> <li><a href="#deleting-your-account">Deleting your account</a></li> </ul> </li> <li><a href="#con-user-impersonation_server_administration_guide">Impersonating a user</a></li> <li><a href="#proc-enabling-recaptcha_server_administration_guide">Enabling reCAPTCHA</a> <ul class="sectlevel3"> <li><a href="#procedure_recaptcha">Setting up Google reCAPTCHA</a></li> <li><a href="#procedure_recaptcha_enterprise">Setting up Google reCAPTCHA Enterprise</a></li> </ul> </li> <li><a href="#ref-personal-data-collected_server_administration_guide">Personal data collected by Keycloak</a></li> </ul> </li> <li><a href="#managing-user-sessions">Managing user sessions</a> <ul class="sectlevel2"> <li><a href="#administering-sessions">Administering sessions</a> <ul class="sectlevel3"> <li><a href="#signing-out-all-active-sessions">Signing out all active sessions</a></li> <li><a href="#viewing-client-sessions">Viewing client sessions</a></li> <li><a href="#viewing-user-sessions">Viewing user sessions</a></li> </ul> </li> <li><a href="#_revocation-policy">Revoking active sessions</a></li> <li><a href="#_timeouts">Session and token timeouts</a></li> <li><a href="#_offline-access">Offline access</a></li> <li><a href="#_transient-session">Transient sessions</a></li> </ul> </li> <li><a href="#assigning-permissions-using-roles-and-groups">Assigning permissions using roles and groups</a> <ul class="sectlevel2"> <li><a href="#proc-creating-realm-roles_server_administration_guide">Creating a realm role</a></li> <li><a href="#con-client-roles_server_administration_guide">Client roles</a></li> <li><a href="#_composite-roles">Converting a role to a composite role</a></li> <li><a href="#proc-assigning-role-mappings_server_administration_guide">Assigning role mappings</a></li> <li><a href="#_default_roles">Using default roles</a></li> <li><a href="#_role_scope_mappings">Role scope mappings</a></li> <li><a href="#proc-managing-groups_server_administration_guide">Groups</a> <ul class="sectlevel3"> <li><a href="#con-comparing-groups-roles_server_administration_guide">Groups compared to roles</a></li> <li><a href="#proc-specifying-default-groups_server_administration_guide">Using default groups</a></li> </ul> </li> </ul> </li> <li><a href="#configuring-authentication_server_administration_guide">Configuring authentication</a> <ul class="sectlevel2"> <li><a href="#_password-policies">Password policies</a> <ul class="sectlevel3"> <li><a href="#password-policy-types">Password policy types</a></li> </ul> </li> <li><a href="#one-time-password-otp-policies">One Time Password (OTP) policies</a> <ul class="sectlevel3"> <li><a href="#time-based-or-counter-based-one-time-passwords">Time-based or counter-based one time passwords</a></li> <li><a href="#totp-configuration-options">TOTP configuration options</a></li> <li><a href="#hotp-configuration-options">HOTP configuration options</a></li> </ul> </li> <li><a href="#_authentication-flows">Authentication flows</a> <ul class="sectlevel3"> <li><a href="#built-in-flows">Built-in flows</a></li> <li><a href="#creating-flows">Creating flows</a></li> <li><a href="#creating-a-password-less-browser-login-flow">Creating a password-less browser login flow</a></li> <li><a href="#_step-up-flow">Creating a browser login flow with step-up mechanism</a></li> <li><a href="#_registration-rc-client-flows">Registration or Reset credentials requested by client</a></li> </ul> </li> <li><a href="#_user_session_limits">User session limits</a></li> <li><a href="#script-authenticator">Script Authenticator</a></li> <li><a href="#_kerberos">Kerberos</a> <ul class="sectlevel3"> <li><a href="#setup-of-kerberos-server">Setup of Kerberos server</a></li> <li><a href="#setup-and-configuration-of-keycloak-server">Setup and configuration of Keycloak server</a></li> <li><a href="#setup-and-configuration-of-client-machines">Setup and configuration of client machines</a></li> <li><a href="#example-setups">Example setups</a></li> <li><a href="#credential-delegation">Credential delegation</a></li> <li><a href="#cross-realm-trust">Cross-realm trust</a></li> <li><a href="#troubleshooting">Troubleshooting</a></li> </ul> </li> <li><a href="#_x509">X.509 client certificate user authentication</a> <ul class="sectlevel3"> <li><a href="#features-2">Features</a></li> <li><a href="#_browser_flow">Adding X.509 client certificate authentication to browser flows</a></li> <li><a href="#_x509-config">Configuring X.509 client certificate authentication</a></li> <li><a href="#adding-x-509-client-certificate-authentication-to-a-direct-grant-flow">Adding X.509 Client Certificate Authentication to a Direct Grant Flow</a></li> </ul> </li> <li><a href="#webauthn_server_administration_guide">W3C Web Authentication (WebAuthn)</a> <ul class="sectlevel3"> <li><a href="#setup">Setup</a></li> <li><a href="#_webauthn-authenticator-setup">Adding WebAuthn authentication to a browser flow</a></li> <li><a href="#authenticate-with-webauthn-authenticator">Authenticate with WebAuthn authenticator</a></li> <li><a href="#managing-webauthn-as-an-administrator">Managing WebAuthn as an administrator</a></li> <li><a href="#attestation-statement-verification">Attestation statement verification</a></li> <li><a href="#managing-webauthn-credentials-as-a-user">Managing WebAuthn credentials as a user</a></li> <li><a href="#_webauthn_passwordless">Passwordless WebAuthn together with Two-Factor</a></li> <li><a href="#_webauthn_loginless">LoginLess WebAuthn</a></li> </ul> </li> <li><a href="#passkeys_server_administration_guide">Passkeys</a> <ul class="sectlevel3"> <li><a href="#_passkeys-conditional-ui">Passkey Authentication with Conditional UI</a></li> </ul> </li> <li><a href="#_recovery-codes">Recovery Codes (RecoveryCodes)</a></li> <li><a href="#conditions-in-conditional-flows">Conditions in conditional flows</a> <ul class="sectlevel3"> <li><a href="#available-conditions">Available conditions</a></li> <li><a href="#explicitly-denyallow-access-in-conditional-flows">Explicitly deny/allow access in conditional flows</a></li> </ul> </li> <li><a href="#_authentication-sessions">Authentication sessions</a> <ul class="sectlevel3"> <li><a href="#authentication-in-more-browser-tabs">Authentication in more browser tabs</a></li> </ul> </li> </ul> </li> <li><a href="#_identity_broker">Integrating identity providers</a> <ul class="sectlevel2"> <li><a href="#_identity_broker_overview">Brokering overview</a></li> <li><a href="#default_identity_provider">Default Identity Provider</a></li> <li><a href="#_general-idp-config">General configuration</a></li> <li><a href="#social-identity-providers">Social Identity Providers</a> <ul class="sectlevel3"> <li><a href="#bitbucket">Bitbucket</a></li> <li><a href="#_facebook">Facebook</a></li> <li><a href="#_github">GitHub</a></li> <li><a href="#gitlab">GitLab</a></li> <li><a href="#_google">Google</a></li> <li><a href="#instagram">Instagram</a></li> <li><a href="#_linkedin">LinkedIn</a></li> <li><a href="#_microsoft">Microsoft</a></li> <li><a href="#openshift-3">OpenShift 3</a></li> <li><a href="#openshift-4">OpenShift 4</a></li> <li><a href="#paypal">PayPal</a></li> <li><a href="#_stackoverflow">Stack Overflow</a></li> <li><a href="#_twitter">Twitter</a></li> </ul> </li> <li><a href="#_identity_broker_oidc">OpenID Connect v1.0 identity providers</a></li> <li><a href="#saml-v2-0-identity-providers">SAML v2.0 Identity Providers</a> <ul class="sectlevel3"> <li><a href="#_identity_broker_saml_requested_authncontext">Requesting specific AuthnContexts</a></li> <li><a href="#_identity_broker_saml_sp_descriptor">SP Descriptor</a></li> <li><a href="#_identity_broker_saml_login_hint">Send subject in SAML requests</a></li> </ul> </li> <li><a href="#_client_suggested_idp">Client-suggested Identity Provider</a></li> <li><a href="#_mappers">Mapping claims and assertions</a></li> <li><a href="#available-user-session-data">Available user session data</a></li> <li><a href="#_identity_broker_first_login">First login flow</a> <ul class="sectlevel3"> <li><a href="#default-first-login-flow-authenticators">Default first login flow authenticators</a></li> <li><a href="#automatically-link-existing-first-login-flow">Automatically link existing first login flow</a></li> <li><a href="#_disabling_automatic_user_creation">Disabling automatic user creation</a></li> <li><a href="#_detect_existing_user_first_login_flow">Detect existing user first login flow</a></li> <li><a href="#_override_existing_broker_link">Override existing broker link</a></li> </ul> </li> <li><a href="#retrieving-external-idp-tokens">Retrieving external IDP tokens</a></li> <li><a href="#identity-broker-logout">Identity broker logout</a></li> </ul> </li> <li><a href="#sso-protocols">SSO protocols</a> <ul class="sectlevel2"> <li><a href="#con-oidc_server_administration_guide">OpenID Connect</a> <ul class="sectlevel3"> <li><a href="#con-oidc-auth-flows_server_administration_guide">OIDC auth flows</a></li> <li><a href="#_oidc-logout">OIDC Logout</a></li> <li><a href="#con-server-oidc-uri-endpoints_server_administration_guide">Keycloak server OIDC URI endpoints</a></li> </ul> </li> <li><a href="#_saml">SAML</a> <ul class="sectlevel3"> <li><a href="#con-saml-bindings_server_administration_guide">SAML bindings</a></li> <li><a href="#keycloak-server-saml-uri-endpoints">Keycloak Server SAML URI Endpoints</a></li> </ul> </li> <li><a href="#ref-saml-vs-oidc_server_administration_guide">OpenID Connect compared to SAML</a></li> <li><a href="#_docker">Docker registry v2 authentication</a> <ul class="sectlevel3"> <li><a href="#docker-authentication-flow">Docker authentication flow</a></li> <li><a href="#keycloak-docker-registry-v2-authentication-server-uri-endpoints">Keycloak Docker Registry v2 Authentication Server URI Endpoints</a></li> </ul> </li> </ul> </li> <li><a href="#_admin_permissions">Controlling access to the Admin Console</a> <ul class="sectlevel2"> <li><a href="#master-realm-access-control">Master realm access control</a> <ul class="sectlevel3"> <li><a href="#global-roles">Global roles</a></li> <li><a href="#realm-specific-roles">Realm specific roles</a></li> </ul> </li> <li><a href="#_per_realm_admin_permissions">Dedicated realm admin consoles</a></li> <li><a href="#_fine_grain_permissions">Fine grain admin permissions</a> <ul class="sectlevel3"> <li><a href="#managing-one-specific-client">Managing one specific client</a></li> <li><a href="#restrict-user-role-mapping">Restrict user role mapping</a></li> <li><a href="#full-list-of-permissions">Full list of permissions</a></li> </ul> </li> </ul> </li> <li><a href="#_managing_organizations">Managing organizations</a> <ul class="sectlevel2"> <li><a href="#_enabling_organization_">Enabling organizations in Keycloak</a></li> <li><a href="#managing-an-organization">Managing an organization</a> <ul class="sectlevel3"> <li><a href="#creating-an-organization">Creating an organization</a></li> <li><a href="#understanding-organization-domains">Understanding organization domains</a></li> <li><a href="#disabling-an-organization">Disabling an organization</a></li> <li><a href="#deleting-an-organization">Deleting an organization</a></li> </ul> </li> <li><a href="#_managing_attributes_">Managing attributes</a></li> <li><a href="#_managing_members_">Managing members</a> <ul class="sectlevel3"> <li><a href="#_managed_unmanaged_members_">Managed and unmanaged members</a></li> <li><a href="#adding-an-existing-realm-user-as-a-member">Adding an existing realm user as a member</a></li> <li><a href="#inviting-users">Inviting users</a></li> <li><a href="#_onboard_member_identity_provider_">Onboarding members using an Identity Provider</a></li> <li><a href="#removing-a-member">Removing a member</a></li> </ul> </li> <li><a href="#_managing_identity_provider_">Managing identity providers</a> <ul class="sectlevel3"> <li><a href="#linking-an-identity-provider-to-an-organization">Linking an identity provider to an organization</a></li> <li><a href="#editing-a-linked-identity-provider">Editing a linked identity provider</a></li> <li><a href="#unlinking-an-identity-provider-from-an-organization">Unlinking an identity provider from an organization</a></li> </ul> </li> <li><a href="#authenticating-members_server_administration_guide">Authenticating members</a> <ul class="sectlevel3"> <li><a href="#understanding-the-identity-first-login">Understanding the identity-first login</a></li> <li><a href="#configuring-existing-authentication-flows">Configuring existing authentication flows</a></li> </ul> </li> <li><a href="#mapping-organization-claims_server_administration_guide">Mapping organization claims</a></li> </ul> </li> <li><a href="#assembly-managing-clients_server_administration_guide">Managing OpenID Connect and SAML Clients</a> <ul class="sectlevel2"> <li><a href="#_oidc_clients">Managing OpenID Connect clients</a> <ul class="sectlevel3"> <li><a href="#proc-creating-oidc-client_server_administration_guide">Creating an OpenID Connect client</a></li> <li><a href="#con-basic-settings_server_administration_guide">Basic configuration</a></li> <li><a href="#con-advanced-settings_server_administration_guide">Advanced configuration</a></li> <li><a href="#_client-credentials">Confidential client credentials</a></li> <li><a href="#_secret_rotation">Client Secret Rotation</a></li> <li><a href="#_proc-secret-rotation">Creating an OIDC Client Secret Rotation Policy</a></li> <li><a href="#_service_accounts">Using a service account</a></li> <li><a href="#audience-support">Audience support</a></li> </ul> </li> <li><a href="#_client-saml-configuration">Creating a SAML client</a> <ul class="sectlevel3"> <li><a href="#settings-tab">Settings tab</a></li> <li><a href="#keys-tab">Keys tab</a></li> <li><a href="#advanced-tab-2">Advanced tab</a></li> <li><a href="#idp-initiated-login">IDP Initiated login</a></li> <li><a href="#proc-using-an-entity-descriptors_server_administration_guide">Using an entity descriptor to create a client</a></li> </ul> </li> <li><a href="#con-client-links_server_administration_guide">Client links</a></li> <li><a href="#_protocol-mappers">OIDC token and SAML assertion mappings</a> <ul class="sectlevel3"> <li><a href="#_protocol-mappers_priority">Priority order</a></li> <li><a href="#_protocol-mappers_oidc-user-session-note-mappers">OIDC user session note mappers</a></li> <li><a href="#script-mapper">Script mapper</a></li> <li><a href="#pairwise-subject-identifier-mapper">Pairwise subject identifier mapper</a></li> <li><a href="#_using_lightweight_access_token">Using lightweight access token</a></li> </ul> </li> <li><a href="#_client_installation">Generating client adapter config</a></li> <li><a href="#_client_scopes">Client scopes</a> <ul class="sectlevel3"> <li><a href="#protocol">Protocol</a></li> <li><a href="#consent-related-settings">Consent related settings</a></li> <li><a href="#_client_scopes_linking">Link client scope with the client</a></li> <li><a href="#_client_scopes_evaluate">Evaluating Client Scopes</a></li> <li><a href="#client-scopes-permissions">Client scopes permissions</a></li> <li><a href="#realm-default-client-scopes">Realm default client scopes</a></li> <li><a href="#scopes-explained">Scopes explained</a></li> </ul> </li> <li><a href="#_client_policies">Client Policies</a> <ul class="sectlevel3"> <li><a href="#use-cases">Use-cases</a></li> <li><a href="#protocol-2">Protocol</a></li> <li><a href="#architecture">Architecture</a></li> <li><a href="#configuration">Configuration</a></li> <li><a href="#backward-compatibility">Backward Compatibility</a></li> <li><a href="#client-secret-rotation-example">Client Secret Rotation Example</a></li> </ul> </li> </ul> </li> <li><a href="#_vault-administration">Using a vault to obtain secrets</a> <ul class="sectlevel2"> <li><a href="#_vault-key-resolvers">Key resolvers</a></li> </ul> </li> <li><a href="#configuring-auditing-to-track-events">Configuring auditing to track events</a> <ul class="sectlevel2"> <li><a href="#auditing-user-events">Auditing user events</a> <ul class="sectlevel3"> <li><a href="#event-types">Event types</a></li> <li><a href="#event-listener">Event listener</a></li> </ul> </li> <li><a href="#auditing-admin-events">Auditing admin events</a></li> </ul> </li> <li><a href="#mitigating_security_threats">Mitigating security threats</a> <ul class="sectlevel2"> <li><a href="#host">Host</a></li> <li><a href="#admin-endpoints-and-admin-console">Admin endpoints and Admin Console</a></li> <li><a href="#password-guess-brute-force-attacks">Brute force attacks</a> <ul class="sectlevel3"> <li><a href="#password-policies">Password policies</a></li> </ul> </li> <li><a href="#read_only_user_attributes">Read-only user attributes</a></li> <li><a href="#validate_user_attributes">Validate user attributes</a></li> <li><a href="#clickjacking">Clickjacking</a></li> <li><a href="#sslhttps-requirement">SSL/HTTPS requirement</a></li> <li><a href="#csrf-attacks">CSRF attacks</a></li> <li><a href="#unspecific-redirect-uris_server_administration_guide">Unspecific redirect URIs</a></li> <li><a href="#fapi-compliance">FAPI compliance</a></li> <li><a href="#oauth-2-1-compliance">OAuth 2.1 compliance</a></li> <li><a href="#compromised-access-and-refresh-tokens">Compromised access and refresh tokens</a></li> <li><a href="#compromised-authorization-code">Compromised authorization code</a></li> <li><a href="#open-redirectors">Open redirectors</a></li> <li><a href="#password-database-compromised">Password database compromised</a></li> <li><a href="#limiting-scope">Limiting scope</a></li> <li><a href="#limit-token-audience">Limit token audience</a></li> <li><a href="#_limit-authentication-sessions">Limit Authentication Sessions</a></li> <li><a href="#sql-injection-attacks">SQL injection attacks</a></li> </ul> </li> <li><a href="#_account-service">Account Console</a> <ul class="sectlevel2"> <li><a href="#accessing-the-account-console">Accessing the Account Console</a></li> <li><a href="#configuring-ways-to-sign-in">Configuring ways to sign in</a> <ul class="sectlevel3"> <li><a href="#two-factor-authentication-with-otp">Two-factor authentication with OTP</a></li> <li><a href="#two-factor-authentication-with-webauthn">Two-factor authentication with WebAuthn</a></li> <li><a href="#passwordless-authentication-with-webauthn">Passwordless authentication with WebAuthn</a></li> </ul> </li> <li><a href="#viewing-device-activity">Viewing device activity</a></li> <li><a href="#adding-an-identity-provider-account">Adding an identity provider account</a></li> <li><a href="#accessing-other-applications">Accessing other applications</a></li> <li><a href="#viewing-group-memberships">Viewing group memberships</a></li> </ul> </li> <li><a href="#admin-cli">Admin CLI</a> <ul class="sectlevel2"> <li><a href="#installing-the-admin-cli">Installing the Admin CLI</a></li> <li><a href="#using-the-admin-cli">Using the Admin CLI</a></li> <li><a href="#sensitive-options">Sensitive Options</a></li> <li><a href="#authenticating">Authenticating</a></li> <li><a href="#_working_with_alternative_configurations">Working with alternative configurations</a></li> <li><a href="#basic-operations-and-resource-uris">Basic operations and resource URIs</a></li> <li><a href="#realm-operations">Realm operations</a></li> <li><a href="#role-operations">Role operations</a></li> <li><a href="#client-operations">Client operations</a></li> <li><a href="#user-operations">User operations</a></li> <li><a href="#_group_operations">Group operations</a></li> <li><a href="#identity-provider-operations">Identity provider operations</a></li> <li><a href="#storage-provider-operations">Storage provider operations</a></li> <li><a href="#adding-mappers">Adding mappers</a></li> <li><a href="#authentication-operations">Authentication operations</a></li> </ul> </li> </ul> </div> </div> <div id="content"> <div id="preamble"> <div class="sectionbody"> <div class="exampleblock top-menu-guides"> <div class="content"> <div class="paragraph"> <p><strong>Server Administration</strong> <span class="icon"><i class="fa fa-angle-down"></i></span></p> </div> <div class="ulist"> <ul> <li> <p><a href="https://www.keycloak.org/guides#getting-started">Getting Started</a></p> </li> <li> <p><a href="https://www.keycloak.org/guides#securing-apps">Securing applications</a></p> </li> <li> <p><a href="https://www.keycloak.org/docs/26.0.6/server_development/">Server Developer</a></p> </li> <li> <p><a href="https://www.keycloak.org/docs/26.0.6/authorization_services/">Authorization Services</a></p> </li> <li> <p><a href="https://www.keycloak.org/docs/26.0.6/upgrading/">Upgrading</a></p> </li> <li> <p><a href="https://www.keycloak.org/docs/26.0.6/release_notes/">Release Notes</a></p> </li> </ul> </div> </div> </div> <div class="exampleblock top-menu-version"> <div class="content"> <div class="paragraph"> <p>Version <strong>26.0.6</strong></p> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="keycloak-features-and-concepts"><a class="anchor" href="#keycloak-features-and-concepts"></a>Keycloak features and concepts</h2> <div class="sectionbody"> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/overview.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/overview.adoc&amp;description=%0A%0AFile:%20server_admin/topics/overview.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Keycloak is a single sign on solution for web apps and RESTful web services. The goal of Keycloak is to make security simple so that it is easy for application developers to secure the apps and services they have deployed in their organization. Security features that developers normally have to write for themselves are provided out of the box and are easily tailorable to the individual requirements of your organization. Keycloak provides customizable user interfaces for login, registration, administration, and account management. You can also use Keycloak as an integration platform to hook it into existing LDAP and Active Directory servers. You can also delegate authentication to third party identity providers like Facebook and Google.</p> </div> <div class="sect2"> <h3 id="features"><a class="anchor" href="#features"></a>Features</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/overview/features.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/overview/features.adoc&amp;description=%0A%0AFile:%20server_admin/topics/overview/features.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Keycloak provides the following features:</p> </div> <div class="ulist"> <ul> <li> <p>Single-Sign On and Single-Sign Out for browser applications.</p> </li> <li> <p>OpenID Connect support.</p> </li> <li> <p>OAuth 2.0 support.</p> </li> <li> <p>SAML support.</p> </li> <li> <p>Identity Brokering - Authenticate with external OpenID Connect or SAML Identity Providers.</p> </li> <li> <p>Social Login - Enable login with Google, GitHub, Facebook, Twitter, and other social networks.</p> </li> <li> <p>User Federation - Sync users from LDAP and Active Directory servers.</p> </li> <li> <p>Kerberos bridge - Automatically authenticate users that are logged-in to a Kerberos server.</p> </li> <li> <p>Admin Console for central management of users, roles, role mappings, clients and configuration.</p> </li> <li> <p>Account Console that allows users to centrally manage their account.</p> </li> <li> <p>Theme support - Customize all user facing pages to integrate with your applications and branding.</p> </li> <li> <p>Two-factor Authentication - Support for TOTP/HOTP via Google Authenticator or FreeOTP.</p> </li> <li> <p>Login flows - optional user self-registration, recover password, verify email, require password update, etc.</p> </li> <li> <p>Session management - Admins and users themselves can view and manage user sessions.</p> </li> <li> <p>Token mappers - Map user attributes, roles, etc. how you want into tokens and statements.</p> </li> <li> <p>Not-before revocation policies per realm, application and user.</p> </li> <li> <p>CORS support - Client adapters have built-in support for CORS.</p> </li> <li> <p>Service Provider Interfaces (SPI) - A number of SPIs to enable customizing various aspects of the server. Authentication flows, user federation providers, protocol mappers and many more.</p> </li> <li> <p>Supports any platform/language that has an OpenID Connect Relying Party library or SAML 2.0 Service Provider library.</p> </li> </ul> </div> </div> <div class="sect2"> <h3 id="basic-keycloak-operations"><a class="anchor" href="#basic-keycloak-operations"></a>Basic Keycloak operations</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/overview/how.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/overview/how.adoc&amp;description=%0A%0AFile:%20server_admin/topics/overview/how.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Keycloak is a separate server that you manage on your network. Applications are configured to point to and be secured by this server. Keycloak uses open protocol standards like <a href="https://openid.net/developers/how-connect-works/">OpenID Connect</a> or <a href="https://saml.xml.org/saml-specifications">SAML 2.0</a> to secure your applications. Browser applications redirect a user&#8217;s browser from the application to the Keycloak authentication server where they enter their credentials. This redirection is important because users are completely isolated from applications and applications never see a user&#8217;s credentials. Applications instead are given an identity token or assertion that is cryptographically signed. These tokens can have identity information like username, address, email, and other profile data. They can also hold permission data so that applications can make authorization decisions. These tokens can also be used to make secure invocations on REST-based services.</p> </div> </div> <div class="sect2"> <h3 id="core-concepts-and-terms"><a class="anchor" href="#core-concepts-and-terms"></a>Core concepts and terms</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/overview/concepts.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/overview/concepts.adoc&amp;description=%0A%0AFile:%20server_admin/topics/overview/concepts.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Consider these core concepts and terms before attempting to use Keycloak to secure your web applications and REST services.</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">users</dt> <dd> <p>Users are entities that are able to log into your system. They can have attributes associated with themselves like email, username, address, phone number, and birthday. They can be assigned group membership and have specific roles assigned to them.</p> </dd> <dt class="hdlist1">authentication</dt> <dd> <p>The process of identifying and validating a user.</p> </dd> <dt class="hdlist1">authorization</dt> <dd> <p>The process of granting access to a user.</p> </dd> <dt class="hdlist1">credentials</dt> <dd> <p>Credentials are pieces of data that Keycloak uses to verify the identity of a user. Some examples are passwords, one-time-passwords, digital certificates, or even fingerprints.</p> </dd> <dt class="hdlist1">roles</dt> <dd> <p>Roles identify a type or category of user. <code>Admin</code>, <code>user</code>, <code>manager</code>, and <code>employee</code> are all typical roles that may exist in an organization. Applications often assign access and permissions to specific roles rather than individual users as dealing with users can be too fine-grained and hard to manage.</p> </dd> <dt class="hdlist1">user role mapping</dt> <dd> <p>A user role mapping defines a mapping between a role and a user. A user can be associated with zero or more roles. This role mapping information can be encapsulated into tokens and assertions so that applications can decide access permissions on various resources they manage.</p> </dd> <dt class="hdlist1">composite roles</dt> <dd> <p>A composite role is a role that can be associated with other roles. For example a <code>superuser</code> composite role could be associated with the <code>sales-admin</code> and <code>order-entry-admin</code> roles. If a user is mapped to the <code>superuser</code> role they also inherit the <code>sales-admin</code> and <code>order-entry-admin</code> roles.</p> </dd> <dt class="hdlist1">groups</dt> <dd> <p>Groups manage groups of users. Attributes can be defined for a group. You can map roles to a group as well. Users that become members of a group inherit the attributes and role mappings that group defines.</p> </dd> <dt class="hdlist1">realms</dt> <dd> <p>A realm manages a set of users, credentials, roles, and groups. A user belongs to and logs into a realm. Realms are isolated from one another and can only manage and authenticate the users that they control.</p> </dd> <dt class="hdlist1">clients</dt> <dd> <p>Clients are entities that can request Keycloak to authenticate a user. Most often, clients are applications and services that want to use Keycloak to secure themselves and provide a single sign-on solution. Clients can also be entities that just want to request identity information or an access token so that they can securely invoke other services on the network that are secured by Keycloak.</p> </dd> <dt class="hdlist1">client adapters</dt> <dd> <p>Client adapters are plugins that you install into your application environment to be able to communicate and be secured by Keycloak. Keycloak has a number of adapters for different platforms that you can download. There are also third-party adapters you can get for environments that we don&#8217;t cover.</p> </dd> <dt class="hdlist1">consent</dt> <dd> <p>Consent is when you as an admin want a user to give permission to a client before that client can participate in the authentication process. After a user provides their credentials, Keycloak will pop up a screen identifying the client requesting a login and what identity information is requested of the user. User can decide whether or not to grant the request.</p> </dd> <dt class="hdlist1">client scopes</dt> <dd> <p>When a client is registered, you must define protocol mappers and role scope mappings for that client. It is often useful to store a client scope, to make creating new clients easier by sharing some common settings. This is also useful for requesting some claims or roles to be conditionally based on the value of <code>scope</code> parameter. Keycloak provides the concept of a client scope for this.</p> </dd> <dt class="hdlist1">client role</dt> <dd> <p>Clients can define roles that are specific to them. This is basically a role namespace dedicated to the client.</p> </dd> <dt class="hdlist1">identity token</dt> <dd> <p>A token that provides identity information about the user. Part of the OpenID Connect specification.</p> </dd> <dt class="hdlist1">access token</dt> <dd> <p>A token that can be provided as part of an HTTP request that grants access to the service being invoked on. This is part of the OpenID Connect and OAuth 2.0 specification.</p> </dd> <dt class="hdlist1">assertion</dt> <dd> <p>Information about a user. This usually pertains to an XML blob that is included in a SAML authentication response that provided identity metadata about an authenticated user.</p> </dd> <dt class="hdlist1">service account</dt> <dd> <p>Each client has a built-in service account which allows it to obtain an access token.</p> </dd> <dt class="hdlist1">direct grant</dt> <dd> <p>A way for a client to obtain an access token on behalf of a user via a REST invocation.</p> </dd> <dt class="hdlist1">protocol mappers</dt> <dd> <p>For each client you can tailor what claims and assertions are stored in the OIDC token or SAML assertion. You do this per client by creating and configuring protocol mappers.</p> </dd> <dt class="hdlist1">session</dt> <dd> <p>When a user logs in, a session is created to manage the login session. A session contains information like when the user logged in and what applications have participated within single-sign on during that session. Both admins and users can view session information.</p> </dd> <dt class="hdlist1">user federation provider</dt> <dd> <p>Keycloak can store and manage users. Often, companies already have LDAP or Active Directory services that store user and credential information. You can point Keycloak to validate credentials from those external stores and pull in identity information.</p> </dd> <dt class="hdlist1">identity provider</dt> <dd> <p>An identity provider (IDP) is a service that can authenticate a user. Keycloak is an IDP.</p> </dd> <dt class="hdlist1">identity provider federation</dt> <dd> <p>Keycloak can be configured to delegate authentication to one or more IDPs. Social login via Facebook or Google is an example of identity provider federation. You can also hook Keycloak to delegate authentication to any other OpenID Connect or SAML 2.0 IDP.</p> </dd> <dt class="hdlist1">identity provider mappers</dt> <dd> <p>When doing IDP federation you can map incoming tokens and assertions to user and session attributes. This helps you propagate identity information from the external IDP to your client requesting authentication.</p> </dd> <dt class="hdlist1">required actions</dt> <dd> <p>Required actions are actions a user must perform during the authentication process. A user will not be able to complete the authentication process until these actions are complete. For example, an admin may schedule users to reset their passwords every month. An <code>update password</code> required action would be set for all these users.</p> </dd> <dt class="hdlist1">authentication flows</dt> <dd> <p>Authentication flows are work flows a user must perform when interacting with certain aspects of the system. A login flow can define what credential types are required. A registration flow defines what profile information a user must enter and whether something like reCAPTCHA must be used to filter out bots. Credential reset flow defines what actions a user must do before they can reset their password.</p> </dd> <dt class="hdlist1">events</dt> <dd> <p>Events are audit streams that admins can view and hook into.</p> </dd> <dt class="hdlist1">themes</dt> <dd> <p>Every screen provided by Keycloak is backed by a theme. Themes define HTML templates and stylesheets which you can override as needed.</p> </dd> </dl> </div> </div> </div> </div> <div class="sect1"> <h2 id="creating-first-admin_server_administration_guide"><a class="anchor" href="#creating-first-admin_server_administration_guide"></a>Creating the first administrator</h2> <div class="sectionbody"> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/assembly-creating-first-admin.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/assembly-creating-first-admin.adoc&amp;description=%0A%0AFile:%20server_admin/topics/assembly-creating-first-admin.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>After installing Keycloak, you need an administrator account that can act as a <em>super</em> admin with full permissions to manage Keycloak. With this account, you can log in to the Keycloak Admin Console where you create realms and users and register applications that are secured by Keycloak.</p> </div> <div class="sect2"> <h3 id="creating-the-account-on-the-local-host"><a class="anchor" href="#creating-the-account-on-the-local-host"></a>Creating the account on the local host</h3> <div class="paragraph"> <p>If your server is accessible from <code>localhost</code>, perform these steps.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>In a web browser, go to the <a href="http://localhost:8080" class="bare">http://localhost:8080</a> URL.</p> </li> <li> <p>Supply a username and password that you can recall.</p> <div class="paragraph"> <div class="title">Welcome page</div> <p><span class="image"><img src="./images/initial-welcome-page.png" alt="Welcome page"></span></p> </div> </li> </ol> </div> </div> <div class="sect2"> <h3 id="creating-the-account-remotely"><a class="anchor" href="#creating-the-account-remotely"></a>Creating the account remotely</h3> <div class="paragraph"> <p>If you cannot access the server from a <code>localhost</code> address or just want to start Keycloak from the command line, use the <code>KC_BOOTSTRAP_ADMIN_USERNAME</code> and <code>KC_BOOTSTRAP_ADMIN_PASSWORD</code> environment variables to create an initial admin account.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">export KC_BOOTSTRAP_ADMIN_USERNAME=&lt;username&gt; export KC_BOOTSTRAP_ADMIN_PASSWORD=&lt;password&gt; bin/kc.[sh|bat] start</code></pre> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="_configuring-realms"><a class="anchor" href="#_configuring-realms"></a>Configuring realms</h2> <div class="sectionbody"> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/admin-console.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/admin-console.adoc&amp;description=%0A%0AFile:%20server_admin/topics/admin-console.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Once you have an administrative account for the Admin Console, you can configure realms. A realm is a space where you manage objects, including users, applications, roles, and groups. A user belongs to and logs into a realm. One Keycloak deployment can define, store, and manage as many realms as there is space for in the database.</p> </div> <div class="sect2"> <h3 id="using-the-admin-console"><a class="anchor" href="#using-the-admin-console"></a>Using the Admin Console</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/realms/proc-using-admin-console.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/realms/proc-using-admin-console.adoc&amp;description=%0A%0AFile:%20server_admin/topics/realms/proc-using-admin-console.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>You configure realms and perform most administrative tasks in the Keycloak Admin Console.</p> </div> <div class="ulist"> <div class="title">Prerequisites</div> <ul> <li> <p>You need an administrator account. See <a href="#creating-first-admin_server_administration_guide">Creating the first administrator</a>.</p> </li> </ul> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Go to the URL for the Admin Console.</p> <div class="paragraph"> <p>For example, for localhost, use this URL: <a href="http://localhost:8080/admin/" class="bare">http://localhost:8080/admin/</a></p> </div> <div class="paragraph"> <div class="title">Login page</div> <p><span class="image"><img src="./images/login-page.png" alt="Login page"></span></p> </div> </li> <li> <p>Enter the username and password you created on the Welcome Page or through environment variables as per <a href="https://www.keycloak.org/server/configuration#_creating_the_initial_admin_user">Creating the initial admin user</a> guide. This action displays the Admin Console.</p> <div class="paragraph"> <div class="title">Admin Console</div> <p><span class="image"><img src="./images/admin-console.png" alt="Admin Console"></span></p> </div> </li> <li> <p>Note the menus and other options that you can use:</p> <div class="ulist"> <ul> <li> <p>Click the menu labeled <strong>Master</strong> to pick a realm you want to manage or to create a new one.</p> </li> <li> <p>Click the top right list to view your account or log out.</p> </li> <li> <p>Hover over a question mark <strong>?</strong> icon to show a tooltip text that describes that field. The image above shows the tooltip in action.</p> </li> <li> <p>Click a question mark <strong>?</strong> icon to show a tooltip text that describes that field. The image above shows the tooltip in action.</p> </li> </ul> </div> </li> </ol> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> Export files from the Admin Console are not suitable for backups or data transfer between servers. Only boot-time exports are suitable for backups or data transfer between servers. </td> </tr> </table> </div> </div> <div class="sect2"> <h3 id="the-master-realm"><a class="anchor" href="#the-master-realm"></a>The master realm</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/realms/master.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/realms/master.adoc&amp;description=%0A%0AFile:%20server_admin/topics/realms/master.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>In the Admin Console, two types of realms exist:</p> </div> <div class="ulist"> <ul> <li> <p><code>Master realm</code> - This realm was created for you when you first started Keycloak. It contains the administrator account you created at the first login. Use the <em>master</em> realm only to create and manage the realms in your system.</p> </li> <li> <p><code>Other realms</code> - These realms are created by the administrator in the master realm. In these realms, administrators manage the users in your organization and the applications they need. The applications are owned by the users.</p> </li> </ul> </div> <div class="paragraph"> <div class="title">Realms and applications</div> <p><span class="image"><img src="./images/master_realm.png" alt="Realms and applications"></span></p> </div> <div class="paragraph"> <p>Realms are isolated from one another and can only manage and authenticate the users that they control. Following this security model helps prevent accidental changes and follows the tradition of permitting user accounts access to only those privileges and powers necessary for the successful completion of their current task.</p> </div> <div class="ulist"> <div class="title">Additional resources</div> <ul> <li> <p>See <a href="#_per_realm_admin_permissions">Dedicated Realm Admin Consoles</a> if you want to disable the <em>master</em> realm and define administrator accounts within any new realm you create. Each realm has its own dedicated Admin Console that you can log into with local accounts.</p> </li> </ul> </div> </div> <div class="sect2"> <h3 id="proc-creating-a-realm_server_administration_guide"><a class="anchor" href="#proc-creating-a-realm_server_administration_guide"></a>Creating a realm</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/realms/proc-creating-a-realm.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/realms/proc-creating-a-realm.adoc&amp;description=%0A%0AFile:%20server_admin/topics/realms/proc-creating-a-realm.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>You create a realm to provide a management space where you can create users and give them permissions to use applications. At first login, you are typically in the <em>master</em> realm, the top-level realm from which you create other realms.</p> </div> <div class="paragraph"> <p>When deciding what realms you need, consider the kind of isolation you want to have for your users and applications. For example, you might create a realm for the employees of your company and a separate realm for your customers. Your employees would log into the employee realm and only be able to visit internal company applications. Customers would log into the customer realm and only be able to interact with customer-facing apps.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Keycloak</strong> next to <strong>master realm</strong>, then click <strong>Create Realm</strong>.</p> <div class="paragraph"> <div class="title">Add realm menu</div> <p><span class="image"><img src="./images/add-realm-menu.png" alt="Add realm menu"></span></p> </div> </li> <li> <p>Enter a name for the realm.</p> </li> <li> <p>Click <strong>Create</strong>.</p> <div class="paragraph"> <div class="title">Create realm</div> <p><span class="image"><img src="./images/create-realm.png" alt="Create realm"></span></p> </div> <div class="paragraph"> <p>The current realm is now set to the realm you just created. You can switch between realms by clicking the realm name in the menu.</p> </div> </li> </ol> </div> </div> <div class="sect2"> <h3 id="_ssl_modes"><a class="anchor" href="#_ssl_modes"></a>Configuring SSL for a realm</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/realms/ssl.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/realms/ssl.adoc&amp;description=%0A%0AFile:%20server_admin/topics/realms/ssl.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Each realm has an associated SSL Mode, which defines the SSL/HTTPS requirements for interacting with the realm. Browsers and applications that interact with the realm honor the SSL/HTTPS requirements defined by the SSL Mode or they cannot interact with the server.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Realm settings</strong> in the menu.</p> </li> <li> <p>Click the <strong>General</strong> tab.</p> <div class="paragraph"> <div class="title">General tab</div> <p><span class="image"><img src="./images/general-tab.png" alt="General Tab"></span></p> </div> </li> <li> <p>Set <strong>Require SSL</strong> to one of the following SSL modes:</p> <div class="ulist"> <ul> <li> <p><strong>External requests</strong> Users can interact with Keycloak without SSL so long as they stick to private IPv4 addresses such as <code>localhost</code>, <code>127.0.0.1</code>, <code>10.x.x.x</code>, <code>192.168.x.x</code>, <code>172.16.x.x</code> or IPv6 link-local and unique-local addresses. If you try to access Keycloak without SSL from a non-private IP address, you will get an error.</p> </li> <li> <p><strong>None</strong> Keycloak does not require SSL. This choice applies only in development when you are experimenting and do not plan to support this deployment.</p> </li> <li> <p><strong>All requests</strong> Keycloak requires SSL for all IP addresses.</p> </li> </ul> </div> </li> </ol> </div> </div> <div class="sect2"> <h3 id="_email"><a class="anchor" href="#_email"></a>Configuring email for a realm</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/realms/email.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/realms/email.adoc&amp;description=%0A%0AFile:%20server_admin/topics/realms/email.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Keycloak sends emails to users to verify their email addresses, when they forget their passwords, or when an administrator needs to receive notifications about a server event. To enable Keycloak to send emails, you provide Keycloak with your SMTP server settings.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Realm settings</strong> in the menu.</p> </li> <li> <p>Click the <strong>Email</strong> tab.</p> <div class="paragraph"> <div class="title">Email tab</div> <p><span class="image"><img src="./images/email-tab.png" alt="Email Tab"></span></p> </div> </li> <li> <p>Fill in the fields and toggle the switches as needed.</p> </li> </ol> </div> <div class="dlist"> <div class="title">Template</div> <dl> <dt class="hdlist1">From</dt> <dd> <p><strong>From</strong> denotes the address used for the <strong>From</strong> SMTP-Header for the emails sent.</p> </dd> <dt class="hdlist1">From display name</dt> <dd> <p><strong>From display name</strong> allows to configure a user-friendly email address aliases (optional). If not set the plain <strong>From</strong> email address will be displayed in email clients.</p> </dd> <dt class="hdlist1">Reply to</dt> <dd> <p><strong>Reply to</strong> denotes the address used for the <strong>Reply-To</strong> SMTP-Header for the mails sent (optional). If not set the plain <strong>From</strong> email address will be used.</p> </dd> <dt class="hdlist1">Reply to display name</dt> <dd> <p><strong>Reply to display name</strong> allows to configure a user-friendly email address aliases (optional). If not set the plain <strong>Reply To</strong> email address will be displayed.</p> </dd> <dt class="hdlist1">Envelope from</dt> <dd> <p><strong>Envelope from</strong> denotes the <a href="https://en.wikipedia.org/wiki/Bounce_address">Bounce Address</a> used for the <strong>Return-Path</strong> SMTP-Header for the mails sent (optional).</p> </dd> </dl> </div> <div class="dlist"> <div class="title">Connection &amp; Authentication</div> <dl> <dt class="hdlist1">Host</dt> <dd> <p><strong>Host</strong> denotes the SMTP server hostname used for sending emails.</p> </dd> <dt class="hdlist1">Port</dt> <dd> <p><strong>Port</strong> denotes the SMTP server port.</p> </dd> <dt class="hdlist1">Encryption</dt> <dd> <p>Tick one of these checkboxes to support sending emails for recovering usernames and passwords, especially if the SMTP server is on an external network. You will most likely need to change the <strong>Port</strong> to 465, the default port for SSL/TLS.</p> </dd> <dt class="hdlist1">Authentication</dt> <dd> <p>Set this switch to <strong>ON</strong> if your SMTP server requires authentication. When prompted, supply the <strong>Username</strong> and <strong>Password</strong>. The value of the <strong>Password</strong> field can refer a value from an external <a href="#_vault-administration">vault</a>.</p> </dd> </dl> </div> </div> <div class="sect2"> <h3 id="_themes"><a class="anchor" href="#_themes"></a>Configuring themes</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/realms/themes.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/realms/themes.adoc&amp;description=%0A%0AFile:%20server_admin/topics/realms/themes.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>For a given realm, you can change the appearance of any UI in Keycloak by using themes.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Realm setting</strong> in the menu.</p> </li> <li> <p>Click the <strong>Themes</strong> tab.</p> <div class="paragraph"> <div class="title">Themes tab</div> <p><span class="image"><img src="./images/themes-tab.png" alt="Themes tab"></span></p> </div> </li> <li> <p>Pick the theme you want for each UI category and click <strong>Save</strong>.</p> <div class="dlist"> <dl> <dt class="hdlist1">Login theme</dt> <dd> <p>Username password entry, OTP entry, new user registration, and other similar screens related to login.</p> </dd> <dt class="hdlist1">Account theme</dt> <dd> <p>The console used by the user to manage his or her account.</p> </dd> <dt class="hdlist1">Admin console theme</dt> <dd> <p>The skin of the Keycloak Admin Console.</p> </dd> <dt class="hdlist1">Email theme</dt> <dd> <p>Whenever Keycloak has to send out an email, it uses templates defined in this theme to craft the email.</p> </dd> </dl> </div> </li> </ol> </div> <div class="ulist"> <div class="title">Additional resources</div> <ul> <li> <p>The <a href="https://www.keycloak.org/docs/26.0.6/server_development/">Server Developer Guide</a> describes how to create a new theme or modify existing ones.</p> </li> </ul> </div> </div> <div class="sect2"> <h3 id="enabling-internationalization"><a class="anchor" href="#enabling-internationalization"></a>Enabling internationalization</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/realms/proc-configuring-internationalization.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/realms/proc-configuring-internationalization.adoc&amp;description=%0A%0AFile:%20server_admin/topics/realms/proc-configuring-internationalization.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Every UI screen is internationalized in Keycloak. The default language is English, but you can choose which locales you want to support and what the default locale will be.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Realm Settings</strong> in the menu.</p> </li> <li> <p>Click the <strong>Localization</strong> tab.</p> </li> <li> <p>Enable <strong>Internationalization</strong>.</p> </li> <li> <p>Select the languages you will support.</p> <div class="paragraph"> <div class="title">Localization tab</div> <p><span class="image"><img src="./images/localization.png" alt="Localization tab"></span></p> </div> <div class="paragraph"> <p>The next time a user logs in, that user can choose a language on the login page to use for the login screens, Account Console, and Admin Console.</p> </div> </li> </ol> </div> <div class="ulist"> <div class="title">Additional resources</div> <ul> <li> <p>The <a href="https://www.keycloak.org/docs/26.0.6/server_development/">Server Developer Guide</a> explains how you can offer additional languages. All internationalized texts which are provided by the theme can be overwritten by realm-specific texts on the <strong>Localization</strong> tab.</p> </li> </ul> </div> <div class="sect3"> <h4 id="_user_locale_selection"><a class="anchor" href="#_user_locale_selection"></a>User locale selection</h4> <div class="paragraph"> <p>A locale selector provider suggests the best locale on the information available. However, it is often unknown who the user is. For this reason, the previously authenticated user&#8217;s locale is remembered in a persisted cookie.</p> </div> <div class="paragraph"> <p>The logic for selecting the locale uses the first of the following that is available:</p> </div> <div class="ulist"> <ul> <li> <p>User selected - when the user has selected a locale using the drop-down locale selector</p> </li> <li> <p>User profile - when there is an authenticated user and the user has a preferred locale set</p> </li> <li> <p>Client selected - passed by the client using for example ui_locales parameter</p> </li> <li> <p>Cookie - last locale selected on the browser</p> </li> <li> <p>Accepted language - locale from <strong>Accept-Language</strong> header</p> </li> <li> <p>Realm default</p> </li> <li> <p>If none of the above, fall back to English</p> </li> </ul> </div> <div class="paragraph"> <p>When a user is authenticated an action is triggered to update the locale in the persisted cookie mentioned earlier. If the user has actively switched the locale through the locale selector on the login pages the users locale is also updated at this point.</p> </div> <div class="paragraph"> <p>If you want to change the logic for selecting the locale, you have an option to create custom <code>LocaleSelectorProvider</code>. For details, please refer to the <a href="https://www.keycloak.org/docs/26.0.6/server_development/#_locale_selector">Server Developer Guide</a>.</p> </div> </div> </div> <div class="sect2"> <h3 id="controlling-login-options"><a class="anchor" href="#controlling-login-options"></a>Controlling login options</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/login-settings.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/login-settings.adoc&amp;description=%0A%0AFile:%20server_admin/topics/login-settings.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Keycloak includes several built-in login page features.</p> </div> <div class="sect3"> <h4 id="enabling-forgot-password"><a class="anchor" href="#enabling-forgot-password"></a>Enabling forgot password</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/login-settings/forgot-password.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/login-settings/forgot-password.adoc&amp;description=%0A%0AFile:%20server_admin/topics/login-settings/forgot-password.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>If you enable <code>Forgot password</code>, users can reset their login credentials if they forget their passwords or lose their OTP generator.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Realm settings</strong> in the menu.</p> </li> <li> <p>Click the <strong>Login</strong> tab.</p> <div class="paragraph"> <div class="title">Login tab</div> <p><span class="image"><img src="./images/login-tab.png" alt="Login Tab"></span></p> </div> </li> <li> <p>Toggle <strong>Forgot password</strong> to <strong>ON</strong>.</p> <div class="paragraph"> <p>A <code>Forgot Password?</code> link displays in your login pages.</p> </div> <div class="paragraph"> <div class="title">Forgot password link</div> <p><span class="image"><img src="./images/forgot-password-link.png" alt="Forgot Password Link"></span></p> </div> </li> <li> <p>Specify <code>Host</code> and <code>From</code> in the <strong>Email</strong> tab in order for Keycloak to be able to send the reset email.</p> </li> <li> <p>Click this link to bring users where they can enter their username or email address and receive an email with a link to reset their credentials.</p> <div class="paragraph"> <div class="title">Forgot password page</div> <p><span class="image"><img src="./images/forgot-password-page.png" alt="Forgot Password Page"></span></p> </div> </li> </ol> </div> <div class="paragraph"> <p>The text sent in the email is configurable. See <a href="https://www.keycloak.org/docs/26.0.6/server_development/">Server Developer Guide</a> for more information.</p> </div> <div class="paragraph"> <p>When users click the email link, Keycloak asks them to update their password, and if they have set up an OTP generator, Keycloak asks them to reconfigure the OTP generator. Depending on security requirements of your organization, you may not want users to reset their OTP generator through email.</p> </div> <div class="paragraph"> <p>To change this behavior, perform these steps:</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Authentication</strong> in the menu.</p> </li> <li> <p>Click the <strong>Flows</strong> tab.</p> </li> <li> <p>Select the <strong>Reset Credentials</strong> flow.</p> <div class="paragraph"> <div class="title">Reset credentials flow</div> <p><span class="image"><img src="./images/reset-credentials-flow.png" alt="Reset Credentials Flow"></span></p> </div> <div class="paragraph"> <p>If you do not want to reset the OTP, set the <code>Reset - Conditional OTP</code> sub-flow requirement to <strong>Disabled</strong>.</p> </div> </li> <li> <p>Click <strong>Authentication</strong> in the menu.</p> </li> <li> <p>Click the <strong>Required actions</strong> tab.</p> </li> <li> <p>Ensure <strong>Update Password</strong> is enabled.</p> <div class="paragraph"> <div class="title">Required Actions</div> <p><span class="image"><img src="./images/reset-credentials-required-actions.png" alt="Required Actions"></span></p> </div> </li> </ol> </div> </div> <div class="sect3"> <h4 id="enabling-remember-me"><a class="anchor" href="#enabling-remember-me"></a>Enabling Remember Me</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/login-settings/remember-me.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/login-settings/remember-me.adoc&amp;description=%0A%0AFile:%20server_admin/topics/login-settings/remember-me.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>A logged-in user closing their browser destroys their session, and that user must log in again. You can set Keycloak to keep the user&#8217;s login session open if that user clicks the <em>Remember Me</em> checkbox upon login. This action turns the login cookie from a session-only cookie to a persistence cookie.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Realm settings</strong> in the menu.</p> </li> <li> <p>Click the <strong>Login</strong> tab.</p> </li> <li> <p>Toggle the <strong>Remember Me</strong> switch to <strong>On</strong>.</p> <div class="paragraph"> <div class="title">Login tab</div> <p><span class="image"><img src="./images/login-tab-remember-me.png" alt="Login Tab Remember Me"></span></p> </div> <div class="paragraph"> <p>When you save this setting, a <code>remember me</code> checkbox displays on the realm&#8217;s login page.</p> </div> <div class="paragraph"> <div class="title">Remember Me</div> <p><span class="image"><img src="./images/remember-me.png" alt="Remember Me"></span></p> </div> </li> </ol> </div> </div> <div class="sect3"> <h4 id="_mapping-acr-to-loa-realm"><a class="anchor" href="#_mapping-acr-to-loa-realm"></a>ACR to Level of Authentication (LoA) Mapping</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/login-settings/acr-to-loa-mapping.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/login-settings/acr-to-loa-mapping.adoc&amp;description=%0A%0AFile:%20server_admin/topics/login-settings/acr-to-loa-mapping.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>In the general settings of a realm, you can define which <code>Authentication Context Class Reference (ACR)</code> value is mapped to which <code>Level of Authentication (LoA)</code>. The ACR can be any value, whereas the LoA must be numeric. The acr claim can be requested in the <code>claims</code> or <code>acr_values</code> parameter sent in the OIDC request and it is also included in the access token and ID token. The mapped number is used in the authentication flow conditions.</p> </div> <div class="paragraph"> <p>Mapping can be also specified at the client level in case that particular client needs to use different values than realm. However, a best practice is to stick to realm mappings.</p> </div> <div class="paragraph"> <p><span class="image"><img src="./images/realm-oidc-map-acr-to-loa.png" alt="ACR to LoA mapping"></span></p> </div> <div class="paragraph"> <p>For further details see <a href="#_step-up-flow">Step-up Authentication</a> and <a href="https://openid.net/specs/openid-connect-core-1_0.html#acrSemantics">the official OIDC specification</a>.</p> </div> </div> <div class="sect3"> <h4 id="_update-email-workflow"><a class="anchor" href="#_update-email-workflow"></a>Update Email Workflow (UpdateEmail)</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/login-settings/update-email-workflow.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/login-settings/update-email-workflow.adoc&amp;description=%0A%0AFile:%20server_admin/topics/login-settings/update-email-workflow.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>With this workflow, users will have to use an UPDATE_EMAIL action to change their own email address.</p> </div> <div class="paragraph"> <p>The action is associated with a single email input form. If the realm has email verification disabled, this action will allow to update the email without verification. If the realm has email verification enabled, the action will send an email update action token to the new email address without changing the account email. Only the action token triggering will complete the email update.</p> </div> <div class="paragraph"> <p>Applications are able to send their users to the email update form by leveraging UPDATE_EMAIL as an <a href="#con-aia_server_administration_guide">AIA (Application Initiated Action)</a>.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>UpdateEmail is <strong>Preview</strong> and is not fully supported. This feature is disabled by default.</p> </div> <div class="paragraph"> <p>To enable start the server with <code>--features=preview</code> or <code>--features=update-email</code></p> </div> </td> </tr> </table> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>If you enable this feature and you are migrating from a previous version, enable the <strong>Update Email</strong> required action in your realms. Otherwise, users cannot update their email addresses.</p> </div> </td> </tr> </table> </div> </div> </div> <div class="sect2"> <h3 id="realm_keys"><a class="anchor" href="#realm_keys"></a>Configuring realm keys</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/realms/keys.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/realms/keys.adoc&amp;description=%0A%0AFile:%20server_admin/topics/realms/keys.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>The authentication protocols that are used by Keycloak require cryptographic signatures and sometimes encryption. Keycloak uses asymmetric key pairs, a private and public key, to accomplish this.</p> </div> <div class="paragraph"> <p>Keycloak has a single active key pair at a time, but can have several passive keys as well. The active key pair is used to create new signatures, while the passive key pair can be used to verify previous signatures. This makes it possible to regularly rotate the keys without any downtime or interruption to users.</p> </div> <div class="paragraph"> <p>When a realm is created, a key pair and a self-signed certificate is automatically generated.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Realm settings</strong> in the menu.</p> </li> <li> <p>Click <strong>Keys</strong>.</p> </li> <li> <p>Select <strong>Passive keys</strong> from the filter dropdown to view passive keys.</p> </li> <li> <p>Select <strong>Disabled keys</strong> from the filter dropdown to view disabled keys.</p> </li> </ol> </div> <div class="paragraph"> <p>A key pair can have the status <code>Active</code>, but still not be selected as the currently active key pair for the realm. The selected active pair which is used for signatures is selected based on the first key provider sorted by priority that is able to provide an active key pair.</p> </div> <div class="sect3"> <h4 id="rotating-keys"><a class="anchor" href="#rotating-keys"></a>Rotating keys</h4> <div class="paragraph"> <p>We recommend that you regularly rotate keys. Start by creating new keys with a higher priority than the existing active keys. You can instead create new keys with the same priority and making the previous keys passive.</p> </div> <div class="paragraph"> <p>Once new keys are available, all new tokens and cookies will be signed with the new keys. When a user authenticates to an application, the SSO cookie is updated with the new signature. When OpenID Connect tokens are refreshed new tokens are signed with the new keys. Eventually, all cookies and tokens use the new keys and after a while the old keys can be removed.</p> </div> <div class="paragraph"> <p>The frequency of deleting old keys is a tradeoff between security and making sure all cookies and tokens are updated. Consider creating new keys every three to six months and deleting old keys one to two months after you create the new keys. If a user was inactive in the period between the new keys being added and the old keys being removed, that user will have to re-authenticate.</p> </div> <div class="paragraph"> <p>Rotating keys also applies to offline tokens. To make sure they are updated, the applications need to refresh the tokens before the old keys are removed.</p> </div> </div> <div class="sect3"> <h4 id="adding-a-generated-key-pair"><a class="anchor" href="#adding-a-generated-key-pair"></a>Adding a generated key pair</h4> <div class="paragraph"> <p>Use this procedure to generate a key pair including a self-signed certificate.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Select the realm in the Admin Console.</p> </li> <li> <p>Click <strong>Realm settings</strong> in the menu.</p> </li> <li> <p>Click the <strong>Keys</strong> tab.</p> </li> <li> <p>Click the <strong>Providers</strong> tab.</p> </li> <li> <p>Click <strong>Add provider</strong> and select <strong>rsa-generated</strong>.</p> </li> <li> <p>Enter a number in the <strong>Priority</strong> field. This number determines if the new key pair becomes the active key pair. The highest number makes the key pair active.</p> </li> <li> <p>Select a value for <strong>AES Key size</strong>.</p> </li> <li> <p>Click <strong>Save</strong>.</p> </li> </ol> </div> <div class="paragraph"> <p>Changing the priority for a provider will not cause the keys to be re-generated, but if you want to change the keysize you can edit the provider and new keys will be generated.</p> </div> </div> <div class="sect3"> <h4 id="rotating-keys-by-extracting-a-certificate"><a class="anchor" href="#rotating-keys-by-extracting-a-certificate"></a>Rotating keys by extracting a certificate</h4> <div class="paragraph"> <p>You can rotate keys by extracting a certificate from an RSA generated key pair and using that certificate in a new keystore.</p> </div> <div class="ulist"> <div class="title">Prerequisites</div> <ul> <li> <p>A generated key pair</p> </li> </ul> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Select the realm in the Admin Console.</p> </li> <li> <p>Click <strong>Realm Settings</strong>.</p> </li> <li> <p>Click the <strong>Keys</strong> tab.</p> <div class="paragraph"> <p>A list of <strong>Active</strong> keys appears.</p> </div> </li> <li> <p>On a row with an RSA key, click <strong>Certificate</strong> under <strong>Public Keys</strong>.</p> <div class="paragraph"> <p>The certificate appears in text form.</p> </div> </li> <li> <p>Save the certificate to a file and enclose it in these lines.</p> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">----Begin Certificate---- &lt;Output&gt; ----End Certificate----</code></pre> </div> </div> </li> <li> <p>Use the <strong>keytool</strong> command to convert the key file to PEM Format.</p> </li> <li> <p>Remove the current RSA public key certificate from the keystore.</p> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">keytool -delete -keystore &lt;keystore&gt;.jks -storepass &lt;password&gt; -alias &lt;key&gt;</code></pre> </div> </div> </li> <li> <p>Import the new certificate into the keystore</p> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">keytool -importcert -file domain.crt -keystore &lt;keystore&gt;.jks -storepass &lt;password&gt; -alias &lt;key&gt;</code></pre> </div> </div> </li> <li> <p>Rebuild the application.</p> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">mvn clean install wildfly:deploy</code></pre> </div> </div> </li> </ol> </div> </div> <div class="sect3"> <h4 id="adding-an-existing-key-pair-and-certificate"><a class="anchor" href="#adding-an-existing-key-pair-and-certificate"></a>Adding an existing key pair and certificate</h4> <div class="paragraph"> <p>To add a key pair and certificate obtained elsewhere select <code>Providers</code> and choose <code>rsa</code> from the dropdown. You can change the priority to make sure the new key pair becomes the active key pair.</p> </div> <div class="ulist"> <div class="title">Prerequisites</div> <ul> <li> <p>A private key file. The file must be PEM formatted.</p> </li> </ul> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Select the realm in the Admin Console.</p> </li> <li> <p>Click <strong>Realm settings</strong>.</p> </li> <li> <p>Click the <strong>Keys</strong> tab.</p> </li> <li> <p>Click the <strong>Providers</strong> tab.</p> </li> <li> <p>Click <strong>Add provider</strong> and select <strong>rsa</strong>.</p> </li> <li> <p>Enter a number in the <strong>Priority</strong> field. This number determines if the new key pair becomes the active key pair.</p> </li> <li> <p>Click <strong>Browse&#8230;&#8203;</strong> beside <strong>Private RSA Key</strong> to upload the private key file.</p> </li> <li> <p>If you have a signed certificate for your private key, click <strong>Browse&#8230;&#8203;</strong> beside <strong>X509 Certificate</strong> to upload the certificate file. Keycloak automatically generates a self-signed certificate if you do not upload a certificate.</p> </li> <li> <p>Click <strong>Save</strong>.</p> </li> </ol> </div> </div> <div class="sect3"> <h4 id="loading-keys-from-a-java-keystore"><a class="anchor" href="#loading-keys-from-a-java-keystore"></a>Loading keys from a Java Keystore</h4> <div class="paragraph"> <p>To add a key pair and certificate stored in a Java Keystore file on the host select <code>Providers</code> and choose <code>java-keystore</code> from the dropdown. You can change the priority to make sure the new key pair becomes the active key pair.</p> </div> <div class="paragraph"> <p>For the associated certificate chain to be loaded it must be imported to the Java Keystore file with the same <code>Key Alias</code> used to load the key pair.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Select the realm in the Admin Console.</p> </li> <li> <p>Click <strong>Realm settings</strong> in the menu.</p> </li> <li> <p>Click the <strong>Keys</strong> tab.</p> </li> <li> <p>Click the <strong>Providers</strong> tab.</p> </li> <li> <p>Click <strong>Add provider</strong> and select <strong>java-keystore</strong>.</p> </li> <li> <p>Enter a number in the <strong>Priority</strong> field. This number determines if the new key pair becomes the active key pair.</p> </li> <li> <p>Enter the desired <strong>Algorithm</strong>. Note that the algorithm should match the key type (for example <code>RS256</code> requires a RSA private key, <code>ES256</code> a EC private key or <code>AES</code> an AES secret key).</p> </li> <li> <p>Enter a value for <strong>Keystore</strong>. Path to the keystore file.</p> </li> <li> <p>Enter the <strong>Keystore Password</strong>. The option can refer a value from an external <a href="#_vault-administration">vault</a>.</p> </li> <li> <p>Enter a value for <strong>Keystore Type</strong> (<code>JKS</code>, <code>PKCS12</code> or <code>BCFKS</code>).</p> </li> <li> <p>Enter a value for the <strong>Key Alias</strong> to load from the keystore.</p> </li> <li> <p>Enter the <strong>Key Password</strong>. The option can refer a value from an external <a href="#_vault-administration">vault</a>.</p> </li> <li> <p>Enter a value for <strong>Key Use</strong> (<code>sig</code> for signing or <code>enc</code> for encryption). Note that the use should match the algorithm type (for example <code>RS256</code> is <code>sig</code> but <code>RSA-OAEP</code> is <code>enc</code>)</p> </li> <li> <p>Click <strong>Save</strong>.</p> </li> </ol> </div> <div class="admonitionblock warning"> <table> <tr> <td class="icon"> <i class="fa icon-warning" title="Warning"></i> </td> <td class="content"> <div class="paragraph"> <p>Not all the keystore types support all types of keys. For example, <code>JKS</code> in all modes and <code>PKCS12</code> in fips mode (<code>BCFIPS</code> provider) cannot store secret key entries.</p> </div> </td> </tr> </table> </div> </div> <div class="sect3"> <h4 id="making-keys-passive"><a class="anchor" href="#making-keys-passive"></a>Making keys passive</h4> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Select the realm in the Admin Console.</p> </li> <li> <p>Click <strong>Realm settings</strong> in the menu.</p> </li> <li> <p>Click the <strong>Keys</strong> tab.</p> </li> <li> <p>Click the <strong>Providers</strong> tab.</p> </li> <li> <p>Click the provider of the key you want to make passive.</p> </li> <li> <p>Toggle <strong>Active</strong> to <strong>Off</strong>.</p> </li> <li> <p>Click <strong>Save</strong>.</p> </li> </ol> </div> </div> <div class="sect3"> <h4 id="disabling-keys"><a class="anchor" href="#disabling-keys"></a>Disabling keys</h4> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Select the realm in the Admin Console.</p> </li> <li> <p>Click <strong>Realm settings</strong> in the menu.</p> </li> <li> <p>Click the <strong>Keys</strong> tab.</p> </li> <li> <p>Click the <strong>Providers</strong> tab.</p> </li> <li> <p>Click the provider of the key you want to make passive.</p> </li> <li> <p>Toggle <strong>Enabled</strong> to <strong>Off</strong>.</p> </li> <li> <p>Click <strong>Save</strong>.</p> </li> </ol> </div> </div> <div class="sect3"> <h4 id="compromised-keys"><a class="anchor" href="#compromised-keys"></a>Compromised keys</h4> <div class="paragraph"> <p>Keycloak has the signing keys stored just locally and they are never shared with the client applications, users or other entities. However, if you think that your realm signing key was compromised, you should first generate new key pair as described above and then immediately remove the compromised key pair.</p> </div> <div class="paragraph"> <p>Alternatively, you can delete the provider from the <code>Providers</code> table.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Clients</strong> in the menu.</p> </li> <li> <p>Click <strong>security-admin-console</strong>.</p> </li> <li> <p>Scroll down to the <strong>Access settings</strong> section.</p> </li> <li> <p>Fill in the <strong>Admin URL</strong> field.</p> </li> <li> <p>Click the <strong>Advanced</strong> tab.</p> </li> <li> <p>Click <strong>Set to now</strong> in the <strong>Revocation</strong> section.</p> </li> <li> <p>Click <strong>Push</strong>.</p> </li> </ol> </div> <div class="paragraph"> <p>Pushing the not-before policy ensures that client applications do not accept the existing tokens signed by the compromised key. The client application is forced to download new key pairs from Keycloak also so the tokens signed by the compromised key will be invalid.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>REST and confidential clients must set <strong>Admin URL</strong> so Keycloak can send clients the pushed not-before policy request.</p> </div> </td> </tr> </table> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="_user-storage-federation"><a class="anchor" href="#_user-storage-federation"></a>Using external storage</h2> <div class="sectionbody"> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/user-federation.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/user-federation.adoc&amp;description=%0A%0AFile:%20server_admin/topics/user-federation.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>Organizations can have databases containing information, passwords, and other credentials. Typically, you cannot migrate existing data storage to a Keycloak deployment so Keycloak can federate existing external user databases. Keycloak supports LDAP and Active Directory, but you can also code extensions for any custom user database by using the Keycloak User Storage SPI.</p> </div> <div class="paragraph"> <p>When a user attempts to log in, Keycloak examines that user&#8217;s storage to find that user. If Keycloak does not find the user, Keycloak iterates over each User Storage provider for the realm until it finds a match. Data from the external data storage then maps into a standard user model the Keycloak runtime consumes. This user model then maps to OIDC token claims and SAML assertion attributes.</p> </div> <div class="paragraph"> <p>External user databases rarely have the data necessary to support all the features of Keycloak, so the User Storage Provider can opt to store items locally in Keycloak user data storage. Providers can import users locally and sync periodically with external data storage. This approach depends on the capabilities of the provider and the configuration of the provider. For example, your external user data storage may not support OTP. The OTP can be handled and stored by Keycloak, depending on the provider.</p> </div> <div class="sect2"> <h3 id="adding-a-provider"><a class="anchor" href="#adding-a-provider"></a>Adding a provider</h3> <div class="paragraph"> <p>To add a storage provider, perform the following procedure:</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>User Federation</strong> in the menu.</p> <div class="paragraph"> <div class="title">User federation</div> <p><span class="image"><img src="./images/user-federation.png" alt="User federation"></span></p> </div> </li> <li> <p>Select the provider type card from the listed cards.</p> <div class="paragraph"> <p>Keycloak brings you to that provider&#8217;s configuration page.</p> </div> </li> </ol> </div> </div> <div class="sect2"> <h3 id="dealing-with-provider-failures"><a class="anchor" href="#dealing-with-provider-failures"></a>Dealing with provider failures</h3> <div class="paragraph"> <p>If a User Storage Provider fails, you may not be able to log in and view users in the Admin Console. Keycloak does not detect failures when using a Storage Provider to look up a user, so it cancels the invocation. If you have a Storage Provider with a high priority that fails during user lookup, the login or user query fails with an exception and will not fail over to the next configured provider.</p> </div> <div class="paragraph"> <p>Keycloak searches the local Keycloak user database first to resolve users before any LDAP or custom User Storage Provider. Consider creating an administrator account stored in the local Keycloak user database in case of problems connecting to your LDAP and back ends.</p> </div> <div class="paragraph"> <p>Each LDAP and custom User Storage Provider has an <code>enable</code> toggle on its Admin Console page. Disabling the User Storage Provider skips the provider when performing queries, so you can view and log in with user accounts in a different provider with lower priority. If your provider uses an <code>import</code> strategy and is disabled, imported users are still available for lookup in read-only mode.</p> </div> <div class="paragraph"> <p>When a Storage Provider lookup fails, Keycloak does not fail over because user databases often have duplicate usernames or duplicate emails between them. Duplicate usernames and emails can cause problems because the user loads from one external data store when the admin expects them to load from another data store.</p> </div> </div> <div class="sect2"> <h3 id="_ldap"><a class="anchor" href="#_ldap"></a>Lightweight Directory Access Protocol (LDAP) and Active Directory</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/user-federation/ldap.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/user-federation/ldap.adoc&amp;description=%0A%0AFile:%20server_admin/topics/user-federation/ldap.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Keycloak includes an LDAP/AD provider. You can federate multiple different LDAP servers in one Keycloak realm and map LDAP user attributes into the Keycloak common user model.</p> </div> <div class="paragraph"> <p>By default, Keycloak maps the username, email, first name, and last name of the user account, but you can also configure additional <a href="#_ldap_mappers">mappings</a>. Keycloak&#8217;s LDAP/AD provider supports password validation using LDAP/AD protocols and storage, edit, and synchronization modes.</p> </div> <div class="sect3"> <h4 id="configuring-federated-ldap-storage"><a class="anchor" href="#configuring-federated-ldap-storage"></a>Configuring federated LDAP storage</h4> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>User Federation</strong> in the menu.</p> <div class="paragraph"> <div class="title">User federation</div> <p><span class="image"><img src="./images/user-federation.png" alt="User federation"></span></p> </div> </li> <li> <p>Click <strong>Add LDAP providers</strong>.</p> <div class="paragraph"> <p>Keycloak brings you to the LDAP configuration page.</p> </div> </li> </ol> </div> </div> <div class="sect3"> <h4 id="storage-mode"><a class="anchor" href="#storage-mode"></a>Storage mode</h4> <div class="paragraph"> <p>Keycloak imports users from LDAP into the local Keycloak user database. This copy of the user database synchronizes on-demand or through a periodic background task. An exception exists for synchronizing passwords. Keycloak never imports passwords. Password validation always occurs on the LDAP server.</p> </div> <div class="paragraph"> <p>The advantage of synchronization is that all Keycloak features work efficiently because any required extra per-user data is stored locally. The disadvantage is that each time Keycloak queries a specific user for the first time, Keycloak performs a corresponding database insert.</p> </div> <div class="paragraph"> <p>You can synchronize the import with your LDAP server. Import synchronization is unnecessary when LDAP mappers always read particular attributes from the LDAP rather than the database.</p> </div> <div class="paragraph"> <p>You can use LDAP with Keycloak without importing users into the Keycloak user database. The LDAP server backs up the common user model that the Keycloak runtime uses. If LDAP does not support data that a Keycloak feature requires, that feature will not work. The advantage of this approach is that you do not have the resource usage of importing and synchronizing copies of LDAP users into the Keycloak user database.</p> </div> <div class="paragraph"> <p>The <strong>Import Users</strong> switch on the LDAP configuration page controls this storage mode. To import users, toggle this switch to <strong>ON</strong>.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>If you disable <strong>Import Users</strong>, you cannot save user profile attributes into the Keycloak database. Also, you cannot save metadata except for user profile metadata mapped to the LDAP. This metadata can include role mappings, group mappings, and other metadata based on the LDAP mappers' configuration.</p> </div> <div class="paragraph"> <p>When you attempt to change the non-LDAP mapped user data, the user update is not possible. For example, you cannot disable the LDAP mapped user unless the user&#8217;s <code>enabled</code> flag maps to an LDAP attribute.</p> </div> </td> </tr> </table> </div> </div> <div class="sect3"> <h4 id="edit-mode"><a class="anchor" href="#edit-mode"></a>Edit mode</h4> <div class="paragraph"> <p>Users and admins can modify user metadata, users through the <a href="#_account-service">Account Console</a>, and administrators through the Admin Console. The <code>Edit Mode</code> configuration on the LDAP configuration page defines the user&#8217;s LDAP update privileges.</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">READONLY</dt> <dd> <p>You cannot change the username, email, first name, last name, and other mapped attributes. Keycloak shows an error anytime a user attempts to update these fields. Password updates are not supported.</p> </dd> <dt class="hdlist1">WRITABLE</dt> <dd> <p>You can change the username, email, first name, last name, and other mapped attributes and passwords and synchronize them automatically with the LDAP store.</p> </dd> <dt class="hdlist1">UNSYNCED</dt> <dd> <p>Keycloak stores changes to the username, email, first name, last name, and passwords in Keycloak local storage, so the administrator must synchronize this data back to LDAP. In this mode, Keycloak deployments can update user metadata on read-only LDAP servers. This option also applies when importing users from LDAP into the local Keycloak user database.</p> </dd> </dl> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>When Keycloak creates the LDAP provider, Keycloak also creates a set of initial <a href="#_ldap_mappers">LDAP mappers</a>. Keycloak configures these mappers based on a combination of the <strong>Vendor</strong>, <strong>Edit Mode</strong>, and <strong>Import Users</strong> switches. For example, when edit mode is UNSYNCED, Keycloak configures the mappers to read a particular user attribute from the database and not from the LDAP server. However, if you later change the edit mode, the mapper&#8217;s configuration does not change because it is impossible to detect if the configuration changes changed in UNSYNCED mode. Decide the <strong>Edit Mode</strong> when creating the LDAP provider. This note applies to <strong>Import Users</strong> switch also.</p> </div> </td> </tr> </table> </div> </div> <div class="sect3"> <h4 id="other-configuration-options"><a class="anchor" href="#other-configuration-options"></a>Other configuration options</h4> <div class="dlist"> <dl> <dt class="hdlist1">Console Display Name</dt> <dd> <p>The name of the provider to display in the admin console.</p> </dd> <dt class="hdlist1">Priority</dt> <dd> <p>The priority of the provider when looking up users or adding a user.</p> </dd> <dt class="hdlist1">Sync Registrations</dt> <dd> <p>Toggle this switch to <strong>ON</strong> if you want new users created by Keycloak added to LDAP.</p> </dd> <dt class="hdlist1">Allow Kerberos authentication</dt> <dd> <p>Enable Kerberos/SPNEGO authentication in the realm with user data provisioned from LDAP. For more information, see the <a href="#_kerberos">Kerberos section</a>.</p> </dd> <dt class="hdlist1">Other options</dt> <dd> <p>Hover the mouse pointer over the tooltips in the Admin Console to see more details about these options.</p> </dd> </dl> </div> </div> <div class="sect3"> <h4 id="connecting-to-ldap-over-ssl"><a class="anchor" href="#connecting-to-ldap-over-ssl"></a>Connecting to LDAP over SSL</h4> <div class="paragraph"> <p>When you configure a secure connection URL to your LDAP store (for example,<code>ldaps://myhost.com:636</code>), Keycloak uses SSL to communicate with the LDAP server. Configure a truststore on the Keycloak server side so that Keycloak can trust the SSL connection to LDAP - see <a href="https://www.keycloak.org/server/keycloak-truststore">Configuring a Truststore</a> guide.</p> </div> <div class="paragraph"> <p>The <code>Use Truststore SPI</code> configuration property is deprecated. It should normally be left as <code>Always</code>.</p> </div> </div> <div class="sect3"> <h4 id="synchronizing-ldap-users-to-keycloak"><a class="anchor" href="#synchronizing-ldap-users-to-keycloak"></a>Synchronizing LDAP users to Keycloak</h4> <div class="paragraph"> <p>If you set the <strong>Import Users</strong> option, the LDAP Provider handles importing LDAP users into the Keycloak local database. The first time a user logs in or is returned as part of a user query (e.g. using the search field in the admin console), the LDAP provider imports the LDAP user into the Keycloak database. During authentication, the LDAP password is validated.</p> </div> <div class="paragraph"> <p>If you want to sync all LDAP users into the Keycloak database, configure and enable the <strong>Sync Settings</strong> on the LDAP provider configuration page.</p> </div> <div class="paragraph"> <p>Two types of synchronization exist:</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Periodic Full sync</dt> <dd> <p>This type synchronizes all LDAP users into the Keycloak database. The LDAP users already in Keycloak, but different in LDAP, directly update in the Keycloak database.</p> </dd> <dt class="hdlist1">Periodic Changed users sync</dt> <dd> <p>When synchronizing, Keycloak creates or updates users created or updated after the last sync only.</p> </dd> </dl> </div> <div class="paragraph"> <p>The best way to synchronize is to click <strong>Synchronize all users</strong> when you first create the LDAP provider, then set up periodic synchronization of changed users.</p> </div> </div> <div class="sect3"> <h4 id="_ldap_mappers"><a class="anchor" href="#_ldap_mappers"></a>LDAP mappers</h4> <div class="paragraph"> <p>LDAP mappers are <code>listeners</code> triggered by the LDAP Provider. They provide another extension point to LDAP integration. LDAP mappers are triggered when:</p> </div> <div class="ulist"> <ul> <li> <p>Users log in by using LDAP.</p> </li> <li> <p>Users initially register.</p> </li> <li> <p>The Admin Console queries a user.</p> </li> </ul> </div> <div class="paragraph"> <p>When you create an LDAP Federation provider, Keycloak automatically provides a set of <code>mappers</code> for this provider. This set is changeable by users, who can also develop mappers or update/delete existing ones.</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">User Attribute Mapper</dt> <dd> <p>This mapper specifies which LDAP attribute maps to the attribute of the Keycloak user. For example, you can configure the <code>mail</code> LDAP attribute to the <code>email</code> attribute in the Keycloak database. For this mapper implementation, a one-to-one mapping always exists.</p> </dd> <dt class="hdlist1">FullName Mapper</dt> <dd> <p>This mapper specifies the full name of the user. Keycloak saves the name in an LDAP attribute (usually <code>cn</code>) and maps the name to the <code>firstName</code> and <code>lastname</code> attributes in the Keycloak database. Having <code>cn</code> to contain the full name of the user is common for LDAP deployments.</p> </dd> </dl> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>When you register new users in Keycloak and <code>Sync Registrations</code> is ON for the LDAP provider, the fullName mapper permits falling back to the username. This fallback is useful when using Microsoft Active Directory (MSAD). The common setup for MSAD is to configure the <code>cn</code> LDAP attribute as fullName and, at the same time, use the <code>cn</code> LDAP attribute as the <code>RDN LDAP Attribute</code> in the LDAP provider configuration. With this setup, Keycloak falls back to the username. For example, if you create Keycloak user "john123" and leave firstName and lastName empty, then the fullname mapper saves "john123" as the value of the <code>cn</code> in LDAP. When you enter "John Doe" for firstName and lastName later, the fullname mapper updates LDAP <code>cn</code> to the "John Doe" value as falling back to the username is unnecessary.</p> </div> </td> </tr> </table> </div> <div class="dlist"> <dl> <dt class="hdlist1">Hardcoded Attribute Mapper</dt> <dd> <p>This mapper adds a hardcoded attribute value to each Keycloak user linked with LDAP. This mapper can also force values for the <code>enabled</code> or <code>emailVerified</code> user properties.</p> </dd> <dt class="hdlist1">Role Mapper</dt> <dd> <p>This mapper configures role mappings from LDAP into Keycloak role mappings. A single role mapper can map LDAP roles (usually groups from a particular branch of the LDAP tree) into roles corresponding to a specified client&#8217;s realm roles or client roles. You can configure more Role mappers for the same LDAP provider. For example, you can specify that role mappings from groups under <code>ou=main,dc=example,dc=org</code> map to realm role mappings, and role mappings from groups under <code>ou=finance,dc=example,dc=org</code> map to client role mappings of client <code>finance</code>.</p> </dd> <dt class="hdlist1">Hardcoded Role Mapper</dt> <dd> <p>This mapper grants a specified Keycloak role to each Keycloak user from the LDAP provider.</p> </dd> <dt class="hdlist1">Group Mapper</dt> <dd> <p>This mapper maps LDAP groups from a branch of an LDAP tree into groups within Keycloak. This mapper also propagates user-group mappings from LDAP into user-group mappings in Keycloak.</p> </dd> <dt class="hdlist1">MSAD User Account Mapper</dt> <dd> <p>This mapper is specific to Microsoft Active Directory (MSAD). It can integrate the MSAD user account state into the Keycloak account state, such as enabled account or expired password. This mapper uses the <code>userAccountControl</code>, and <code>pwdLastSet</code> LDAP attributes, specific to MSAD and are not the LDAP standard. For example, if the value of <code>pwdLastSet</code> is <code>0</code>, the Keycloak user must update their password. The result is an UPDATE_PASSWORD required action added to the user. If the value of <code>userAccountControl</code> is <code>514</code> (disabled account), the Keycloak user is disabled.</p> </dd> <dt class="hdlist1">Certificate Mapper</dt> <dd> <p>This mapper maps X.509 certificates. Keycloak uses it in conjunction with X.509 authentication and <code>Full certificate in PEM format</code> as an identity source. This mapper behaves similarly to the <code>User Attribute Mapper</code>, but Keycloak can filter for an LDAP attribute storing a PEM or DER format certificate. Enable <code>Always Read Value From LDAP</code> with this mapper.</p> </dd> </dl> </div> <div class="paragraph"> <p>User Attribute mappers that map basic Keycloak user attributes, such as username, firstname, lastname, and email, to corresponding LDAP attributes. You can extend these and provide your own additional attribute mappings. The Admin Console provides tooltips to help with configuring the corresponding mappers.</p> </div> </div> <div class="sect3"> <h4 id="_ldap_password_hashing"><a class="anchor" href="#_ldap_password_hashing"></a>Password hashing</h4> <div class="paragraph"> <p>When Keycloak updates a password, Keycloak sends the password in plain-text format. This action is different from updating the password in the built-in Keycloak database, where Keycloak hashes and salts the password before sending it to the database. For LDAP, Keycloak relies on the LDAP server to hash and salt the password.</p> </div> <div class="paragraph"> <p>By default, LDAP servers such as MSAD, RHDS, or FreeIPA hash and salt passwords. Other LDAP servers such as OpenLDAP or ApacheDS store the passwords in plain-text unless you use the <em>LDAPv3 Password Modify Extended Operation</em> as described in <a href="https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.3">RFC3062</a>. Enable the LDAPv3 Password Modify Extended Operation in the LDAP configuration page. See the documentation of your LDAP server for more details.</p> </div> <div class="admonitionblock warning"> <table> <tr> <td class="icon"> <i class="fa icon-warning" title="Warning"></i> </td> <td class="content"> Always verify that user passwords are properly hashed and not stored as plaintext by inspecting a changed directory entry using <code>ldapsearch</code> and base64 decode the <code>userPassword</code> attribute value. </td> </tr> </table> </div> </div> <div class="sect3"> <h4 id="_ldap_connection_pool"><a class="anchor" href="#_ldap_connection_pool"></a>Configuring the connection pool</h4> <div class="paragraph"> <p>For more efficiency when managing LDAP connections and to improve performance when handling multiple connections, you can enable connection pooling. By doing that, when a connection is closed, it will be returned to the pool for future use therefore reducing the cost of creating new connections all the time.</p> </div> <div class="paragraph"> <p>The LDAP connection pool configuration is configured using the following system properties:</p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 50%;"> <col style="width: 50%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Name</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>com.sun.jndi.ldap.connect.pool.authentication</code></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">A list of space-separated authentication types of connections that may be pooled. Valid types are "none", "simple", and "DIGEST-MD5"</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>com.sun.jndi.ldap.connect.pool.initsize</code></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The string representation of an integer that represents the number of connections per connection identity to create when initially creating a connection for the identity</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>com.sun.jndi.ldap.connect.pool.maxsize</code></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The string representation of an integer that represents the maximum number of connections per connection identity that can be maintained concurrently</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>com.sun.jndi.ldap.connect.pool.prefsize</code></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The string representation of an integer that represents the preferred number of connections per connection identity that should be maintained concurrently</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>com.sun.jndi.ldap.connect.pool.timeout</code></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The string representation of an integer that represents the number of milliseconds that an idle connection may remain in the pool without being closed and removed from the pool</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>com.sun.jndi.ldap.connect.pool.protocol</code></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">A list of space-separated protocol types of connections that may be pooled. Valid types are "plain" and "ssl"</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>com.sun.jndi.ldap.connect.pool.debug</code></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">A string that indicates the level of debug output to produce. Valid values are "fine" (trace connection creation and removal) and "all" (all debugging information)</p></td> </tr> </tbody> </table> <div class="paragraph"> <p>For more details, see the <a href="https://docs.oracle.com/javase/jndi/tutorial/ldap/connect/config.html">Java LDAP Connection Pooling Configuration</a> documentation.</p> </div> <div class="paragraph"> <p>To set any of these properties, you can set the <code>JAVA_OPTS_APPEND</code> environment variable:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">export JAVA_OPTS_APPEND=-Dcom.sun.jndi.ldap.connect.pool.initsize=10 -Dcom.sun.jndi.ldap.connect.pool.maxsize=50</code></pre> </div> </div> </div> <div class="sect3"> <h4 id="_ldap_troubleshooting"><a class="anchor" href="#_ldap_troubleshooting"></a>Troubleshooting</h4> <div class="paragraph"> <p>It is useful to increase the logging level to TRACE for the category <code>org.keycloak.storage.ldap</code>. With this setting, many logging messages are sent to the server log in the <code>TRACE</code> level, including the logging for all queries to the LDAP server and the parameters, which were used to send the queries. When you are creating any LDAP question on user forum or JIRA, consider attaching the server log with enabled TRACE logging. If it is too big, the good alternative is to include just the snippet from server log with the messages, which were added to the log during the operation, which causes the issues to you.</p> </div> <div class="ulist"> <ul> <li> <p>When you create an LDAP provider, a message appears in the server log in the INFO level starting with:</p> </li> </ul> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>Creating new LDAP Store for the LDAP storage provider: ...</code></pre> </div> </div> <div class="paragraph"> <p>It shows the configuration of your LDAP provider. Before you are asking the questions or reporting bugs, it will be nice to include this message to show your LDAP configuration. Eventually feel free to replace some config changes, which you do not want to include, with some placeholder values. One example is <code>bindDn=some-placeholder</code> . For <code>connectionUrl</code>, feel free to replace it as well, but it is generally useful to include at least the protocol, which was used (<code>ldap</code> vs <code>ldaps</code>)`. Similarly it can be useful to include the details for configuration of your LDAP mappers, which are displayed with the message like this at the DEBUG level:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>Mapper for provider: XXX, Mapper name: YYY, Provider: ZZZ ...</code></pre> </div> </div> <div class="paragraph"> <p>Note those messages are displayed just with the enabled DEBUG logging.</p> </div> <div class="ulist"> <ul> <li> <p>For tracking the performance or connection pooling issues, consider setting the value of property <code>com.sun.jndi.ldap.connect.pool.debug</code> to <code>all</code>. This change adds many additional messages to the server log with the included logging for the LDAP connection pooling. As a result, you can track the issues related to connection pooling or performance. For more details, see <a href="#_ldap_connection_pool">Configuring the connection pool</a>.</p> </li> </ul> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> After changing the configuration of connection pooling, you may need to restart the Keycloak server to enforce re-initialization of the LDAP provider connection. </td> </tr> </table> </div> <div class="paragraph"> <p>If no more messages appear for connection pooling even after server restart, it can indicate that connection pooling does not work with your LDAP server.</p> </div> <div class="ulist"> <ul> <li> <p>For the case of reporting LDAP issue, you may consider to attach some part of your LDAP tree with the target data, which causes issues in your environment. For example if login of some user takes lot of time, you can consider attach his LDAP entry showing count of <code>member</code> attributes of various "group" entries. In this case, it might be useful to add if those group entries are mapped to some Group LDAP mapper (or Role LDAP Mapper) in Keycloak and so on.</p> </li> </ul> </div> </div> </div> <div class="sect2"> <h3 id="_sssd"><a class="anchor" href="#_sssd"></a>SSSD and FreeIPA Identity Management integration</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/user-federation/sssd.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/user-federation/sssd.adoc&amp;description=%0A%0AFile:%20server_admin/topics/user-federation/sssd.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Keycloak includes the <a href="https://fedoraproject.org/wiki/Features/SSSD">System Security Services Daemon (SSSD)</a> plugin. SSSD is part of the Fedora and Red Hat Enterprise Linux (RHEL), and it provides access to multiple identities and authentication providers. SSSD also provides benefits such as failover and offline support. For more information, see <a href="https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/7/html/system-level_authentication_guide/sssd">the Red Hat Enterprise Linux Identity Management documentation</a>.</p> </div> <div class="paragraph"> <p>SSSD integrates with the FreeIPA identity management (IdM) server, providing authentication and access control. With this integration, Keycloak can authenticate against privileged access management (PAM) services and retrieve user data from SSSD. For more information about using Red Hat Identity Management in Linux environments, see <a href="https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/7/html/linux_domain_identity_authentication_and_policy_guide/index">the Red Hat Enterprise Linux Identity Management documentation</a>.</p> </div> <div class="paragraph"> <p><span class="image"><img src="./images/keycloak-sssd-freeipa-integration-overview.png" alt="keycloak sssd freeipa integration overview"></span></p> </div> <div class="paragraph"> <p>Keycloak and SSSD communicate through read-only D-Bus interfaces. For this reason, the way to provision and update users is to use the FreeIPA/IdM administration interface. By default, the interface imports the username, email, first name, and last name.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>Keycloak registers groups and roles automatically but does not synchronize them. Any changes made by the Keycloak administrator in Keycloak do not synchronize with SSSD.</p> </div> </td> </tr> </table> </div> <div class="sect3"> <h4 id="freeipaidm-server"><a class="anchor" href="#freeipaidm-server"></a>FreeIPA/IdM server</h4> <div class="paragraph"> <p>The <a href="https://quay.io/repository/freeipa/freeipa-server?tab=tags/">FreeIPA Container image</a> is available at <a href="https://quay.io/">Quay.io</a>. To set up the FreeIPA server, see the <a href="https://www.freeipa.org/page/Quick_Start_Guide">FreeIPA documentation</a>.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Run your FreeIPA server using this command:</p> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash"> docker run --name freeipa-server-container -it \ -h server.freeipa.local -e PASSWORD=YOUR_PASSWORD \ -v /sys/fs/cgroup:/sys/fs/cgroup:ro \ -v /var/lib/ipa-data:/data:Z freeipa/freeipa-server</code></pre> </div> </div> <div class="paragraph"> <p>The parameter <code>-h</code> with <code>server.freeipa.local</code> represents the FreeIPA/IdM server hostname. Change <code>YOUR_PASSWORD</code> to a password of your own.</p> </div> </li> <li> <p>After the container starts, change the <code>/etc/hosts</code> file to include:</p> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">x.x.x.x server.freeipa.local</code></pre> </div> </div> <div class="paragraph"> <p>If you do not make this change, you must set up a DNS server.</p> </div> </li> <li> <p>Use the following command to enroll your Linux server in the IPA domain so that the SSSD federation provider starts and runs on Keycloak:</p> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash"> ipa-client-install --mkhomedir -p admin -w password</code></pre> </div> </div> </li> <li> <p>Run the following command on the client to verify the installation is working:</p> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash"> kinit admin</code></pre> </div> </div> </li> <li> <p>Enter your password.</p> </li> <li> <p>Add users to the IPA server using this command:</p> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">$ ipa user-add &lt;username&gt; --first=&lt;first name&gt; --last=&lt;surname&gt; --email=&lt;email address&gt; --phone=&lt;telephoneNumber&gt; --street=&lt;street&gt; --city=&lt;city&gt; --state=&lt;state&gt; --postalcode=&lt;postal code&gt; --password</code></pre> </div> </div> </li> <li> <p>Force set the user&#8217;s password using kinit.</p> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash"> kinit &lt;username&gt;</code></pre> </div> </div> </li> <li> <p>Enter the following to restore normal IPA operation:</p> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">kdestroy -A kinit admin</code></pre> </div> </div> </li> </ol> </div> </div> <div class="sect3"> <h4 id="sssd-and-d-bus"><a class="anchor" href="#sssd-and-d-bus"></a>SSSD and D-Bus</h4> <div class="paragraph"> <p>The federation provider obtains the data from SSSD using D-BUS. It authenticates the data using PAM.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Install the sssd-dbus RPM.</p> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">$ sudo yum install sssd-dbus</code></pre> </div> </div> </li> <li> <p>Run the following provisioning script:</p> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">$ bin/federation-sssd-setup.sh</code></pre> </div> </div> <div class="paragraph"> <p>The script can also be used as a guide to configure SSSD and PAM for Keycloak. It makes the following changes to <code>/etc/sssd/sssd.conf</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash"> [domain/your-hostname.local] ... ldap_user_extra_attrs = mail:mail, sn:sn, givenname:givenname, telephoneNumber:telephoneNumber ... [sssd] services = nss, sudo, pam, ssh, ifp ... [ifp] allowed_uids = root, yourOSUsername user_attributes = +mail, +telephoneNumber, +givenname, +sn</code></pre> </div> </div> <div class="paragraph"> <p>The <code>ifp</code> service is added to SSSD and configured to allow the OS user to interrogate the IPA server through this interface.</p> </div> <div class="paragraph"> <p>The script also creates a new PAM service <code>/etc/pam.d/keycloak</code> to authenticate users via SSSD:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">auth required pam_sss.so account required pam_sss.so</code></pre> </div> </div> </li> <li> <p>Run <code>dbus-send</code> to ensure the setup is successful.</p> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">dbus-send --print-reply --system --dest=org.freedesktop.sssd.infopipe /org/freedesktop/sssd/infopipe org.freedesktop.sssd.infopipe.GetUserAttr string:&lt;username&gt; array:string:mail,givenname,sn,telephoneNumber dbus-send --print-reply --system --dest=org.freedesktop.sssd.infopipe /org/freedesktop/sssd/infopipe org.freedesktop.sssd.infopipe.GetUserGroups string:&lt;username&gt;</code></pre> </div> </div> <div class="paragraph"> <p>If the setup is successful, each command displays the user&#8217;s attributes and groups respectively. If there is a timeout or an error, the federation provider running on Keycloak cannot retrieve any data. This error usually happens because the server is not enrolled in the FreeIPA IdM server, or does not have permission to access the SSSD service.</p> </div> <div class="paragraph"> <p>If you do not have permission to access the SSSD service, ensure that the user running the Keycloak server is in the <code>/etc/sssd/sssd.conf</code> file in the following section:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">[ifp] allowed_uids = root, yourOSUsername</code></pre> </div> </div> <div class="paragraph"> <p>And the <code>ipaapi</code> system user is created inside the host. This user is necessary for the <code>ifp</code> service. Check the user is created in the system.</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">grep ipaapi /etc/passwd ipaapi:x:992:988:IPA Framework User:/:/sbin/nologin</code></pre> </div> </div> </li> </ol> </div> </div> <div class="sect3"> <h4 id="enabling-the-sssd-federation-provider"><a class="anchor" href="#enabling-the-sssd-federation-provider"></a>Enabling the SSSD federation provider</h4> <div class="paragraph"> <p>Keycloak uses <a href="https://github.com/hypfvieh/dbus-java">DBus-Java</a> project to communicate at a low level with D-Bus and <a href="https://github.com/java-native-access/jna">JNA</a> to authenticate via Operating System Pluggable Authentication Modules (PAM).</p> </div> <div class="paragraph"> <p>Although now Keycloak contains all the needed libraries to run the <code>SSSD</code> provider, JDK version 21 is needed. Therefore the <code>SSSD</code> provider will only be displayed when the host configuration is correct and JDK 21 is used to run Keycloak.</p> </div> </div> <div class="sect3"> <h4 id="configuring-a-federated-sssd-store"><a class="anchor" href="#configuring-a-federated-sssd-store"></a>Configuring a federated SSSD store</h4> <div class="paragraph"> <p>After the installation, configure a federated SSSD store.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>User Federation</strong> in the menu.</p> </li> <li> <p>If everything is setup successfully the <strong>Add Sssd providers</strong> button will be displayed in the page. Click on it.</p> </li> <li> <p>Assign a name to the new provider.</p> </li> <li> <p>Click <strong>Save</strong>.</p> </li> </ol> </div> <div class="paragraph"> <p>You can now authenticate against Keycloak using a FreeIPA/IdM user and credentials.</p> </div> </div> </div> <div class="sect2"> <h3 id="custom-providers"><a class="anchor" href="#custom-providers"></a>Custom providers</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/user-federation/custom.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/user-federation/custom.adoc&amp;description=%0A%0AFile:%20server_admin/topics/user-federation/custom.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Keycloak does have a Service Provider Interface (SPI) for User Storage Federation to develop custom providers. You can find documentation on developing customer providers in the <a href="https://www.keycloak.org/docs/26.0.6/server_development/">Server Developer Guide</a>.</p> </div> </div> </div> </div> <div class="sect1"> <h2 id="assembly-managing-users_server_administration_guide"><a class="anchor" href="#assembly-managing-users_server_administration_guide"></a>Managing users</h2> <div class="sectionbody"> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/assembly-managing-users.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/assembly-managing-users.adoc&amp;description=%0A%0AFile:%20server_admin/topics/assembly-managing-users.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>From the Admin Console, you have a wide range of actions you can perform to manage users.</p> </div> <div class="sect2"> <h3 id="proc-creating-user_server_administration_guide"><a class="anchor" href="#proc-creating-user_server_administration_guide"></a>Creating users</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/users/proc-creating-user.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/users/proc-creating-user.adoc&amp;description=%0A%0AFile:%20server_admin/topics/users/proc-creating-user.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>You create users in the realm where you intend to have applications needed by those users. Avoid creating users in the master realm, which is only intended for creating other realms.</p> </div> <div class="ulist"> <div class="title">Prerequisite</div> <ul> <li> <p>You are in a realm other than the master realm.</p> </li> </ul> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Users</strong> in the menu.</p> </li> <li> <p>Click <strong>Add User</strong>.</p> </li> <li> <p>Enter the details for the new user.</p> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <strong>Username</strong> is the only required field. </td> </tr> </table> </div> </li> <li> <p>Click <strong>Save</strong>. After saving the details, the <strong>Management</strong> page for the new user is displayed.</p> </li> </ol> </div> </div> <div class="sect2"> <h3 id="user-profile"><a class="anchor" href="#user-profile"></a>Managing user attributes</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/users/user-profile.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/users/user-profile.adoc&amp;description=%0A%0AFile:%20server_admin/topics/users/user-profile.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>In Keycloak a user is associated with a set of attributes. These attributes are used to better describe and identify users within Keycloak as well as to pass over additional information about them to applications.</p> </div> <div class="paragraph"> <p>A user profile defines a well-defined schema for representing user attributes and how they are managed within a realm. By providing a consistent view over user information, it allows administrators to control the different aspects on how attributes are managed as well as to make it much easier to extend Keycloak to support additional attributes.</p> </div> <div class="paragraph"> <p>Although the user profile is mainly targeted for attributes that end-users can manage (e.g.: first and last names, phone, etc) it also serves for managing any other metadata you want to associate with your users.</p> </div> <div class="paragraph"> <p>Among other capabilities, user profile enables administrators to:</p> </div> <div class="ulist"> <ul> <li> <p>Define a schema for user attributes</p> </li> <li> <p>Define whether an attribute is required based on contextual information (e.g.: if required only for users, or admins, or both, or depending on the scope being requested.)</p> </li> <li> <p>Define specific permissions for viewing and editing user attributes, making possible to adhere to strong privacy requirements where some attributes can not be seen or be changed by third-parties (including administrators)</p> </li> <li> <p>Dynamically enforce user profile compliance so that user information is always updated and in compliance with the metadata and rules associated with attributes</p> </li> <li> <p>Define validation rules on a per-attribute basis by leveraging the built-in validators or writing custom ones</p> </li> <li> <p>Dynamically render forms that users interact with like registration, update profile, brokering, and personal information in the account console, according to the attribute definitions and without any need to manually change themes.</p> </li> <li> <p>Customize user management interfaces in the administration console so that attributes are rendered dynamically based on the user profile schema</p> </li> </ul> </div> <div class="paragraph"> <p>The user profile schema or configuration uses a <a href="#_user-profile-json-configuration">JSON</a> format to represent attributes and their metadata. From the administration console, you are able to manage the configuration by clicking on the <code>Realm Settings</code> on the left side menu and then clicking on the <code>User Profile</code> tab on that page.</p> </div> <div class="paragraph"> <p>In the next sections, we&#8217;ll be looking at how to create your own user profile schema or configuration, and how to manage attributes.</p> </div> <div class="sect3"> <h4 id="understanding-the-default-configuration"><a class="anchor" href="#understanding-the-default-configuration"></a>Understanding the Default Configuration</h4> <div class="paragraph"> <p>By default, Keycloak provides a basic user profile configuration covering some of the most common user attributes:</p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 50%;"> <col style="width: 50%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Name</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>username</code></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The username</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>email</code></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">End-User&#8217;s preferred e-mail address.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>firstName</code></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Given name(s) or first name(s) of the end-user</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>lastName</code></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Surname(s) or last name(s) of the End-User</p></td> </tr> </tbody> </table> <div class="paragraph"> <p>In Keycloak, both <code>username</code> and <code>email</code> attributes have a special handling as they are often used to identify, authenticate, and link user accounts. For those attributes, you are limited to changing their settings, and you can not remove them.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>The behavior of both <code>username</code> and <code>email</code> attributes changes accordingly to the <code>Login</code> settings of your realm. For instance, changing the <code>Email as username</code> or the <code>Edit username</code> settings will override any configuration you have set in the user profile configuration.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>As you will see in the following sections, you are free to change the default configuration by bringing your own attributes or changing the settings for any of the available attributes to better fit it to your needs.</p> </div> </div> <div class="sect3"> <h4 id="understanding-the-user-profile-contexts"><a class="anchor" href="#understanding-the-user-profile-contexts"></a>Understanding the User Profile Contexts</h4> <div class="paragraph"> <p>In Keycloak, users are managed through different contexts:</p> </div> <div class="ulist"> <ul> <li> <p>Registration</p> </li> <li> <p>Update Profile</p> </li> <li> <p>Reviewing Profile when authenticating through a broker or social provider</p> </li> <li> <p>Account Console</p> </li> <li> <p>Administrative (e.g.: administration console and Admin REST API)</p> </li> </ul> </div> <div class="paragraph"> <p>Except for the <code>Administrative</code> context, all other contexts are considered end-user contexts as they are related to user self-service flows.</p> </div> <div class="paragraph"> <p>Knowing these contexts is important to understand where your user profile configuration will take effect when managing users. Regardless of the context where the user is being managed, the same user profile configuration will be used to render UIs and validate attribute values.</p> </div> <div class="paragraph"> <p>As you will see in the following sections, you might restrict certain attributes to be available only from the administrative context and disable them completely for end-users. The other way around is also true if you don&#8217;t want administrators to have access to certain user attributes but only the end-user.</p> </div> </div> <div class="sect3"> <h4 id="_understanding-managed-and-unmanaged-attributes"><a class="anchor" href="#_understanding-managed-and-unmanaged-attributes"></a>Understanding Managed and Unmanaged Attributes</h4> <div class="paragraph"> <p>By default, Keycloak will only recognize the attributes defined in your user profile configuration. The server ignores any other attribute not explicitly defined there.</p> </div> <div class="paragraph"> <p>By being strict about which user attributes can be set to your users, as well as how their values are validated, Keycloak can add another defense barrier to your realm and help you to prevent unexpected attributes and values associated to your users.</p> </div> <div class="paragraph"> <p>That said, user attributes can be categorized as follows:</p> </div> <div class="ulist"> <ul> <li> <p><strong>Managed</strong>. These are attributes controlled by your user profile, to which you want to allow end-users and administrators to manage from any user profile context. For these attributes, you want complete control on how and when they are managed.</p> </li> <li> <p><strong>Unmanaged</strong>. These are attributes you do not explicitly define in your user profile so that they are completely ignored by Keycloak, by default.</p> </li> </ul> </div> <div class="paragraph"> <p>Although unmanaged attributes are disabled by default, you can configure your realm using different policies to define how they are handled by the server. For that, click on the <code>Realm Settings</code> at the left side menu, click on the <code>General</code> tab, and then choose any of the following options from the <code>Unmanaged Attributes</code> setting:</p> </div> <div class="ulist"> <ul> <li> <p><strong>Disabled</strong>. This is the default policy so that unmanaged attributes are disabled from all user profile contexts.</p> </li> <li> <p><strong>Enabled</strong>. This policy enables unmanaged attributes to all user profile contexts.</p> </li> <li> <p><strong>Admin can view</strong>. This policy enables unmanaged attributes only from the administrative context as read-only.</p> </li> <li> <p><strong>Admin can edit</strong>. This policy enables unmanaged attributes only from the administrative context for reads and writes.</p> </li> </ul> </div> <div class="paragraph"> <p>These policies give you a fine-grained control over how the server will handle unmanaged attributes. You can choose to completely disable or only support unmanaged attributes when managing users through the administrative context.</p> </div> <div class="paragraph"> <p>When unmanaged attributes are enabled (even if partially) you can manage them from the administration console at the <code>Attributes</code> tab in the User Details UI. If the policy is set to <code>Disabled</code> this tab is not available.</p> </div> <div class="paragraph"> <p>As a security recommendation, try to adhere to the most strict policy as much as possible (e.g.: <code>Disabled</code> or <code>Admin can edit</code>) to prevent unexpected attributes (and values) set to your users when they are managing their profile through end-user contexts. Avoid setting the <code>Enabled</code> policy and prefer defining all the attributes that end-users can manage in your user profile configuration, under your control.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>The <code>Enabled</code> policy is targeted for realms migrating from previous versions of Keycloak and to avoid breaking behavior when using custom themes and extending the server with their own custom user attributes.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>As you will see in the following sections, you can also restrict the audience for an attribute by choosing if it should be visible or writable by users and/or administrators.</p> </div> <div class="paragraph"> <p>For unmanaged attributes, the maximum length is 2048 characters. To specify a different minimum or maximum length, change the unmanaged attribute to a managed attribute and add a <code>length</code> validator.</p> </div> <div class="admonitionblock warning"> <table> <tr> <td class="icon"> <i class="fa icon-warning" title="Warning"></i> </td> <td class="content"> Keycloak caches user-related objects in its internal caches. The longer the attributes are, the more memory the cache consumes. Therefore, limiting the size of the length attributes is recommended. Consider storing large objects outside Keycloak and reference them by ID or URL. </td> </tr> </table> </div> </div> <div class="sect3"> <h4 id="managing-the-user-profile"><a class="anchor" href="#managing-the-user-profile"></a>Managing the User Profile</h4> <div class="paragraph"> <p>The user profile configuration is managed on a per-realm basis. For that, click on the <code>Realm Settings</code> link on the left side menu and then click on the <code>User Profile</code> tab.</p> </div> <div class="paragraph"> <div class="title">User Profile Tab</div> <p><span class="image"><img src="./images/user-profile-tab.png" alt="user profile tab"></span></p> </div> <div class="paragraph"> <p>In the <code>Attributes</code> sub-tab you have a list of all managed attributes.</p> </div> <div class="paragraph"> <p>In the <code>Attribute Groups</code> sub-tab you can manage attribute groups. An attribute group allows you to correlate attributes so that they are displayed together when rendering user facing forms.</p> </div> <div class="paragraph"> <p>In the <code>JSON Editor</code> sub-tab you can view and edit the <a href="#_user-profile-json-configuration">JSON</a> configuration. You can use this tab to grab your current configuration or manage it manually. Any change you make to this tab is reflected in the other tabs, and vice-versa.</p> </div> <div class="paragraph"> <p>In the next section, you are going to learn how to manage attributes.</p> </div> </div> <div class="sect3"> <h4 id="managing-attributes"><a class="anchor" href="#managing-attributes"></a>Managing Attributes</h4> <div class="paragraph"> <p>At the <code>Attributes</code> sub-tab you can create, edit, and delete the managed attributes.</p> </div> <div class="paragraph"> <p>To define a new attribute and associate it with the user profile, click on the <strong>Create attribute</strong> button at the top of the attribute listing.</p> </div> <div class="paragraph"> <div class="title">Attribute Configuration</div> <p><span class="image"><img src="./images/user-profile-create-attribute.png" alt="user profile create attribute"></span></p> </div> <div class="paragraph"> <p>When configuring the attribute you can define the following settings:</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Name</dt> <dd> <p>The name of the attribute, used to uniquely identify an attribute.</p> </dd> <dt class="hdlist1">Display name</dt> <dd> <p>A user-friendly name for the attribute, mainly used when rendering user-facing forms. It also supports <a href="#_using-internationalized-messages">Using Internationalized Messages</a></p> </dd> <dt class="hdlist1">Multivalued</dt> <dd> <p>If enabled, the attribute supports multiple values and UIs are rendered accordingly to allow setting many values. When enabling this setting, make sure to add a validator to set a hard limit to the number of values.</p> </dd> <dt class="hdlist1">Attribute Group</dt> <dd> <p>The attribute group to which the attribute belongs to, if any.</p> </dd> <dt class="hdlist1">Enabled when</dt> <dd> <p>Enables or disables an attribute. If set to <code>Always</code>, the attribute is available from any user profile context. If set to <code>Scopes are requested</code>, the attribute is only available when the client acting on behalf of the user is requesting a set of one or more scopes. You can use this option to dynamically enforce certain attributes depending on the client scopes being requested. For the account and administration consoles, scopes are not evaluated and the attribute is always enabled. That is because filtering attributes by scopes only works when running authentication flows.</p> </dd> <dt class="hdlist1">Required</dt> <dd> <p>Set the conditions to mark an attribute as required. If disabled, the attribute is optional. If enabled, you can set the <code>Required for</code> setting to mark the attribute as required depending on the user profile context so that the attribute is required for end-users (via end-user contexts) or to administrators (via administrative context), or both. You can also set the <code>Required when</code> setting to mark the attribute as required only when a set of one or more client scopes are requested. If set to <code>Always</code>, the attribute is required from any user profile context. If set to <code>Scopes are requested</code>, the attribute is only required when the client acting on behalf of the user is requesting a set of one or more scopes. For the account and administration consoles, scopes are not evaluated and the attribute is not required. That is because filtering attributes by scopes only works when running authentication flows.</p> </dd> <dt class="hdlist1">Permission</dt> <dd> <p>In this section, you can define read and write permissions when the attribute is being managed from an end-user or administrative context. The <code>Who can edit</code> setting mark an attribute as writable by <code>User</code> and/or <code>Admin</code>, from an end-user and administrative context, respectively. The <code>Who can view</code> setting mark an attribute as read-only by <code>User</code> and/or <code>Admin</code> from an end-user and administrative context, respectively.</p> </dd> <dt class="hdlist1">Validation</dt> <dd> <p>In this section, you can define the validations that will be performed when managing the attribute value. Keycloak provides a set of built-in validators you can choose from with the possibility to add your own. For more details, look at the <a href="#_validating-attributes">Validating Attributes</a> section.</p> </dd> <dt class="hdlist1">Annotation</dt> <dd> <p>In this section, you can associate annotations to the attribute. Annotations are mainly useful to pass over additional metadata to frontends for rendering purposes. For more details, look at the <a href="#_defining-ui-annotations">Defining UI Annotations</a> section.</p> </dd> </dl> </div> <div class="paragraph"> <p>When you create an attribute, the attribute is only available from administrative contexts to avoid unexpectedly exposing attributes to end-users. Effectively, the attribute won&#8217;t be accessible to end-users when they are managing their profile through the end-user contexts. You can change the <code>Permissions</code> settings anytime accordingly to your needs.</p> </div> </div> <div class="sect3"> <h4 id="_validating-attributes"><a class="anchor" href="#_validating-attributes"></a>Validating Attributes</h4> <div class="paragraph"> <p>You can enable validation to managed attributes to make sure the attribute value conforms to specific rules. For that, you can add or remove validators from the <code>Validations</code> settings when managing an attribute.</p> </div> <div class="paragraph"> <div class="title">Attribute Validation</div> <p><span class="image"><img src="./images/user-profile-validation.png" alt="user profile validation"></span></p> </div> <div class="paragraph"> <p>Validation happens at any time when writing to an attribute, and they can throw errors that will be shown in UIs when the value fails a validation.</p> </div> <div class="paragraph"> <p>For security reasons, every attribute that is editable by users should have a validation to restrict the size of the values users enter. If no <code>length</code> validator has been specified, Keycloak defaults to a maximum length of 2048 characters.</p> </div> <div class="sect4"> <h5 id="built-in-validators"><a class="anchor" href="#built-in-validators"></a>Built-in Validators</h5> <div class="paragraph"> <p>Keycloak provides some built-in validators that you can choose from, and you are also able to provide your own validators by extending the <code>Validator SPI</code>.</p> </div> <div class="paragraph"> <p>The list below provides a list of all the built-in validators:</p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 33.3333%;"> <col style="width: 33.3333%;"> <col style="width: 33.3334%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Name</th> <th class="tableblock halign-left valign-top">Description</th> <th class="tableblock halign-left valign-top">Configuration</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">length</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Check the length of a string value based on a minimum and maximum length.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>min</strong>: an integer to define the minimum allowed length.</p> <p class="tableblock"><strong>max</strong>: an integer to define the maximum allowed length.</p> <p class="tableblock"><strong>trim-disabled</strong>: a boolean to define whether the value is trimmed prior to validation.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">integer</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Check if the value is an integer and within a lower and/or upper range. If no range is defined, the validator only checks whether the value is a valid number.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>min</strong>: an integer to define the lower range.</p> <p class="tableblock"><strong>max</strong>: an integer to define the upper range.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">double</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Check if the value is a double and within a lower and/or upper range. If no range is defined, the validator only checks whether the value is a valid number.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>min</strong>: an integer to define the lower range.</p> <p class="tableblock"><strong>max</strong>: an integer to define the upper range.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">uri</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Check if the value is a valid URI.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">None</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">pattern</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Check if the value matches a specific RegEx pattern.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>pattern</strong>: the RegEx pattern to use when validating values.</p> <p class="tableblock"><strong>error-message</strong>: the key of the error message in i18n bundle. If not set a generic message is used.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">email</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Check if the value has a valid e-mail format.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>max-local-length</strong>: an integer to define the maximum length for the local part of the email. It defaults to 64 per specification.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">local-date</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Check if the value has a valid format based on the realm and/or user locale.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">None</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">iso-date</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Check if the value has a valid format based on ISO 8601. This validator can be used with inputs using the html5-date input type.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">None</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">person-name-prohibited-characters</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Check if the value is a valid person name as an additional barrier for attacks such as script injection. The validation is based on a default RegEx pattern that blocks characters not common in person names.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>error-message</strong>: the key of the error message in i18n bundle. If not set a generic message is used.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">username-prohibited-characters</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Check if the value is a valid username as an additional barrier for attacks such as script injection. The validation is based on a default RegEx pattern that blocks characters not common in usernames. When the realm setting <code>Email as username</code> is enabled, this validator is skipped to allow email values.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>error-message</strong>: the key of the error message in i18n bundle. If not set a generic message is used.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">options</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Check if the value is from the defined set of allowed values. Useful to validate values entered through select and multiselect fields.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>options</strong>: array of strings containing allowed values.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">up-username-not-idn-homograph</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The field can contain only latin characters and common unicode characters. Useful for the fields, which can be subject of IDN homograph attacks (typically username).</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>error-message</strong>: the key of the error message in i18n bundle. If not set a generic message is used.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">multivalued</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Validates the size of a multivalued attribute.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>min</strong>: an integer to define the minimum allowed count of attribute values.</p> <p class="tableblock"><strong>max</strong>: an integer to define the maximum allowed count of attribute values.</p></td> </tr> </tbody> </table> </div> </div> <div class="sect3"> <h4 id="_defining-ui-annotations"><a class="anchor" href="#_defining-ui-annotations"></a>Defining UI Annotations</h4> <div class="paragraph"> <p>In order to pass additional information to frontends, attributes can be decorated with annotations to dictate how attributes are rendered. This capability is mainly useful when extending Keycloak themes to render pages dynamically based on the annotations associated with attributes.</p> </div> <div class="paragraph"> <p>Annotations are used, for example, for <a href="#_changing-the-html-type-for-an-attribute">Changing the HTML <code>type</code> for an Attribute</a> and <a href="#_changing-the-dom-representation-of-an-attribute">Changing the DOM representation of an Attribute</a>, as you will see in the following sections.</p> </div> <div class="paragraph"> <div class="title">Attribute Annotation</div> <p><span class="image"><img src="./images/user-profile-annotation.png" alt="user profile annotation"></span></p> </div> <div class="paragraph"> <p>An annotation is a key/value pair shared with the UI so that they can change how the HTML element corresponding to the attribute is rendered. You can set any annotation you want to an attribute as long as the annotation is supported by the theme your realm is using.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>The only restriction you have is to avoid using annotations using the <code>kc</code> prefix in their keys because these annotations using this prefix are reserved for Keycloak.</p> </div> </td> </tr> </table> </div> <div class="sect4"> <h5 id="built-in-annotations"><a class="anchor" href="#built-in-annotations"></a>Built-in Annotations</h5> <div class="paragraph"> <p>The following annotations are supported by Keycloak built-in themes:</p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 50%;"> <col style="width: 50%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Name</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">inputType</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Type of the form input field. Available types are described in a table below.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">inputHelperTextBefore</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Helper text rendered before (above) the input field. Direct text or internationalization pattern (like <code>${i18n.key}</code>) can be used here. Text is NOT html escaped when rendered into the page, so you can use html tags here to format the text, but you also have to correctly escape html control characters.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">inputHelperTextAfter</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Helper text rendered after (under) the input field. Direct text or internationalization pattern (like <code>${i18n.key}</code>) can be used here. Text is NOT html escaped when rendered into the page, so you can use html tags here to format the text, but you also have to correctly escape html control characters.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">inputOptionsFromValidation</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Annotation for select and multiselect types. Optional name of custom attribute validation to get input options from. See <a href="#_managing_options_for_select_fields">detailed description</a> below.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">inputOptionLabelsI18nPrefix</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Annotation for select and multiselect types. Internationalization key prefix to render options in UI. See <a href="#_managing_options_for_select_fields">detailed description</a> below.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">inputOptionLabels</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Annotation for select and multiselect types. Optional map to define UI labels for options (directly or using internationalization). See <a href="#_managing_options_for_select_fields">detailed description</a> below.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">inputTypePlaceholder</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">HTML input <code>placeholder</code> attribute applied to the field - specifies a short hint that describes the expected value of an input field (e.g. a sample value or a short description of the expected format). The short hint is displayed in the input field before the user enters a value.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">inputTypeSize</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">HTML input <code>size</code> attribute applied to the field - specifies the width, in characters, of a single line input field. For fields based on HTML <code>select</code> type it specifies number of rows with options shown. May not work, depending on css in used theme!</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">inputTypeCols</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">HTML input <code>cols</code> attribute applied to the field - specifies the width, in characters, for <code>textarea</code> type. May not work, depending on css in used theme!</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">inputTypeRows</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">HTML input <code>rows</code> attribute applied to the field - specifies the height, in characters, for <code>textarea</code> type. For select fields it specifies number of rows with options shown. May not work, depending on css in used theme!</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">inputTypePattern</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">HTML input <code>pattern</code> attribute applied to the field providing client side validation - specifies a regular expression that an input field&#8217;s value is checked against. Useful for single line inputs.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">inputTypeMaxLength</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">HTML input <code>maxlength</code> attribute applied to the field providing client side validation - maximal length of the text which can be entered into the input field. Useful for text fields.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">inputTypeMinLength</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">HTML input <code>minlength</code> attribute applied to the field providing client side validation - minimal length of the text which can be entered into the input field. Useful for text fields.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">inputTypeMax</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">HTML input <code>max</code> attribute applied to the field providing client side validation - maximal value which can be entered into the input field. Useful for numeric fields.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">inputTypeMin</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">HTML input <code>min</code> attribute applied to the field providing client side validation - minimal value which can be entered into the input field. Useful for numeric fields.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">inputTypeStep</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">HTML input <code>step</code> attribute applied to the field - Specifies the interval between legal numbers in an input field. Useful for numeric fields.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Number Format</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">If set, the <code>data-kcNumberFormat</code> attribute is added to the field to format the value based on a given format. This annotation is targeted for numbers where the format is based on the number of digits expected in a determined position. For instance, a format <code>({2}) {5}-{4}</code> will format the field value to <code>(00) 00000-0000</code>.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Number UnFormat</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">If set, the <code>data-kcNumberUnFormat</code> attribute is added to the field to format the value based on a given format before submitting the form. This annotation is useful if you do not want to store any format for a specific attribute but only format the value on the client side. For instance, if the current value is <code>(00) 00000-0000</code>, the value will change to <code>00000000000</code> if you set the value <code>{11}</code> to this annotation or any other format you want by specifying a set of one or more group of digits. Make sure to add validators to perform server-side validations before storing values.</p></td> </tr> </tbody> </table> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>Field types use HTML form field tags and attributes applied to them - they behave based on the HTML specifications and browser support for them.</p> </div> <div class="paragraph"> <p>Visual rendering also depends on css styles applied in the used theme.</p> </div> </td> </tr> </table> </div> </div> <div class="sect4"> <h5 id="_changing-the-html-type-for-an-attribute"><a class="anchor" href="#_changing-the-html-type-for-an-attribute"></a>Changing the HTML <code>type</code> for an Attribute</h5> <div class="paragraph"> <p>You can change the <code>type</code> of a HTML5 input element by setting the <code>inputType</code> annotation. The available types are:</p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 33.3333%;"> <col style="width: 33.3333%;"> <col style="width: 33.3334%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Name</th> <th class="tableblock halign-left valign-top">Description</th> <th class="tableblock halign-left valign-top">HTML tag used</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">text</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Single line text input.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">input</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">textarea</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Multiple line text input.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">textarea</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">select</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Common single select input. See <a href="#_managing_options_for_select_fields">description how to configure options</a> below.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">select</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">select-radiobuttons</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Single select input through group of radio buttons. See <a href="#_managing_options_for_select_fields">description how to configure options</a> below.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">group of input</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">multiselect</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Common multiselect input. See <a href="#_managing_options_for_select_fields">description how to configure options</a> below.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">select</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">multiselect-checkboxes</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Multiselect input through group of checkboxes. See <a href="#_managing_options_for_select_fields">description how to configure options</a> below.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">group of input</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">html5-email</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Single line text input for email address based on HTML 5 spec.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">input</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">html5-tel</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Single line text input for phone number based on HTML 5 spec.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">input</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">html5-url</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Single line text input for URL based on HTML 5 spec.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">input</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">html5-number</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Single line input for number (integer or float depending on <code>step</code>) based on HTML 5 spec.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">input</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">html5-range</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Slider for number entering based on HTML 5 spec.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">input</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">html5-datetime-local</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Date Time input based on HTML 5 spec.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">input</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">html5-date</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Date input based on HTML 5 spec.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">input</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">html5-month</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Month input based on HTML 5 spec.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">input</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">html5-week</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Week input based on HTML 5 spec.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">input</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">html5-time</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Time input based on HTML 5 spec.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">input</p></td> </tr> </tbody> </table> </div> <div class="sect4"> <h5 id="_managing_options_for_select_fields"><a class="anchor" href="#_managing_options_for_select_fields"></a>Defining options for select and multiselect fields</h5> <div class="paragraph"> <p>Options for select and multiselect fields are taken from validation applied to the attribute to be sure validation and field options presented in UI are always consistent. By default, options are taken from built-in <code>options</code> validation.</p> </div> <div class="paragraph"> <p>You can use various ways to provide nice human-readable labels for select and multiselect options. The simplest case is when attribute values are same as UI labels. No extra configuration is necessary in this case.</p> </div> <div class="paragraph"> <div class="title">Option values same as UI labels</div> <p><span class="image"><img src="./images/user-profile-select-options-simple.png" alt="user profile select options simple"></span></p> </div> <div class="paragraph"> <p>When attribute value is kind of ID not suitable for UI, you can use simple internationalization support provided by <code>inputOptionLabelsI18nPrefix</code> annotation. It defines prefix for internationalization keys, option value is dot appended to this prefix.</p> </div> <div class="paragraph"> <div class="title">Simple internationalization for UI labels using i18n key prefix</div> <p><span class="image"><img src="./images/user-profile-select-options-simple-i18n.png" alt="user profile select options simple i18n"></span></p> </div> <div class="paragraph"> <p>Localized UI label texts for option value have to be provided by <code>userprofile.jobtitle.sweng</code> and <code>userprofile.jobtitle.swarch</code> keys then, using common localization mechanism.</p> </div> <div class="paragraph"> <p>You can also use <code>inputOptionLabels</code> annotation to provide labels for individual options. It contains a map of labels for option - key in the map is option value (defined in validation), and value in the map is UI label text itself or its internationalization pattern (like <code>${i18n.key}</code>) for that option.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>You have to use User Profile <code>JSON Editor</code> to enter map as <code>inputOptionLabels</code> annotation value.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>Example of directly entered labels for individual options without internationalization:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="json"><span class="key"><span class="delimiter">&quot;</span><span class="content">attributes</span><span class="delimiter">&quot;</span></span>: [ <span class="error">&lt;</span><span class="error">.</span><span class="error">.</span><span class="error">.</span> { <span class="key"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">jobTitle</span><span class="delimiter">&quot;</span></span>, <span class="key"><span class="delimiter">&quot;</span><span class="content">validations</span><span class="delimiter">&quot;</span></span>: { <span class="key"><span class="delimiter">&quot;</span><span class="content">options</span><span class="delimiter">&quot;</span></span>: { <span class="key"><span class="delimiter">&quot;</span><span class="content">options</span><span class="delimiter">&quot;</span></span>:[ <span class="string"><span class="delimiter">&quot;</span><span class="content">sweng</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">swarch</span><span class="delimiter">&quot;</span></span> ] } }, <span class="key"><span class="delimiter">&quot;</span><span class="content">annotations</span><span class="delimiter">&quot;</span></span>: { <span class="key"><span class="delimiter">&quot;</span><span class="content">inputType</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">select</span><span class="delimiter">&quot;</span></span>, <span class="key"><span class="delimiter">&quot;</span><span class="content">inputOptionLabels</span><span class="delimiter">&quot;</span></span>: { <span class="key"><span class="delimiter">&quot;</span><span class="content">sweng</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">Software Engineer</span><span class="delimiter">&quot;</span></span>, <span class="key"><span class="delimiter">&quot;</span><span class="content">swarch</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">Software Architect</span><span class="delimiter">&quot;</span></span> } } } <span class="error">.</span><span class="error">.</span><span class="error">.</span> ]</code></pre> </div> </div> <div class="paragraph"> <p>Example of the internationalized labels for individual options:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="json"><span class="key"><span class="delimiter">&quot;</span><span class="content">attributes</span><span class="delimiter">&quot;</span></span>: [ <span class="error">.</span><span class="error">.</span><span class="error">.</span> { <span class="key"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">jobTitle</span><span class="delimiter">&quot;</span></span>, <span class="key"><span class="delimiter">&quot;</span><span class="content">validations</span><span class="delimiter">&quot;</span></span>: { <span class="key"><span class="delimiter">&quot;</span><span class="content">options</span><span class="delimiter">&quot;</span></span>: { <span class="key"><span class="delimiter">&quot;</span><span class="content">options</span><span class="delimiter">&quot;</span></span>:[ <span class="string"><span class="delimiter">&quot;</span><span class="content">sweng</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">swarch</span><span class="delimiter">&quot;</span></span> ] } }, <span class="key"><span class="delimiter">&quot;</span><span class="content">annotations</span><span class="delimiter">&quot;</span></span>: { <span class="key"><span class="delimiter">&quot;</span><span class="content">inputType</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">select-radiobuttons</span><span class="delimiter">&quot;</span></span>, <span class="key"><span class="delimiter">&quot;</span><span class="content">inputOptionLabels</span><span class="delimiter">&quot;</span></span>: { <span class="key"><span class="delimiter">&quot;</span><span class="content">sweng</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">${jobtitle.swengineer}</span><span class="delimiter">&quot;</span></span>, <span class="key"><span class="delimiter">&quot;</span><span class="content">swarch</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">${jobtitle.swarchitect}</span><span class="delimiter">&quot;</span></span> } } } <span class="error">.</span><span class="error">.</span><span class="error">.</span> ]</code></pre> </div> </div> <div class="paragraph"> <p>Localized texts have to be provided by <code>jobtitle.swengineer</code> and <code>jobtitle.swarchitect</code> keys then, using common localization mechanism.</p> </div> <div class="paragraph"> <p>Custom validator can be used to provide options thanks to <code>inputOptionsFromValidation</code> attribute annotation. This validation have to have <code>options</code> config providing array of options. Internationalization works the same way as for options provided by built-in <code>options</code> validation.</p> </div> <div class="paragraph"> <div class="title">Options provided by custom validator</div> <p><span class="image"><img src="./images/user-profile-select-options-custom-validator.png" alt="user profile select options custom validator"></span></p> </div> </div> <div class="sect4"> <h5 id="_changing-the-dom-representation-of-an-attribute"><a class="anchor" href="#_changing-the-dom-representation-of-an-attribute"></a>Changing the DOM representation of an Attribute</h5> <div class="paragraph"> <p>You can enable additional client-side behavior by setting annotations with the <code>kc</code> prefix. These annotations are going to translate into an HTML attribute in the corresponding element of an attribute, prefixed with <code>data-</code>, and a script with the same name will be loaded to the dynamic pages so that you can select elements from the DOM based on the custom <code>data-</code> attribute and decorate them accordingly by modifying their DOM representation.</p> </div> <div class="paragraph"> <p>For instance, if you add a <code>kcMyCustomValidation</code> annotation to an attribute, the HTML attribute <code>data-kcMyCustomValidation</code> is added to the corresponding HTML element for the attribute, and a JavaScript module is loaded from your custom theme at <code>&lt;THEME TYPE&gt;/resources/js/kcMyCustomValidation.js</code>. See the <a href="https://www.keycloak.org/docs/26.0.6/server_development/">Server Developer Guide</a> for more information about how to deploy a custom JavaScript module to your theme.</p> </div> <div class="paragraph"> <p>The JavaScript module can run any code to customize the DOM and the elements rendered for each attribute. For that, you can use the <code>userProfile.js</code> module to register an annotation descriptor for your custom annotation as follows:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="javascript"><span class="reserved">import</span> { registerElementAnnotatedBy } from <span class="string"><span class="delimiter">&quot;</span><span class="content">./userProfile.js</span><span class="delimiter">&quot;</span></span>; registerElementAnnotatedBy({ <span class="key">name</span>: <span class="string"><span class="delimiter">'</span><span class="content">kcMyCustomValidation</span><span class="delimiter">'</span></span>, onAdd(element) { <span class="keyword">var</span> <span class="function">listener</span> = <span class="keyword">function</span> (event) { <span class="comment">// do something on keyup</span> }; element.addEventListener(<span class="string"><span class="delimiter">&quot;</span><span class="content">keyup</span><span class="delimiter">&quot;</span></span>, listener); <span class="comment">// returns a cleanup function to remove the event listener</span> <span class="keyword">return</span> () =&gt; element.removeEventListener(<span class="string"><span class="delimiter">&quot;</span><span class="content">keyup</span><span class="delimiter">&quot;</span></span>, listener); } });</code></pre> </div> </div> <div class="paragraph"> <p>The <code>registerElementAnnotatedBy</code> is a method to register annotation descriptors. A descriptor is an object with a <code>name</code>, referencing the annotation name, and a <code>onAdd</code> function. Whenever the page is rendered or an attribute with the annotation is added to the DOM, the <code>onAdd</code> function is invoked so that you can customize the behavior for the element.</p> </div> <div class="paragraph"> <p>The <code>onAdd</code> function can also return a function to perform a cleanup. For instance, if you are adding event listeners to elements, you might want to remove them in case the element is removed from the DOM.</p> </div> <div class="paragraph"> <p>Alternatively, you can also use any JavaScript code you want if the <code>userProfile.js</code> is not enough for your needs:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="javascript">document.querySelectorAll(<span class="error">`</span>[data-kcMyCustomValidation]<span class="error">`</span>).forEach((element) =&gt; { <span class="keyword">var</span> <span class="function">listener</span> = <span class="keyword">function</span> (evt) { <span class="comment">// do something on keyup</span> }; element.addEventListener(<span class="string"><span class="delimiter">&quot;</span><span class="content">keyup</span><span class="delimiter">&quot;</span></span>, listener); });</code></pre> </div> </div> </div> </div> <div class="sect3"> <h4 id="managing-attribute-groups"><a class="anchor" href="#managing-attribute-groups"></a>Managing Attribute Groups</h4> <div class="paragraph"> <p>At the <code>Attribute Groups</code> sub-tab you can create, edit, and delete attribute groups. An attribute group allows you to define a container for correlated attributes so that they are rendered together when at the user-facing forms.</p> </div> <div class="paragraph"> <div class="title">Attribute Group List</div> <p><span class="image"><img src="./images/user-profile-attribute-group-list.png" alt="user profile attribute group list"></span></p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>You can&#8217;t delete attribute groups that are bound to attributes. For that, you should first update the attributes to remove the binding.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>To create a new group, click on the <strong>Create attributes group</strong> button on the top of the attribute groups listing.</p> </div> <div class="paragraph"> <div class="title">Attribute Group Configuration</div> <p><span class="image"><img src="./images/user-profile-create-attribute-group.png" alt="user profile create attribute group"></span></p> </div> <div class="paragraph"> <p>When configuring the group you can define the following settings:</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Name</dt> <dd> <p>The name of the attribute, used to uniquely identify an attribute.</p> </dd> <dt class="hdlist1">Display name</dt> <dd> <p>A user-friendly name for the attribute, mainly used when rendering user-facing forms. It also supports <a href="#_using-internationalized-messages">Using Internationalized Messages</a></p> </dd> <dt class="hdlist1">Display description</dt> <dd> <p>A user-friendly text that will be displayed as a tooltip when rendering user-facing forms. It also supports <a href="#_using-internationalized-messages">Using Internationalized Messages</a></p> </dd> <dt class="hdlist1">Annotation</dt> <dd> <p>In this section, you can associate annotations to the attribute. Annotations are mainly useful to pass over additional metadata to frontends for rendering purposes.</p> </dd> </dl> </div> </div> <div class="sect3"> <h4 id="_user-profile-json-configuration"><a class="anchor" href="#_user-profile-json-configuration"></a>Using the JSON configuration</h4> <div class="paragraph"> <p>The user profile configuration is stored using a well-defined JSON schema. You can choose from editing the user profile configuration directly by clicking on the <code>JSON Editor</code> sub-tab.</p> </div> <div class="paragraph"> <div class="title">JSON Configuration</div> <p><span class="image"><img src="./images/user-profile-json-config.png" alt="user profile json config"></span></p> </div> <div class="paragraph"> <p>The JSON schema is defined as follows:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="json">{ <span class="key"><span class="delimiter">&quot;</span><span class="content">unmanagedAttributePolicy</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">DISABLED</span><span class="delimiter">&quot;</span></span>, <span class="key"><span class="delimiter">&quot;</span><span class="content">attributes</span><span class="delimiter">&quot;</span></span>: [ { <span class="key"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">myattribute</span><span class="delimiter">&quot;</span></span>, <span class="key"><span class="delimiter">&quot;</span><span class="content">multivalued</span><span class="delimiter">&quot;</span></span>: <span class="value">false</span>, <span class="key"><span class="delimiter">&quot;</span><span class="content">displayName</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">My Attribute</span><span class="delimiter">&quot;</span></span>, <span class="key"><span class="delimiter">&quot;</span><span class="content">group</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">personalInfo</span><span class="delimiter">&quot;</span></span>, <span class="key"><span class="delimiter">&quot;</span><span class="content">required</span><span class="delimiter">&quot;</span></span>: { <span class="key"><span class="delimiter">&quot;</span><span class="content">roles</span><span class="delimiter">&quot;</span></span>: [ <span class="string"><span class="delimiter">&quot;</span><span class="content">user</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">admin</span><span class="delimiter">&quot;</span></span> ], <span class="key"><span class="delimiter">&quot;</span><span class="content">scopes</span><span class="delimiter">&quot;</span></span>: [ <span class="string"><span class="delimiter">&quot;</span><span class="content">foo</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">bar</span><span class="delimiter">&quot;</span></span> ] }, <span class="key"><span class="delimiter">&quot;</span><span class="content">permissions</span><span class="delimiter">&quot;</span></span>: { <span class="key"><span class="delimiter">&quot;</span><span class="content">view</span><span class="delimiter">&quot;</span></span>: [ <span class="string"><span class="delimiter">&quot;</span><span class="content">admin</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">user</span><span class="delimiter">&quot;</span></span> ], <span class="key"><span class="delimiter">&quot;</span><span class="content">edit</span><span class="delimiter">&quot;</span></span>: [ <span class="string"><span class="delimiter">&quot;</span><span class="content">admin</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">user</span><span class="delimiter">&quot;</span></span> ] }, <span class="key"><span class="delimiter">&quot;</span><span class="content">validations</span><span class="delimiter">&quot;</span></span>: { <span class="key"><span class="delimiter">&quot;</span><span class="content">email</span><span class="delimiter">&quot;</span></span>: { <span class="key"><span class="delimiter">&quot;</span><span class="content">max-local-length</span><span class="delimiter">&quot;</span></span>: <span class="integer">64</span> }, <span class="key"><span class="delimiter">&quot;</span><span class="content">length</span><span class="delimiter">&quot;</span></span>: { <span class="key"><span class="delimiter">&quot;</span><span class="content">max</span><span class="delimiter">&quot;</span></span>: <span class="integer">255</span> } }, <span class="key"><span class="delimiter">&quot;</span><span class="content">annotations</span><span class="delimiter">&quot;</span></span>: { <span class="key"><span class="delimiter">&quot;</span><span class="content">myannotation</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">myannotation-value</span><span class="delimiter">&quot;</span></span> } } ], <span class="key"><span class="delimiter">&quot;</span><span class="content">groups</span><span class="delimiter">&quot;</span></span>: [ { <span class="key"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">personalInfo</span><span class="delimiter">&quot;</span></span>, <span class="key"><span class="delimiter">&quot;</span><span class="content">displayHeader</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">Personal Information</span><span class="delimiter">&quot;</span></span>, <span class="key"><span class="delimiter">&quot;</span><span class="content">annotations</span><span class="delimiter">&quot;</span></span>: { <span class="key"><span class="delimiter">&quot;</span><span class="content">foo</span><span class="delimiter">&quot;</span></span>: [<span class="string"><span class="delimiter">&quot;</span><span class="content">foo-value</span><span class="delimiter">&quot;</span></span>], <span class="key"><span class="delimiter">&quot;</span><span class="content">bar</span><span class="delimiter">&quot;</span></span>: [<span class="string"><span class="delimiter">&quot;</span><span class="content">bar-value</span><span class="delimiter">&quot;</span></span>] } } ] }</code></pre> </div> </div> <div class="paragraph"> <p>The schema supports as many attributes and groups as you need.</p> </div> <div class="paragraph"> <p>The <code>unmanagedAttributePolicy</code> property defines the unmanaged attribute policy by setting one of following values. For more details, look at the <a href="#_understanding-managed-and-unmanaged-attributes">Understanding Managed and Unmanaged Attributes</a>.</p> </div> <div class="ulist"> <ul> <li> <p><code>DISABLED</code></p> </li> <li> <p><code>ENABLED</code></p> </li> <li> <p><code>ADMIN_VIEW</code></p> </li> <li> <p><code>ADMIN_EDIT</code></p> </li> </ul> </div> <div class="sect4"> <h5 id="attribute-schema"><a class="anchor" href="#attribute-schema"></a>Attribute Schema</h5> <div class="paragraph"> <p>For each attribute you should define a <code>name</code> and, optionally, the <code>required</code>, <code>permission</code>, and the <code>annotations</code> settings.</p> </div> <div class="paragraph"> <p>The <code>required</code> property defines whether an attribute is required. Keycloak allows you to set an attribute as required based on different conditions.</p> </div> <div class="paragraph"> <p>When the <code>required</code> property is defined as an empty object, the attribute is always required.</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="json">{ <span class="key"><span class="delimiter">&quot;</span><span class="content">attributes</span><span class="delimiter">&quot;</span></span>: [ { <span class="key"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">myattribute</span><span class="delimiter">&quot;</span></span>, <span class="key"><span class="delimiter">&quot;</span><span class="content">required</span><span class="delimiter">&quot;</span></span>: {} ] }</code></pre> </div> </div> <div class="paragraph"> <p>On the other hand, you can choose to make the attribute required only for users, or administrators, or both. As well as mark the attribute as required only in case a specific scope is requested when the user is authenticating in Keycloak.</p> </div> <div class="paragraph"> <p>To mark an attribute as required for a user and/or administrator, set the <code>roles</code> property as follows:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="json">{ <span class="key"><span class="delimiter">&quot;</span><span class="content">attributes</span><span class="delimiter">&quot;</span></span>: [ { <span class="key"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">myattribute</span><span class="delimiter">&quot;</span></span>, <span class="key"><span class="delimiter">&quot;</span><span class="content">required</span><span class="delimiter">&quot;</span></span>: { <span class="key"><span class="delimiter">&quot;</span><span class="content">roles</span><span class="delimiter">&quot;</span></span>: [<span class="string"><span class="delimiter">&quot;</span><span class="content">user</span><span class="delimiter">&quot;</span></span>] } ] }</code></pre> </div> </div> <div class="paragraph"> <p>The <code>roles</code> property expects an array whose values can be either <code>user</code> or <code>admin</code>, depending on whether the attribute is required by the user or the administrator, respectively.</p> </div> <div class="paragraph"> <p>Similarly, you can choose to make the attribute required when a set of one or more scopes is requested by a client when authenticating a user. For that, you can use the <code>scopes</code> property as follows:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="json">{ <span class="key"><span class="delimiter">&quot;</span><span class="content">attributes</span><span class="delimiter">&quot;</span></span>: [ { <span class="key"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">myattribute</span><span class="delimiter">&quot;</span></span>, <span class="key"><span class="delimiter">&quot;</span><span class="content">required</span><span class="delimiter">&quot;</span></span>: { <span class="key"><span class="delimiter">&quot;</span><span class="content">scopes</span><span class="delimiter">&quot;</span></span>: [<span class="string"><span class="delimiter">&quot;</span><span class="content">foo</span><span class="delimiter">&quot;</span></span>] } ] }</code></pre> </div> </div> <div class="paragraph"> <p>The <code>scopes</code> property is an array whose values can be any string representing a client scope.</p> </div> <div class="paragraph"> <p>The attribute-level <code>permissions</code> property can be used to define the read and write permissions to an attribute. The permissions are set based on whether these operations can be performed on the attribute by a user, or administrator, or both.</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="json">{ <span class="key"><span class="delimiter">&quot;</span><span class="content">attributes</span><span class="delimiter">&quot;</span></span>: [ { <span class="key"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">myattribute</span><span class="delimiter">&quot;</span></span>, <span class="key"><span class="delimiter">&quot;</span><span class="content">permissions</span><span class="delimiter">&quot;</span></span>: { <span class="key"><span class="delimiter">&quot;</span><span class="content">view</span><span class="delimiter">&quot;</span></span>: [<span class="string"><span class="delimiter">&quot;</span><span class="content">admin</span><span class="delimiter">&quot;</span></span>], <span class="key"><span class="delimiter">&quot;</span><span class="content">edit</span><span class="delimiter">&quot;</span></span>: [<span class="string"><span class="delimiter">&quot;</span><span class="content">user</span><span class="delimiter">&quot;</span></span>] } ] }</code></pre> </div> </div> <div class="paragraph"> <p>Both <code>view</code> and <code>edit</code> properties expect an array whose values can be either <code>user</code> or <code>admin</code>, depending on whether the attribute is viewable or editable by the user or the administrator, respectively.</p> </div> <div class="paragraph"> <p>When the <code>edit</code> permission is granted, the <code>view</code> permission is implicitly granted.</p> </div> <div class="paragraph"> <p>The attribute-level <code>annotation</code> property can be used to associate additional metadata to attributes. Annotations are mainly useful for passing over additional information about attributes to frontends rendering user attributes based on the user profile configuration. Each annotation is a key/value pair.</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="json">{ <span class="key"><span class="delimiter">&quot;</span><span class="content">attributes</span><span class="delimiter">&quot;</span></span>: [ { <span class="key"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">myattribute</span><span class="delimiter">&quot;</span></span>, <span class="key"><span class="delimiter">&quot;</span><span class="content">annotations</span><span class="delimiter">&quot;</span></span>: { <span class="key"><span class="delimiter">&quot;</span><span class="content">foo</span><span class="delimiter">&quot;</span></span>: [<span class="string"><span class="delimiter">&quot;</span><span class="content">foo-value</span><span class="delimiter">&quot;</span></span>], <span class="key"><span class="delimiter">&quot;</span><span class="content">bar</span><span class="delimiter">&quot;</span></span>: [<span class="string"><span class="delimiter">&quot;</span><span class="content">bar-value</span><span class="delimiter">&quot;</span></span>] } ] }</code></pre> </div> </div> </div> <div class="sect4"> <h5 id="attribute-group-schema"><a class="anchor" href="#attribute-group-schema"></a>Attribute Group Schema</h5> <div class="paragraph"> <p>For each attribute group you should define a <code>name</code> and, optionally, the <code>annotations</code> settings.</p> </div> <div class="paragraph"> <p>The attribute-level <code>annotation</code> property can be used to associate additional metadata to attributes. Annotations are mainly useful for passing over additional information about attributes to frontends rendering user attributes based on the user profile configuration. Each annotation is a key/value pair.</p> </div> </div> </div> <div class="sect3"> <h4 id="customizing-how-uis-are-rendered"><a class="anchor" href="#customizing-how-uis-are-rendered"></a>Customizing How UIs are Rendered</h4> <div class="paragraph"> <p>The UIs from all the user profile contexts (including the administration console) are rendered dynamically accordingly to your user profile configuration.</p> </div> <div class="paragraph"> <p>The default rendering mechanism provides the following capabilities:</p> </div> <div class="ulist"> <ul> <li> <p>Show or hide fields based on the permissions set to attributes.</p> </li> <li> <p>Render markers for required fields based on the constraints set to the attributes.</p> </li> <li> <p>Change the field input type (text, date, number, select, multiselect) set to an attribute.</p> </li> <li> <p>Mark fields as read-only depending on the permissions set to an attribute.</p> </li> <li> <p>Order fields depending on the order set to the attributes.</p> </li> <li> <p>Group fields that belong to the same attribute group.</p> </li> <li> <p>Dynamically group fields that belong to the same attribute group.</p> </li> </ul> </div> <div class="sect4"> <h5 id="ordering-attributes"><a class="anchor" href="#ordering-attributes"></a>Ordering attributes</h5> <div class="paragraph"> <p>The attribute order is set by dragging and dropping the attribute rows on the attribute listing page.</p> </div> <div class="paragraph"> <div class="title">Ordering Attributes</div> <p><span class="image"><img src="./images/user-profile-attribute-list-order.png" alt="user profile attribute list order"></span></p> </div> <div class="paragraph"> <p>The order you set in this page is respected when fields are rendered in dynamic forms.</p> </div> </div> <div class="sect4"> <h5 id="grouping-attributes"><a class="anchor" href="#grouping-attributes"></a>Grouping attributes</h5> <div class="paragraph"> <p>When dynamic forms are rendered, they will try to group together attributes that belong to the same attribute group.</p> </div> <div class="paragraph"> <div class="title">Dynamic Update Profile Form</div> <p><span class="image"><img src="./images/user-profile-update-profile.png" alt="user profile update profile"></span></p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>When attributes are linked to an attribute group, the attribute order is also important to make sure attributes within the same group are close together, within a same group header. Otherwise, if attributes within a group do not have a sequential order you might have the same group header rendered multiple times in the dynamic form.</p> </div> </td> </tr> </table> </div> </div> </div> <div class="sect3"> <h4 id="enabling-progressive-profiling"><a class="anchor" href="#enabling-progressive-profiling"></a>Enabling Progressive Profiling</h4> <div class="paragraph"> <p>In order to make sure end-user profiles are in compliance with the configuration, administrators can use the <code>VerifyProfile</code> required action to eventually force users to update their profiles when authenticating to Keycloak.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>The <code>VerifyProfile</code> action is similar to the <code>UpdateProfile</code> action. However, it leverages all the capabilities provided by the user profile to automatically enforce compliance with the user profile configuration.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>When enabled, the <code>VerifyProfile</code> action is going to perform the following steps when the user is authenticating:</p> </div> <div class="ulist"> <ul> <li> <p>Check whether the user profile is fully compliant with the user profile configuration set to the realm. That means running validations and make sure all of them are successful.</p> </li> <li> <p>If not, perform an additional step during the authentication so that the user can update any missing or invalid attribute.</p> </li> <li> <p>If the user profile is compliant with the configuration, no additional step is performed, and the user continues with the authentication process.</p> </li> </ul> </div> <div class="paragraph"> <p>The <code>VerifyProfile</code> action is enabled by default. To disable it, click on the <code>Authentication</code> link on the left side menu and then click on the <code>Required Actions</code> tab. At this tab, use the <strong>Enabled</strong> switch of the <code>VerifyProfile</code> action to disable it.</p> </div> <div class="paragraph"> <div class="title">Registering the VerifyProfile Required Action</div> <p><span class="image"><img src="./images/user-profile-register-verify-profile-action.png" alt="user profile register verify profile action"></span></p> </div> </div> <div class="sect3"> <h4 id="_using-internationalized-messages"><a class="anchor" href="#_using-internationalized-messages"></a>Using Internationalized Messages</h4> <div class="paragraph"> <p>If you want to use internationalized messages when configuring attributes, attributes groups, and annotations, you can set their display name, description, and values, using a placeholder that will translate to a message from a message bundle.</p> </div> <div class="paragraph"> <p>For that, you can use a placeholder to resolve messages keys such as <code>${myAttributeName}</code>, where <code>myAttributeName</code> is the key for a message in a message bundle. For more details, look at <a href="https://www.keycloak.org/docs/26.0.6/server_development/#messages">Server Developer Guide</a> about how to add message bundles to custom themes.</p> </div> </div> </div> <div class="sect2"> <h3 id="ref-user-credentials_server_administration_guide"><a class="anchor" href="#ref-user-credentials_server_administration_guide"></a>Defining user credentials</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/users/ref-user-credentials.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/users/ref-user-credentials.adoc&amp;description=%0A%0AFile:%20server_admin/topics/users/ref-user-credentials.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>You can manage credentials of a user in the <strong>Credentials</strong> tab.</p> </div> <div class="paragraph"> <div class="title">Credential management</div> <p><span class="image"><img src="./images/user-credentials.png" alt="user credentials"></span></p> </div> <div class="paragraph"> <p>You change the priority of credentials by dragging and dropping rows. The new order determines the priority of the credentials for that user. The topmost credential has the highest priority. The priority determines which credential is displayed first after a user logs in.</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Type</dt> <dd> <p>This column displays the type of credential, for example <strong>password</strong> or <strong>OTP</strong>.</p> </dd> <dt class="hdlist1">User Label</dt> <dd> <p>This is an assignable label to recognize the credential when presented as a selection option during login. It can be set to any value to describe the credential.</p> </dd> <dt class="hdlist1">Data</dt> <dd> <p>This is the non-confidential technical information about the credential. It is hidden, by default. You can click <strong>Show data&#8230;&#8203;</strong> to display the data for a credential.</p> </dd> <dt class="hdlist1">Actions</dt> <dd> <p>Click <strong>Reset password</strong> to change the password for the user and <strong>Delete</strong> to remove the credential.</p> </dd> </dl> </div> <div class="paragraph"> <p>You cannot configure other types of credentials for a specific user in the Admin Console; that task is the user&#8217;s responsibility.</p> </div> <div class="paragraph"> <p>You can delete the credentials of a user in the event a user loses an OTP device or if credentials have been compromised. You can only delete credentials of a user in the <strong>Credentials</strong> tab.</p> </div> <div class="sect3"> <h4 id="proc-setting-password-user_server_administration_guide"><a class="anchor" href="#proc-setting-password-user_server_administration_guide"></a>Setting a password for a user</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/users/proc-setting-password-user.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/users/proc-setting-password-user.adoc&amp;description=%0A%0AFile:%20server_admin/topics/users/proc-setting-password-user.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>If a user does not have a password, or if the password has been deleted, the <strong>Set Password</strong> section is displayed.</p> </div> <div class="paragraph"> <p>If a user already has a password, it can be reset in the <strong>Reset Password</strong> section.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Users</strong> in the menu. The <strong>Users</strong> page is displayed.</p> </li> <li> <p>Select a user.</p> </li> <li> <p>Click the <strong>Credentials</strong> tab.</p> </li> <li> <p>Type a new password in the <strong>Set Password</strong> section.</p> </li> <li> <p>Click <strong>Set Password</strong>.</p> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> If <strong>Temporary</strong> is <strong>ON</strong>, the user must change the password at the first login. To allow users to keep the password supplied, set <strong>Temporary</strong> to <strong>OFF.</strong> The user must click <strong>Set Password</strong> to change the password. </td> </tr> </table> </div> </li> </ol> </div> </div> <div class="sect3"> <h4 id="requesting-a-user-reset-a-password"><a class="anchor" href="#requesting-a-user-reset-a-password"></a>Requesting a user reset a password</h4> <div class="paragraph"> <p>You can also request that the user reset the password.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Users</strong> in the menu. The <strong>Users</strong> page is displayed.</p> </li> <li> <p>Select a user.</p> </li> <li> <p>Click the <strong>Credentials</strong> tab.</p> </li> <li> <p>Click <strong>Credential Reset</strong>.</p> </li> <li> <p>Select <strong>Update Password</strong> from the list.</p> </li> <li> <p>Click <strong>Send Email</strong>. The sent email contains a link that directs the user to the <strong>Update Password</strong> window.</p> </li> <li> <p>Optionally, you can set the validity of the email link. This is set to the default preset in the <strong>Tokens</strong> tab in <strong>Realm Settings</strong>.</p> </li> </ol> </div> </div> <div class="sect3"> <h4 id="proc_creating-otp_server_administration_guide"><a class="anchor" href="#proc_creating-otp_server_administration_guide"></a>Creating an OTP</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/users/proc-creating-otp.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/users/proc-creating-otp.adoc&amp;description=%0A%0AFile:%20server_admin/topics/users/proc-creating-otp.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>If OTP is conditional in your realm, the user must navigate to Keycloak Account Console to reconfigure a new OTP generator. If OTP is required, then the user must reconfigure a new OTP generator when logging in.</p> </div> <div class="paragraph"> <p>Alternatively, you can send an email to the user that requests the user reset the OTP generator. The following procedure also applies if the user already has an OTP credential.</p> </div> <div class="ulist"> <div class="title">Prerequisite</div> <ul> <li> <p>You are logged in to the appropriate realm.</p> </li> </ul> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Users</strong> in the main menu. The <strong>Users</strong> page is displayed.</p> </li> <li> <p>Select a user.</p> </li> <li> <p>Click the <strong>Credentials</strong> tab.</p> </li> <li> <p>Click <strong>Credential Reset</strong>.</p> </li> <li> <p>Set <strong>Reset Actions</strong> to <strong>Configure OTP</strong>.</p> </li> <li> <p>Click <strong>Send Email</strong>. The sent email contains a link that directs the user to the <strong>OTP setup page</strong>.</p> </li> </ol> </div> </div> </div> <div class="sect2"> <h3 id="con-user-registration_server_administration_guide"><a class="anchor" href="#con-user-registration_server_administration_guide"></a>Allowing users to self-register</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/users/con-user-registration.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/users/con-user-registration.adoc&amp;description=%0A%0AFile:%20server_admin/topics/users/con-user-registration.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>You can use Keycloak as a third-party authorization server to manage application users, including users who self-register. If you enable self-registration, the login page displays a registration link so that user can create an account.</p> </div> <div class="paragraph"> <div class="title">Registration link</div> <p><span class="image"><img src="./images/registration-link.png" alt="registration link"></span></p> </div> <div class="paragraph"> <p>A user must add profile information to the registration form to complete registration. The registration form can be customized by removing or adding the fields that must be completed by a user.</p> </div> <div class="paragraph"> <div class="title">Clarification on identity brokering and admin API</div> <p>Even when self-registrations is disabled, new users can be still added to Keycloak by either:</p> </div> <div class="ulist"> <ul> <li> <p>Administrator can add new users with the usage of admin console (or admin REST API)</p> </li> <li> <p>When identity brokering is enabled, new users authenticated by identity provider may be automatically added/registered in Keycloak storage. See the <a href="#_identity_broker_first_login">First login flow section in the Identity Brokering chapter</a> for more information.</p> </li> </ul> </div> <div class="paragraph"> <p>Also users coming from the <a href="#_user-storage-federation">3rd-party user storage</a> (for example LDAP) are automatically available in Keycloak when the particular user storage is enabled</p> </div> <div class="ulist _additional-resources"> <div class="title">Additional resources</div> <ul> <li> <p>For more information on customizing user registration, see the <a href="https://www.keycloak.org/docs/26.0.6/server_development/">Server Developer Guide</a>.</p> </li> </ul> </div> <div class="sect3"> <h4 id="proc-enabling-user-registration_server_administration_guide"><a class="anchor" href="#proc-enabling-user-registration_server_administration_guide"></a>Enabling user registration</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/users/proc-enabling-user-registration.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/users/proc-enabling-user-registration.adoc&amp;description=%0A%0AFile:%20server_admin/topics/users/proc-enabling-user-registration.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>Enable users to self-register.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Realm Settings</strong> in the main menu.</p> </li> <li> <p>Click the <strong>Login</strong> tab.</p> </li> <li> <p>Toggle <strong>User Registration</strong> to <strong>ON</strong>.</p> </li> </ol> </div> <div class="paragraph"> <p>After you enable this setting, a <strong>Register</strong> link displays on the login page of the Admin Console.</p> </div> </div> <div class="sect3"> <h4 id="proc-registering-new-user_server_administration_guide"><a class="anchor" href="#proc-registering-new-user_server_administration_guide"></a>Registering as a new user</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/users/proc-registering-new-user.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/users/proc-registering-new-user.adoc&amp;description=%0A%0AFile:%20server_admin/topics/users/proc-registering-new-user.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>As a new user, you must complete a registration form to log in for the first time. You add profile information and a password to register.</p> </div> <div class="paragraph"> <div class="title">Registration form</div> <p><span class="image"><img src="./images/registration-form.png" alt="registration form"></span></p> </div> <div class="ulist"> <div class="title">Prerequisite</div> <ul> <li> <p>User registration is enabled.</p> </li> </ul> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click the <strong>Register</strong> link on the login page. The registration page is displayed.</p> </li> <li> <p>Enter the user profile information.</p> </li> <li> <p>Enter the new password.</p> </li> <li> <p>Click <strong>Register</strong>.</p> </li> </ol> </div> </div> <div class="sect3"> <h4 id="proc-requiring-tac-agreement-at-registration_server_administration_guide"><a class="anchor" href="#proc-requiring-tac-agreement-at-registration_server_administration_guide"></a>Requiring user to agree to terms and conditions during registration</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/users/proc-requiring-tac-agreement-at-registration.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/users/proc-requiring-tac-agreement-at-registration.adoc&amp;description=%0A%0AFile:%20server_admin/topics/users/proc-requiring-tac-agreement-at-registration.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>For a user to register, you can require agreement to your terms and conditions.</p> </div> <div class="paragraph"> <div class="title">Registration form with required terms and conditions agreement</div> <p><span class="image"><img src="./images/registration-form-with-required-tac.png" alt="registration form with required tac"></span></p> </div> <div class="ulist"> <div class="title">Prerequisite</div> <ul> <li> <p>User registration is enabled.</p> </li> <li> <p>Terms and conditions required action is enabled.</p> </li> </ul> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Authentication</strong> in the menu. Click the <strong>Flows</strong> tab.</p> </li> <li> <p>Click the <strong>registration</strong> flow.</p> </li> <li> <p>Select <strong>Required</strong> on the <strong>Terms and Conditions</strong> row.</p> <div class="paragraph"> <div class="title">Make the terms and conditions agreement required at registration</div> <p><span class="image"><img src="./images/require-tac-agreement-at-registration.png" alt="require tac agreement at registration"></span></p> </div> </li> </ol> </div> </div> </div> <div class="sect2"> <h3 id="con-required-actions_server_administration_guide"><a class="anchor" href="#con-required-actions_server_administration_guide"></a>Defining actions required at login</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/users/con-required-actions.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/users/con-required-actions.adoc&amp;description=%0A%0AFile:%20server_admin/topics/users/con-required-actions.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>You can set the actions that a user must perform at the first login. These actions are required after the user provides credentials. After the first login, these actions are no longer required. You add required actions on the <strong>Details</strong> tab of that user.</p> </div> <div class="paragraph"> <p>Some required actions are automatically triggered for the user during login even if they are not explicitly added to this user by the administrator. For example <code>Update password</code> action can be triggered if <a href="#_password-policies">Password policies</a> are configured in a way that the user password needs to be changed every X days. Or <code>verify profile</code> action can require the user to update the <a href="#user-profile">User profile</a> as long as some user attributes do not match the requirements according to the user profile configuration.</p> </div> <div class="paragraph"> <p>The following are examples of required action types:</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Update Password</dt> <dd> <p>The user must change their password.</p> </dd> <dt class="hdlist1">Configure OTP</dt> <dd> <p>The user must configure a one-time password generator on their mobile device using either the Free OTP or Google Authenticator application.</p> </dd> <dt class="hdlist1">Verify Email</dt> <dd> <p>The user must verify their email account. An email will be sent to the user with a validation link that they must click. Once this workflow is successfully completed, the user will be allowed to log in.</p> </dd> <dt class="hdlist1">Update Profile</dt> <dd> <p>The user must update profile information, such as name, address, email, and phone number.</p> </dd> </dl> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> Some actions do not makes sense to be added to the user account directly. For example, the <code>Update User Locale</code> is a helper action to handle some localization related parameters. Another example is the <code>Delete Credential</code> action, which is supposed to be triggered as a <a href="#con-aia-parameterized_server_administration_guide">Parameterized AIA</a>. Regarding this one, if the administrator wants to delete the credential of some user, that administrator can do it directly in the Admin Console. The <code>Delete Credential</code> action is dedicated to be used for example by the <a href="#_account-service">Keycloak Account Console</a>. </td> </tr> </table> </div> <div class="sect3"> <h4 id="proc-setting-required-actions_server_administration_guide"><a class="anchor" href="#proc-setting-required-actions_server_administration_guide"></a>Setting required actions for one user</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/users/proc-setting-required-actions.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/users/proc-setting-required-actions.adoc&amp;description=%0A%0AFile:%20server_admin/topics/users/proc-setting-required-actions.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>You can set the actions that are required for any user.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Users</strong> in the menu.</p> </li> <li> <p>Select a user from the list.</p> </li> <li> <p>Navigate to the <strong>Required User Actions</strong> list.</p> <div class="paragraph"> <p><span class="image"><img src="./images/user-required-action.png" alt="user required action"></span></p> </div> </li> <li> <p>Select all the actions you want to add to the account.</p> </li> <li> <p>Click the <strong>X</strong> next to the action name to remove it.</p> </li> <li> <p>Click <strong>Save</strong> after you select which actions to add.</p> </li> </ol> </div> </div> <div class="sect3"> <h4 id="proc-setting-default-required-actions_server_administration_guide"><a class="anchor" href="#proc-setting-default-required-actions_server_administration_guide"></a>Setting required actions for all users</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/users/proc-setting-default-required-actions.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/users/proc-setting-default-required-actions.adoc&amp;description=%0A%0AFile:%20server_admin/topics/users/proc-setting-default-required-actions.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>You can specify what actions are required before the first login of all new users. The requirements apply to a user created by the <strong>Add User</strong> button on the <strong>Users</strong> page or the <strong>Register</strong> link on the login page.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Authentication</strong> in the menu.</p> </li> <li> <p>Click the <strong>Required Actions</strong> tab.</p> </li> <li> <p>Click the checkbox in the <strong>Set as default action</strong> column for one or more required actions. When a new user logs in for the first time, the selected actions must be executed.</p> </li> </ol> </div> </div> <div class="sect3"> <h4 id="proc-enabling-terms-conditions_server_administration_guide"><a class="anchor" href="#proc-enabling-terms-conditions_server_administration_guide"></a>Enabling terms and conditions as a required action</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/users/proc-enabling-terms-conditions.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/users/proc-enabling-terms-conditions.adoc&amp;description=%0A%0AFile:%20server_admin/topics/users/proc-enabling-terms-conditions.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>You can enable a required action that new users must accept the terms and conditions before logging in to Keycloak for the first time.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Authentication</strong> in the menu.</p> </li> <li> <p>Click the <strong>Required Actions</strong> tab.</p> </li> <li> <p>Enable the <strong>Terms and Conditions</strong> action.</p> </li> <li> <p>Edit the <code>terms.ftl</code> file in the base login theme.</p> </li> </ol> </div> <div class="ulist"> <div class="title">Additional resources</div> <ul> <li> <p>For more information on extending and creating themes, see the <a href="https://www.keycloak.org/docs/26.0.6/server_development/">Server Developer Guide</a>.</p> </li> </ul> </div> </div> </div> <div class="sect2"> <h3 id="con-aia_server_administration_guide"><a class="anchor" href="#con-aia_server_administration_guide"></a>Application initiated actions</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/users/con-aia.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/users/con-aia.adoc&amp;description=%0A%0AFile:%20server_admin/topics/users/con-aia.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Application initiated actions (AIA) allow client applications to request a user to perform an action on the Keycloak side. Usually, when an OIDC client application wants a user to log in, it redirects that user to the login URL as described in the <a href="#con-oidc_server_administration_guide">OIDC section</a>. After login, the user is redirected back to the client application. The user performs the actions that were required by the administrator as described in the <a href="#proc-setting-required-actions_server_administration_guide">previous section</a> and then is immediately redirected back to the application. However, AIA allows the client application to request some required actions from the user during login. This can be done even if the user is already authenticated on the client and has an active SSO session. It is triggered by adding the <code>kc_action</code> parameter to the OIDC login URL with the value containing the requested action. For instance <code>kc_action=UPDATE_PASSWORD</code> parameter.</p> </div> <div class="paragraph"> <p>A user may cancel an application initiated action. In this case the user is redirected back to the client application. The redirect URI will contain the query parameters <code>kc_action_status=cancelled</code> and <code>kc_action</code> with the name of the cancelled action.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> The <code>kc_action</code> and <code>kc_action_status</code> parameters are a Keycloak proprietary mechanism unsupported by the OIDC specification. </td> </tr> </table> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> Application initiated actions are supported only for OIDC clients. </td> </tr> </table> </div> <div class="paragraph"> <p>So if AIA is used, an example flow is similar to the following:</p> </div> <div class="ulist"> <ul> <li> <p>A client application redirects the user to the OIDC login URL with the additional parameter such as <code>kc_action=UPDATE_PASSWORD</code></p> </li> <li> <p>There is a <code>browser</code> flow always triggered as described in the <a href="#_authentication-flows">Authentication flows section</a>. If the user was not authenticated, that user needs to authenticate as during normal login. In case the user was already authenticated, that user might be automatically re-authenticated by an SSO cookie without needing to actively re-authenticate and supply the credentials again. In this case, that user will be directly redirected to the screen with the particular action (update password in this case). However, in some cases, active re-authentication is required even if the user has an SSO cookie (See <a href="#con-aia-reauth_server_administration_guide">below</a> for the details).</p> </li> <li> <p>The screen with particular action (in this case <code>update password</code>) is displayed to the user, so that user needs to perform a particular action</p> </li> <li> <p>Then user is redirected back to the client application</p> </li> </ul> </div> <div class="paragraph"> <p>Note that AIA are used by the Keycloak <a href="#_account-service">Account Console</a> to request update password or to reset other credentials such as OTP or WebAuthn.</p> </div> <div class="admonitionblock warning"> <table> <tr> <td class="icon"> <i class="fa icon-warning" title="Warning"></i> </td> <td class="content"> Even if the parameter <code>kc_action</code> was used, it is not sufficient to assume that the user always performs the action. For example, a user could have manually deleted the <code>kc_action</code> parameter from the browser URL. Therefore, no guarantee exists that the user has an OTP for the account after the client requested <code>kc_action=CONFIGURE_TOTP</code>. If you want to verify that the user configured two-factor authenticator, the client application may need to check it was configured. For instance by checking the claims like <code>acr</code> in the tokens. </td> </tr> </table> </div> <div class="sect3"> <h4 id="con-aia-reauth_server_administration_guide"><a class="anchor" href="#con-aia-reauth_server_administration_guide"></a>Re-authentication during AIA</h4> <div class="paragraph"> <p>In case the user is already authenticated due to an active SSO session, that user usually does not need to actively re-authenticate. However, if that user actively authenticated longer than five minutes ago, the client can still request re-authentication when some AIA is requested. Exceptions exist from this guideline as follows:</p> </div> <div class="ulist"> <ul> <li> <p>The action <code>delete_account</code> will always require the user to actively re-authenticate</p> </li> <li> <p>The action <code>update_password</code> might require the user to actively re-authenticate according to the configured <a href="#maximum-authentication-age">Maximum Authentication Age Password policy</a>. In case the policy is not configured, it is also possible to configure it on the required action itself in the <a href="#proc-setting-default-required-actions_server_administration_guide">Required actions tab</a> when configuring the particular required action. If the policy is not configured in any of those places, it defaults to five minutes.</p> </li> <li> <p>If you want to use a shorter re-authentication, you can still use a parameter query parameter such as <code>max_age</code> with the specified shorter value or eventually <code>prompt=login</code>, which will always require user to actively re-authenticate as described in the OIDC specification. Note that using <code>max_age</code> for a longer value than the default five minutes (or the one prescribed by password policy) is not supported. The <code>max_age</code> can be currently used only to make the value shorter than the default five minutes.</p> </li> <li> <p>If <a href="#_step-up-flow">Step-up authentication</a> is enabled and the action is to add or delete a credential, authentication is required with the level corresponding to the given credential. This requirement exists in case the user already has the credential of the particular level. For example, if <code>otp</code> and <code>webauthn</code> are configured in the authentication flow as 2nd-factor authenticators (both in the authentication flow at level 2) and the user already has a 2nd-factor credential (<code>otp</code> or <code>webauthn</code> in this case), the user is required to authenticate with an existing 2nd-factor credential to add another 2nd-level credential. In the same manner, deleting an existing 2nd-factor credential (<code>otp</code> or <code>webauthn</code> in this case), authentication with an existing 2nd-factor level credential is required. The requirement exists for security reasons.</p> </li> </ul> </div> </div> <div class="sect3"> <h4 id="con-aia-parameterized_server_administration_guide"><a class="anchor" href="#con-aia-parameterized_server_administration_guide"></a>Parameterized AIA</h4> <div class="paragraph"> <p>Some AIA can require the parameter to be sent together with the action name. For instance, the <code>Delete Credential</code> action can be triggered only by AIA and it requires a parameter to be sent together with the name of the action, which points to the ID of the removed credential. So the URL for this example would be <code>kc_action=delete_credential:ce1008ac-f811-427f-825a-c0b878d1c24b</code>. In this case, the part after the colon character (<code>ce1008ac-f811-427f-825a-c0b878d1c24b</code>) contains the ID of the credential of the particular user, which is to be deleted. The <code>Delete Credential</code> action displays the confirmation screen where the user can confirm agreement to delete the credential.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> The <a href="#_account-service">Keycloak Account Console</a> typically uses the <code>Delete Credential</code> action when deleting a 2nd-factor credential. You can check the Account Console for examples if you want to use this action directly from your own applications. However, relying on the Account Console is best instead of managing credentials from your own applications. </td> </tr> </table> </div> </div> <div class="sect3"> <h4 id="con-aia-available-actions_server_administration_guide"><a class="anchor" href="#con-aia-available-actions_server_administration_guide"></a>Available actions</h4> <div class="paragraph"> <p>To see all available actions, log in to the Admin Console and go to the top right top corner to click <code>Realm info</code> &#8594; tab <code>Provider info</code> &#8594; Find provider <code>required-action</code> . But note that this can be further restricted based on what actions are enabled for your realm in the <a href="#proc-setting-default-required-actions_server_administration_guide">Required actions tab</a>.</p> </div> </div> </div> <div class="sect2"> <h3 id="proc-searching-user_server_administration_guide"><a class="anchor" href="#proc-searching-user_server_administration_guide"></a>Searching for a user</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/users/proc-searching-user.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/users/proc-searching-user.adoc&amp;description=%0A%0AFile:%20server_admin/topics/users/proc-searching-user.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Search for a user to view detailed information about the user, such as the user&#8217;s groups and roles.</p> </div> <div class="ulist"> <div class="title">Prerequisite</div> <ul> <li> <p>You are in the realm where the user exists.</p> </li> </ul> </div> <div class="sect3"> <h4 id="default-search"><a class="anchor" href="#default-search"></a>Default search</h4> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Users</strong> in the main menu. This <strong>Users</strong> page is displayed.</p> </li> <li> <p>Type the full name, last name, first name, or email address of the user you want to search for in the search box. The search returns all users that match your criteria.</p> <div class="paragraph"> <p>The criteria used to match users depends on the syntax used on the search box:</p> </div> <div class="olist loweralpha"> <ol class="loweralpha" type="a"> <li> <p><code>"somevalue"</code> &#8594; performs exact search of the string <code>"somevalue"</code>;</p> </li> <li> <p><code>*somevalue*</code> &#8594; performs infix search, akin to a <code>LIKE '%somevalue%'</code> DB query;</p> </li> <li> <p><code>somevalue*</code> or <code>somevalue</code> &#8594; performs prefix search, akin to a <code>LIKE 'somevalue%'</code> DB query.</p> </li> </ol> </div> </li> </ol> </div> </div> <div class="sect3"> <h4 id="attribute-search"><a class="anchor" href="#attribute-search"></a>Attribute search</h4> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Users</strong> in the main menu. This <strong>Users</strong> page is displayed.</p> </li> <li> <p>Click <strong>Default search</strong> button and switch it to <strong>Attribute search</strong>.</p> </li> <li> <p>Click <strong>Select attributes</strong> button and specify the attributes to search by.</p> </li> <li> <p>Check <strong>Exact search</strong> checkbox to perform exact match or keep it unchecked to use an infix search for attribute values.</p> </li> <li> <p>Click <strong>Search</strong> button to perform the search. It returns all users that match the criteria.</p> </li> </ol> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>Searches performed in the <strong>Users</strong> page encompass both Keycloak&#8217;s database and configured user federation backends, such as LDAP. Users found in federated backends will be imported into Keycloak&#8217;s database if they don&#8217;t already exist there.</p> </div> </td> </tr> </table> </div> <div class="ulist"> <div class="title">Additional Resources</div> <ul> <li> <p>For more information on user federation, see <a href="#_user-storage-federation">User Federation</a>.</p> </li> </ul> </div> </div> </div> <div class="sect2"> <h3 id="proc-deleting-user_server_administration_guide"><a class="anchor" href="#proc-deleting-user_server_administration_guide"></a>Deleting a user</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/users/proc-deleting-user.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/users/proc-deleting-user.adoc&amp;description=%0A%0AFile:%20server_admin/topics/users/proc-deleting-user.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>You can delete a user, who no longer needs access to applications. If a user is deleted, the user profile and data is also deleted.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Users</strong> in the menu. The <strong>Users</strong> page is displayed.</p> </li> <li> <p>Click <strong>View all users</strong> to find a user to delete.</p> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> Alternatively, you can use the search bar to find a user. </td> </tr> </table> </div> </li> <li> <p>Click <strong>Delete</strong> from the action menu next to the user you want to remove and confirm deletion.</p> </li> </ol> </div> </div> <div class="sect2"> <h3 id="proc-allow-user-to-delete-account_server_administration_guide"><a class="anchor" href="#proc-allow-user-to-delete-account_server_administration_guide"></a>Enabling account deletion by users</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/users/proc-allow-user-to-delete-account.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/users/proc-allow-user-to-delete-account.adoc&amp;description=%0A%0AFile:%20server_admin/topics/users/proc-allow-user-to-delete-account.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>End users and applications can delete their accounts in the Account Console if you enable this capability in the Admin Console. Once you enable this capability, you can give that capability to specific users.</p> </div> <div class="sect3"> <h4 id="enabling-the-delete-account-capability"><a class="anchor" href="#enabling-the-delete-account-capability"></a>Enabling the Delete Account Capability</h4> <div class="paragraph"> <p>You enable this capability on the <strong>Required Actions</strong> tab.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Authentication</strong> in the menu.</p> </li> <li> <p>Click the <strong>Required Actions</strong> tab.</p> </li> <li> <p>Select <strong>Enabled</strong> on the <strong>Delete Account</strong> row.</p> <div class="paragraph"> <div class="title">Delete account on required actions tab</div> <p><span class="image"><img src="./images/enable-delete-account-action.png" alt="enable delete account action"></span></p> </div> </li> </ol> </div> </div> <div class="sect3"> <h4 id="giving-a-user-the-delete-account-role"><a class="anchor" href="#giving-a-user-the-delete-account-role"></a>Giving a user the <strong>delete-account</strong> role</h4> <div class="paragraph"> <p>You can give specific users a role that allows account deletion.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Users</strong> in the menu.</p> </li> <li> <p>Select a user.</p> </li> <li> <p>Click the <strong>Role Mappings</strong> tab.</p> </li> <li> <p>Click the <strong>Assign role</strong> button.</p> </li> <li> <p>Click <strong>account delete-account</strong>.</p> </li> <li> <p>Click <strong>Assign</strong>.</p> <div class="paragraph"> <div class="title">Delete-account role</div> <p><span class="image"><img src="./images/delete-account-client-role.png" alt="delete-account role"></span></p> </div> </li> </ol> </div> </div> <div class="sect3"> <h4 id="deleting-your-account"><a class="anchor" href="#deleting-your-account"></a>Deleting your account</h4> <div class="paragraph"> <p>Once you have the <strong>delete-account</strong> role, you can delete your own account.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Log into the Account Console.</p> </li> <li> <p>At the bottom of the <strong>Personal Info</strong> page, click <strong>Delete Account</strong>.</p> <div class="paragraph"> <div class="title">Delete account page</div> <p><span class="image"><img src="./images/delete-account-page.png" alt="Delete account page"></span></p> </div> </li> <li> <p>Enter your credentials and confirm the deletion.</p> <div class="paragraph"> <div class="title">Delete confirmation</div> <p><span class="image"><img src="./images/delete-account-confirm.png" alt="delete account confirm"></span></p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>This action is irreversible. All your data in Keycloak will be removed.</p> </div> </td> </tr> </table> </div> </li> </ol> </div> </div> </div> <div class="sect2"> <h3 id="con-user-impersonation_server_administration_guide"><a class="anchor" href="#con-user-impersonation_server_administration_guide"></a>Impersonating a user</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/users/con-user-impersonation.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/users/con-user-impersonation.adoc&amp;description=%0A%0AFile:%20server_admin/topics/users/con-user-impersonation.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>An administrator with the appropriate permissions can impersonate a user. For example, if a user experiences a bug in an application, an administrator can impersonate the user to investigate or duplicate the issue.</p> </div> <div class="paragraph"> <p>Any user with the <code>impersonation</code> role in the realm can impersonate a user.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Users</strong> in the menu.</p> </li> <li> <p>Click a user to impersonate.</p> </li> <li> <p>From the <strong>Actions</strong> list, select <strong>Impersonate</strong>.</p> <div class="paragraph"> <p><span class="image"><img src="./images/user-impersonate-action.png" alt="user impersonate action"></span></p> </div> <div class="ulist"> <ul> <li> <p>If the administrator and the user are in the same realm, then the administrator will be logged out and automatically logged in as the user being impersonated.</p> </li> <li> <p>If the administrator and user are in different realms, the administrator will remain logged in, and additionally will be logged in as the user in that user&#8217;s realm.</p> </li> </ul> </div> </li> </ol> </div> <div class="paragraph"> <p>In both instances, the <strong>Account Console</strong> of the impersonated user is displayed.</p> </div> <div class="ulist"> <div class="title">Additional resources</div> <ul> <li> <p>For more information on assigning administration permissions, see the <a href="#_admin_permissions">Admin Console Access Control</a> chapter.</p> </li> </ul> </div> </div> <div class="sect2"> <h3 id="proc-enabling-recaptcha_server_administration_guide"><a class="anchor" href="#proc-enabling-recaptcha_server_administration_guide"></a>Enabling reCAPTCHA</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/users/proc-enabling-recaptcha.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/users/proc-enabling-recaptcha.adoc&amp;description=%0A%0AFile:%20server_admin/topics/users/proc-enabling-recaptcha.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>To safeguard registration against bots, Keycloak has integration with Google reCAPTCHA (see <a href="#procedure_recaptcha">Setting up Google reCAPTCHA</a>) and reCAPTCHA Enterprise (see <a href="#procedure_recaptcha_enterprise">Setting up Google reCAPTCHA Enterprise</a>). The default theme (<code>register.ftl</code>) supports both v2 (visible, checkbox-based) and v3 (score-based, invisible) reCAPTCHA (see <a href="https://cloud.google.com/recaptcha/docs/choose-key-type">Choose the appropriate reCAPTCHA key type</a>).</p> </div> <div class="sect3"> <h4 id="procedure_recaptcha"><a class="anchor" href="#procedure_recaptcha"></a>Setting up Google reCAPTCHA</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Enter the following URL in a browser:</p> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">https://www.google.com/recaptcha/admin/create</code></pre> </div> </div> </li> <li> <p>Create a reCAPTCHA and choose between Challenge v2 (visible checkbox) or Score-based, v3 (invisible) to get your reCAPTCHA site key and secret. Note them down for future use in this procedure.</p> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> The localhost works by default. You do not have to specify a domain. </td> </tr> </table> </div> </li> <li> <p>Navigate to the Keycloak admin console.</p> </li> <li> <p>Click <strong>Authentication</strong> in the menu.</p> </li> <li> <p>Click the <strong>Flows</strong> tab.</p> </li> <li> <p>Select <strong>Registration</strong> from the list.</p> </li> <li> <p>Set the <strong>reCAPTCHA</strong> requirement to <strong>Required</strong>. This enables reCAPTCHA.</p> </li> <li> <p>Click the <strong>gear icon</strong> ⚙️ on the <strong>reCAPTCHA</strong> row.</p> <div class="paragraph"> <div class="title">reCAPTCHA config</div> <p><span class="image"><img src="./images/recaptcha-config.png" alt="recaptcha config"></span></p> </div> <div class="olist loweralpha"> <ol class="loweralpha" type="a"> <li> <p>Enter the <strong>reCAPTCHA Site Key</strong> generated from the Google reCAPTCHA website.</p> </li> <li> <p>Enter the <strong>reCAPTCHA Secret</strong> generated from the Google reCAPTCHA website.</p> </li> <li> <p>Toggle <strong>reCAPTCHA v3</strong> according to your Site Key type: on for score-based reCAPTCHA (v3), off for challenge reCAPTCHA (v2).</p> </li> <li> <p>(Optional) Toggle <strong>Use recaptcha.net</strong> to use <code>www.recatcha.net</code> instead of <code>www.google.com</code> domain for cookies. See <a href="https://developers.google.com/recaptcha/docs/faq">reCAPTCHA faq</a> for more information.</p> </li> </ol> </div> </li> <li> <p>Authorize Google to use the registration page as an iframe.</p> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> In Keycloak, websites cannot include a login page dialog in an iframe. This restriction is to prevent clickjacking attacks. You need to change the default HTTP response headers that is set in Keycloak. </td> </tr> </table> </div> <div class="olist loweralpha"> <ol class="loweralpha" type="a"> <li> <p>Click <strong>Realm Settings</strong> in the menu.</p> </li> <li> <p>Click the <strong>Security Defenses</strong> tab.</p> </li> <li> <p>Enter <code><a href="https://www.google.com" class="bare">https://www.google.com</a></code> in the field for the <strong>X-Frame-Options</strong> header (or <code>https//www.recaptcha.net</code> if you enabled <strong>Use recaptcha.net</strong>).</p> </li> <li> <p>Enter <code><a href="https://www.google.com" class="bare">https://www.google.com</a></code> in the field for the <strong>Content-Security-Policy</strong> header (or <code>https//www.recaptcha.net</code> if you enabled <strong>Use recaptcha.net</strong>).</p> </li> </ol> </div> </li> </ol> </div> </div> <div class="sect3"> <h4 id="procedure_recaptcha_enterprise"><a class="anchor" href="#procedure_recaptcha_enterprise"></a>Setting up Google reCAPTCHA Enterprise</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Enter the following URL in a browser:</p> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">https://developers.google.com/recaptcha/</code></pre> </div> </div> </li> <li> <p>Create a key for a "Website" platform, and choose the desired key type. Leave the defaults for v3 reCAPTCHA (invisible), or toggle <strong>Use checkbox challenge</strong> for a v2 reCAPTCHA (visible). Note the site key for future use in this procedure.</p> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> The localhost works by default. You do not have to specify a domain. </td> </tr> </table> </div> </li> <li> <p>On your Google Cloud Project, go to <strong>Credentials</strong> and create an API key.</p> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> For better security, click on <strong>edit api key</strong> and add an API restriction to restrict the key to the <strong>reCAPTCHA Enterprise API</strong> only. </td> </tr> </table> </div> </li> <li> <p>Navigate to the Keycloak Admin Console.</p> </li> <li> <p>Click <strong>Authentication</strong> in the menu.</p> </li> <li> <p>Click the <strong>Flows</strong> tab.</p> </li> <li> <p>Duplicate the "registration" flow.</p> </li> <li> <p>Bind the new flow to the <strong>Registration flow</strong>.</p> </li> <li> <p>Edit the new flow:</p> <div class="olist loweralpha"> <ol class="loweralpha" type="a"> <li> <p>Delete the <strong>reCAPTCHA</strong> step.</p> </li> <li> <p>Add the step <strong>reCAPTCHA Enterprise</strong> as a sub-step of "registration form" (first step of the flow).</p> </li> </ol> </div> </li> <li> <p>Set the <strong>reCAPTCHA Enterprise</strong> requirement to <strong>Required</strong>.</p> </li> <li> <p>Click the <strong>gear icon</strong> ⚙️ on the <strong>reCAPTCHA Enterprise</strong> row.</p> <div class="paragraph"> <div class="title">reCAPTCHA Enterprise config</div> <p><span class="image"><img src="./images/recaptcha-enterprise-config.png" alt="recaptcha enterprise config"></span></p> </div> <div class="olist loweralpha"> <ol class="loweralpha" type="a"> <li> <p>Enter the <strong>Recaptcha Project ID</strong> of your Google Cloud console project.</p> </li> <li> <p>Enter the <strong>Recaptcha Site Key</strong> generated at the beginning of the procedure.</p> </li> <li> <p>Enter the <strong>Recaptcha API Key</strong> generated at the beginning of the procedure.</p> </li> <li> <p>Toggle <strong>reCAPTCHA v3</strong> according to your Site Key type: on for score-based reCAPTCHA (v3), off for challenge reCAPTCHA (v2).</p> </li> <li> <p>(Optional) Customize the <strong>Min. Score Threshold</strong> as you see fit. Set it to the minimum score, between 0.0 and 1.0, that a user should achieve on reCAPTCHA to be allowed to register. See <a href="https://cloud.google.com/recaptcha/docs/interpret-assessment-website#interpret_scores">interpret scores</a>.</p> </li> <li> <p>(Optional) Toggle <strong>Use recaptcha.net</strong> to use <code>www.recatcha.net</code> instead of <code>www.google.com</code> domain for cookies. See <a href="https://developers.google.com/recaptcha/docs/faq">reCAPTCHA faq</a> for more information.</p> </li> </ol> </div> </li> <li> <p>Authorize Google to use the registration page as an iframe. See the last steps of <a href="#procedure_recaptcha">Setting up Google reCAPTCHA</a> for a detailed procedure.</p> </li> </ol> </div> <div class="ulist _additional-resources"> <div class="title">Additional resources</div> <ul> <li> <p>For more information on extending and creating themes, see the <a href="https://www.keycloak.org/docs/26.0.6/server_development/">Server Developer Guide</a>.</p> </li> </ul> </div> </div> </div> <div class="sect2"> <h3 id="ref-personal-data-collected_server_administration_guide"><a class="anchor" href="#ref-personal-data-collected_server_administration_guide"></a>Personal data collected by Keycloak</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/users/ref-personal-data-collected.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/users/ref-personal-data-collected.adoc&amp;description=%0A%0AFile:%20server_admin/topics/users/ref-personal-data-collected.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>By default, Keycloak collects the following data:</p> </div> <div class="ulist"> <ul> <li> <p>Basic user profile data, such as the user email, first name, and last name.</p> </li> <li> <p>Basic user profile data used for social accounts and references to the social account when using a social login.</p> </li> <li> <p>Device information collected for audit and security purposes, such as the IP address, operating system name, and the browser name.</p> </li> </ul> </div> <div class="paragraph"> <p>The information collected in Keycloak is highly customizable. The following guidelines apply when making customizations:</p> </div> <div class="ulist"> <ul> <li> <p>Registration and account forms can contain custom fields, such as birthday, gender, and nationality. An administrator can configure Keycloak to retrieve data from a social provider or a user storage provider such as LDAP.</p> </li> <li> <p>Keycloak collects user credentials, such as password, OTP codes, and WebAuthn public keys. This information is encrypted and saved in a database, so it is not visible to Keycloak administrators. Each type of credential can include non-confidential metadata that is visible to administrators such as the algorithm that is used to hash the password and the number of hash iterations used to hash the password.</p> </li> <li> <p>With authorization services and UMA support enabled, Keycloak can hold information about some objects for which a particular user is the owner.</p> </li> </ul> </div> </div> </div> </div> <div class="sect1"> <h2 id="managing-user-sessions"><a class="anchor" href="#managing-user-sessions"></a>Managing user sessions</h2> <div class="sectionbody"> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/sessions.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/sessions.adoc&amp;description=%0A%0AFile:%20server_admin/topics/sessions.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>When users log into realms, Keycloak maintains a user session for each user and remembers each client visited by the user within the session. Realm administrators can perform multiple actions on each user session:</p> </div> <div class="ulist"> <ul> <li> <p>View login statistics for the realm.</p> </li> <li> <p>View active users and where they logged in.</p> </li> <li> <p>Log a user out of their session.</p> </li> <li> <p>Revoke tokens.</p> </li> <li> <p>Set up token timeouts.</p> </li> <li> <p>Set up session timeouts.</p> </li> </ul> </div> <div class="sect2"> <h3 id="administering-sessions"><a class="anchor" href="#administering-sessions"></a>Administering sessions</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/sessions/administering.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/sessions/administering.adoc&amp;description=%0A%0AFile:%20server_admin/topics/sessions/administering.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>To see a top-level view of the active clients and sessions in Keycloak, click <strong>Sessions</strong> from the menu.</p> </div> <div class="paragraph"> <div class="title">Sessions</div> <p><span class="image"><img src="./images/sessions.png" alt="Sessions tab"></span></p> </div> <div class="sect3"> <h4 id="signing-out-all-active-sessions"><a class="anchor" href="#signing-out-all-active-sessions"></a>Signing out all active sessions</h4> <div class="paragraph"> <p>You can sign out all users in the realm. From the <strong>Action</strong> list, select <strong>Sign out all active sessions</strong>. All SSO cookies become invalid. Keycloak notifies clients by using the Keycloak OIDC client adapter of the logout event. Clients requesting authentication within active browser sessions must log in again. Client types such as SAML do not receive a back-channel logout request.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>Clicking <strong>Sign out all active sessions</strong> does not revoke outstanding access tokens. Outstanding tokens must expire naturally. For clients using the Keycloak OIDC client adapter, you can push a <a href="#_revocation-policy">revocation policy</a> to revoke the token, but this does not work for other adapters.</p> </div> </td> </tr> </table> </div> </div> <div class="sect3"> <h4 id="viewing-client-sessions"><a class="anchor" href="#viewing-client-sessions"></a>Viewing client sessions</h4> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Clients</strong> in the menu.</p> </li> <li> <p>Click a client to see that client&#8217;s sessions.</p> </li> <li> <p>Click the <strong>Sessions</strong> tab.</p> <div class="paragraph"> <div class="title">Client sessions</div> <p><span class="image"><img src="./images/client-sessions.png" alt="Client sessions"></span></p> </div> </li> </ol> </div> </div> <div class="sect3"> <h4 id="viewing-user-sessions"><a class="anchor" href="#viewing-user-sessions"></a>Viewing user sessions</h4> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Users</strong> in the menu.</p> </li> <li> <p>Click a user to see that user&#8217;s sessions.</p> </li> <li> <p>Click the <strong>Sessions</strong> tab.</p> <div class="paragraph"> <div class="title">User sessions</div> <p><span class="image"><img src="./images/user-sessions.png" alt="User sessions"></span></p> </div> </li> </ol> </div> </div> </div> <div class="sect2"> <h3 id="_revocation-policy"><a class="anchor" href="#_revocation-policy"></a>Revoking active sessions</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/sessions/revocation.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/sessions/revocation.adoc&amp;description=%0A%0AFile:%20server_admin/topics/sessions/revocation.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>If your system is compromised, you can revoke all active sessions and access tokens.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Sessions</strong> in the menu.</p> </li> <li> <p>From the <strong>Actions</strong> list, select <strong>Revocation</strong>.</p> <div class="paragraph"> <div class="title">Revocation</div> <p><span class="image"><img src="./images/revocation.png" alt="Revocation"></span></p> </div> </li> <li> <p>Specify a time and date where sessions or tokens issued before that time and date are invalid using this console.</p> <div class="ulist"> <ul> <li> <p>Click <strong>Set to now</strong> to set the policy to the current time and date.</p> </li> <li> <p>Click <strong>Push</strong> to push this revocation policy to any registered OIDC client with the Keycloak OIDC client adapter.</p> </li> </ul> </div> </li> </ol> </div> </div> <div class="sect2"> <h3 id="_timeouts"><a class="anchor" href="#_timeouts"></a>Session and token timeouts</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/sessions/timeouts.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/sessions/timeouts.adoc&amp;description=%0A%0AFile:%20server_admin/topics/sessions/timeouts.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>Keycloak includes control of the session, cookie, and token timeouts through the <strong>Sessions</strong> and <strong>Tokens</strong> tabs in the <strong>Realm settings</strong> menu.</p> </div> <div class="paragraph"> <div class="title">Sessions tab</div> <p><span class="image"><img src="./images/sessions-tab.png" alt="Sessions Tab"></span></p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 50%;"> <col style="width: 50%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Configuration</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">SSO Session Idle</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">This setting is for OIDC clients only. If a user is inactive for longer than this timeout, the user session is invalidated. This timeout value resets when clients request authentication or send a refresh token request. Keycloak adds a window of time to the idle timeout before the session invalidation takes effect. See the <a href="#_idle_timeouts_note">note</a> later in this section.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">SSO Session Max</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The maximum time before a user session expires.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">SSO Session Idle Remember Me</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">This setting is similar to the standard SSO Session Idle configuration but specific to logins with <strong>Remember Me</strong> enabled. Users can specify longer session idle timeouts when they click <strong>Remember Me</strong> when logging in. This setting is an optional configuration and, if its value is not greater than zero, it uses the same idle timeout as the SSO Session Idle configuration.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">SSO Session Max Remember Me</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">This setting is similar to the standard SSO Session Max but specific to <strong>Remember Me</strong> logins. Users can specify longer sessions when they click <strong>Remember Me</strong> when logging in. This setting is an optional configuration and, if its value is not greater than zero, it uses the same session lifespan as the SSO Session Max configuration.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Client Session Idle</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Idle timeout for the client session. If the user is inactive for longer than this timeout, the client session is invalidated and the refresh token requests bump the idle timeout. This setting never affects the general SSO user session, which is unique. Note the SSO user session is the parent of zero or more client sessions, one client session is created for every different client app the user logs in. This value should specify a shorter idle timeout than the <strong>SSO Session Idle</strong>. Users can override it for individual clients in the <strong>Advanced Settings</strong> client tab. This setting is an optional configuration and, when set to zero, uses the same idle timeout in the SSO Session Idle configuration.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Client Session Max</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The maximum time for a client session and before a refresh token expires and invalidates. As in the previous option, this setting never affects the SSO user session and should specify a shorter value than the <strong>SSO Session Max</strong>. Users can override it for individual clients in the <strong>Advanced Settings</strong> client tab. This setting is an optional configuration and, when set to zero, uses the same max timeout in the SSO Session Max configuration.</p> <p class="tableblock"><a id="_offline-session-idle"></a></p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Offline Session Idle</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">This setting is for <a href="#_offline-access">offline access</a>. The amount of time the session remains idle before Keycloak revokes its offline token. Keycloak adds a window of time to the idle timeout before the session invalidation takes effect. See the <a href="#_idle_timeouts_note">note</a> later in this section.</p> <p class="tableblock"><a id="_offline-session-max-limited"></a></p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Offline Session Max Limited</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">This setting is for <a href="#_offline-access">offline access</a>. If this flag is <strong>Enabled</strong>, Offline Session Max can control the maximum time the offline token remains active, regardless of user activity. If the flag is <strong>Disabled</strong>, offline sessions never expire by lifespan, only by idle. Once this option is activated, the <a href="#_offline-session-max">Offline Session Max</a> (global option at realm level) and <strong>Client Offline Session Max</strong> (specific client level option in the <strong>Advanced Settings</strong> tab) can be configured.</p> <p class="tableblock"><a id="_offline-session-max"></a></p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Offline Session Max</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">This setting is for <a href="#_offline-access">offline access</a>, and it is the maximum time before Keycloak revokes the corresponding offline token. This option controls the maximum amount of time the offline token remains active, regardless of user activity.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Login timeout</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The total time a logging in must take. If authentication takes longer than this time, the user must start the authentication process again.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Login action timeout</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The Maximum time users can spend on any one page during the authentication process.</p></td> </tr> </tbody> </table> <div class="paragraph"> <div class="title">Tokens tab</div> <p><span class="image"><img src="./images/tokens-tab.png" alt="Tokens Tab"></span></p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 50%;"> <col style="width: 50%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Configuration</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Default Signature Algorithm</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The default algorithm used to assign tokens for the realm.</p> <p class="tableblock"><a id="_revoke-refresh-token"></a></p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Revoke Refresh Token</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">When <strong>Enabled</strong>, Keycloak revokes refresh tokens and issues another token that the client must use. This action applies to OIDC clients performing the refresh token flow.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Access Token Lifespan</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">When Keycloak creates an OIDC access token, this value controls the lifetime of the token.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Access Token Lifespan For Implicit Flow</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">With the Implicit Flow, Keycloak does not provide a refresh token. A separate timeout exists for access tokens created by the Implicit Flow.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Client login timeout</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The maximum time before clients must finish the Authorization Code Flow in OIDC.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">User-Initiated Action Lifespan</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The maximum time before a user&#8217;s action permission expires. Keep this value short because users generally react to self-created actions quickly.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Default Admin-Initiated Action Lifespan</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The maximum time before an action permission sent to a user by an administrator expires. Keep this value long to allow administrators to send e-mails to offline users. An administrator can override the default timeout before issuing the token.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Email Verification</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Specifies independent timeout for email verification.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">IdP account email verification</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Specifies independent timeout for IdP account email verification.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Forgot password</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Specifies independent timeout for forgot password.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Execute actions</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Specifies independent timeout for execute actions.</p></td> </tr> </tbody> </table> <div id="_idle_timeouts_note" class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>The following logic is only applied if persistent user sessions are not active:</p> </div> <div class="paragraph"> <p>For idle timeouts, a two-minute window of time exists that the session is active. For example, when you have the timeout set to 30 minutes, it will be 32 minutes before the session expires.</p> </div> <div class="paragraph"> <p>This action is necessary for some scenarios in cluster and cross-data center environments where the token refreshes on one cluster node a short time before the expiration and the other cluster nodes incorrectly consider the session as expired because they have not yet received the message about a successful refresh from the refreshing node.</p> </div> </td> </tr> </table> </div> </div> <div class="sect2"> <h3 id="_offline-access"><a class="anchor" href="#_offline-access"></a>Offline access</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/sessions/offline.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/sessions/offline.adoc&amp;description=%0A%0AFile:%20server_admin/topics/sessions/offline.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>During <a href="https://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess">offline access</a> logins, the client application requests an offline token instead of a refresh token. The client application saves this offline token and can use it for future logins if the user logs out. This action is useful if your application needs to perform offline actions on behalf of the user even when the user is not online. For example, a regular data backup.</p> </div> <div class="paragraph"> <p>The client application is responsible for persisting the offline token in storage and then using it to retrieve new access tokens from the Keycloak server.</p> </div> <div class="paragraph"> <p>The difference between a refresh token and an offline token is that an offline token never expires and is not subject to the <code>SSO Session Idle</code> timeout and <code>SSO Session Max</code> lifespan. The offline token is valid after a user logout. You must use the offline token for a refresh token action at least once per thirty days or for the value of the <a href="#_offline-session-idle">Offline Session Idle</a>.</p> </div> <div class="paragraph"> <p>If you enable <a href="#_offline-session-max-limited">Offline Session Max Limited</a>, offline tokens expire after 60 days even if you use the offline token for a refresh token action. You can change this value, <a href="#_offline-session-max">Offline Session Max</a>, in the Admin Console.</p> </div> <div class="paragraph"> <p>When using offline access, client idle and max timeouts can be overridden at the <a href="#_client_advanced_settings_oidc">client level</a>. The options <strong>Client Offline Session Idle</strong> and <strong>Client Offline Session Max</strong>, in the client <strong>Advanced Settings</strong> tab, allow you to have a shorter offline timeouts for a specific application. Note that client session values also control the refresh token expiration but they never affect the global offline user SSO session. The option <strong>Client Offline Session Max</strong> is only evaluated in the client if <a href="#_offline-session-max-limited">Offline Session Max Limited</a> is <strong>Enabled</strong> at the realm level.</p> </div> <div class="paragraph"> <p>If you enable the <a href="#_revoke-refresh-token">Revoke Refresh Token</a> option, you can use each offline token once only. After refresh, you must store the new offline token from the refresh response instead of the previous one.</p> </div> <div class="paragraph"> <p>Users can view and revoke offline tokens that Keycloak grants them in the <a href="#_account-service">User Account Console</a>. Administrators can revoke offline tokens for individual users in the Admin Console in the <code>Consents</code> tab. Administrators can view all offline tokens issued in the <code>Offline Access</code> tab of each client. Administrators can revoke offline tokens by setting a <a href="#_revocation-policy">revocation policy</a>.</p> </div> <div class="paragraph"> <p>To issue an offline token, users must have the role mapping for the realm-level <code>offline_access</code> role. Clients must also have that role in their scope. Clients must add an <code>offline_access</code> client scope as an <code>Optional client scope</code> to the role, which is done by default.</p> </div> <div class="paragraph"> <p>Clients can request an offline token by adding the parameter <code>scope=offline_access</code> when sending their authorization request to Keycloak. The Keycloak OIDC client adapter automatically adds this parameter when you use it to access your application&#8217;s secured URL (such as, http://localhost:8080/customer-portal/secured?scope=offline_access). The Direct Access Grant and Service Accounts support offline tokens if you include <code>scope=offline_access</code> in the authentication request body.</p> </div> <div class="paragraph"> <p>Keycloak will limit its internal cache for offline user and offline client sessions to 10000 entries by default, which will reduce the overall memory usage for offline sessions. Items which are evicted from memory will be loaded on-demand from the database when needed. To set different sizes for the caches, edit Keycloak&#8217;s cache config file to set a <code>&lt;memory max-count="..."/&gt;</code> for those caches.</p> </div> <div class="paragraph"> <p>If you disabled feature <code>persistent-user-sessions</code>, it is possible to reduce memory requirements using a configuration option that shortens lifespan for imported offline sessions. Such sessions will be evicted from the Infinispan caches after the specified lifespan, but still available in the database. This will lower memory consumption, especially for deployments with a large number of offline sessions.</p> </div> <div class="paragraph"> <p>To specify the lifespan override for offline user sessions, start Keycloak server with the following parameter:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">--spi-user-sessions-infinispan-offline-session-cache-entry-lifespan-override=&lt;lifespan-in-seconds&gt;</code></pre> </div> </div> <div class="paragraph"> <p>Similarly for offline client sessions:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">--spi-user-sessions-infinispan-offline-client-session-cache-entry-lifespan-override=&lt;lifespan-in-seconds&gt;</code></pre> </div> </div> </div> <div class="sect2"> <h3 id="_transient-session"><a class="anchor" href="#_transient-session"></a>Transient sessions</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/sessions/transient.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/sessions/transient.adoc&amp;description=%0A%0AFile:%20server_admin/topics/sessions/transient.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>You can conduct transient sessions in Keycloak. When using transient sessions, Keycloak does not create a user session after successful authentication. Keycloak creates a temporary, transient session for the scope of the current request that successfully authenticates the user. Keycloak can run <a href="#_protocol-mappers">protocol mappers</a> using transient sessions after authentication.</p> </div> <div class="paragraph"> <p>The <code>sid</code> and <code>session_state</code> of the tokens are usually empty when the token is issued with transient sessions. So during transient sessions, the client application cannot refresh tokens or validate a specific session. Sometimes these actions are unnecessary, so you can avoid the additional resource use of persisting user sessions. This session saves performance, memory, and network communication (in cluster and cross-data center environments) resources.</p> </div> <div class="paragraph"> <p>At this moment, transient sessions are automatically used just during <a href="#_service_accounts">service account authentication</a> with disabled token refresh. Note that token refresh is automatically disabled during service account authentication unless explicitly enabled by client switch <code>Use refresh tokens for client credentials grant</code>.</p> </div> </div> </div> </div> <div class="sect1"> <h2 id="assigning-permissions-using-roles-and-groups"><a class="anchor" href="#assigning-permissions-using-roles-and-groups"></a>Assigning permissions using roles and groups</h2> <div class="sectionbody"> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/assembly-roles-groups.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/assembly-roles-groups.adoc&amp;description=%0A%0AFile:%20server_admin/topics/assembly-roles-groups.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Roles and groups have a similar purpose, which is to give users access and permissions to use applications. Groups are a collection of users to which you apply roles and attributes. Roles define specific applications permissions and access control.</p> </div> <div class="paragraph"> <p>A role typically applies to one type of user. For example, an organization may include <code>admin</code>, <code>user</code>, <code>manager</code>, and <code>employee</code> roles. An application can assign access and permissions to a role and then assign multiple users to that role so the users have the same access and permissions. For example, the Admin Console has roles that give permission to users to access different parts of the Admin Console.</p> </div> <div class="paragraph"> <p>There is a global namespace for roles and each client also has its own dedicated namespace where roles can be defined.</p> </div> <div class="sect2"> <h3 id="proc-creating-realm-roles_server_administration_guide"><a class="anchor" href="#proc-creating-realm-roles_server_administration_guide"></a>Creating a realm role</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/roles-groups/proc-creating-realm-roles.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/roles-groups/proc-creating-realm-roles.adoc&amp;description=%0A%0AFile:%20server_admin/topics/roles-groups/proc-creating-realm-roles.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>Realm-level roles are a namespace for defining your roles. To see the list of roles, click <strong>Realm Roles</strong> in the menu.</p> </div> <div class="paragraph"> <p><span class="image"><img src="./images/roles.png" alt="roles"></span></p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Create Role</strong>.</p> </li> <li> <p>Enter a <strong>Role Name</strong>.</p> </li> <li> <p>Enter a <strong>Description</strong>.</p> </li> <li> <p>Click <strong>Save</strong>.</p> </li> </ol> </div> <div class="paragraph"> <div class="title">Add role</div> <p><span class="image"><img src="./images/role.png" alt="Add role"></span></p> </div> <div class="paragraph"> <p>The <strong>description</strong> field can be localized by specifying a substitution variable with <code>${var-name}</code> strings. The localized value is configured to your theme within the themes property files. See the <a href="https://www.keycloak.org/docs/26.0.6/server_development/">Server Developer Guide</a> for more details.</p> </div> </div> <div class="sect2"> <h3 id="con-client-roles_server_administration_guide"><a class="anchor" href="#con-client-roles_server_administration_guide"></a>Client roles</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/roles-groups/con-client-roles.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/roles-groups/con-client-roles.adoc&amp;description=%0A%0AFile:%20server_admin/topics/roles-groups/con-client-roles.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>Client roles are namespaces dedicated to clients. Each client gets its own namespace. Client roles are managed under the <strong>Roles</strong> tab for each client. You interact with this UI the same way you do for realm-level roles.</p> </div> </div> <div class="sect2"> <h3 id="_composite-roles"><a class="anchor" href="#_composite-roles"></a>Converting a role to a composite role</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/roles-groups/proc-converting-composite-roles.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/roles-groups/proc-converting-composite-roles.adoc&amp;description=%0A%0AFile:%20server_admin/topics/roles-groups/proc-converting-composite-roles.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>Any realm or client level role can become a <em>composite role</em>. A <em>composite role</em> is a role that has one or more additional roles associated with it. When a composite role is mapped to a user, the user gains the roles associated with the composite role. This inheritance is recursive so users also inherit any composite of composites. However, we recommend that composite roles are not overused.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Realm Roles</strong> in the menu.</p> </li> <li> <p>Click the role that you want to convert.</p> </li> <li> <p>From the <strong>Action</strong> list, select <strong>Add associated roles</strong>.</p> </li> </ol> </div> <div class="paragraph"> <div class="title">Composite role</div> <p><span class="image"><img src="./images/composite-role.png" alt="Composite role"></span></p> </div> <div class="paragraph"> <p>The role selection UI is displayed on the page and you can associate realm level and client level roles to the composite role you are creating.</p> </div> <div class="paragraph"> <p>In this example, the <strong>employee</strong> realm-level role is associated with the <strong>developer</strong> composite role. Any user with the <strong>developer</strong> role also inherits the <strong>employee</strong> role.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>When creating tokens and SAML assertions, any composite also has its associated roles added to the claims and assertions of the authentication response sent back to the client.</p> </div> </td> </tr> </table> </div> </div> <div class="sect2"> <h3 id="proc-assigning-role-mappings_server_administration_guide"><a class="anchor" href="#proc-assigning-role-mappings_server_administration_guide"></a>Assigning role mappings</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/roles-groups/proc-assigning-role-mappings.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/roles-groups/proc-assigning-role-mappings.adoc&amp;description=%0A%0AFile:%20server_admin/topics/roles-groups/proc-assigning-role-mappings.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>You can assign role mappings to a user through the <strong>Role Mappings</strong> tab for that user.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Users</strong> in the menu.</p> </li> <li> <p>Click the user that you want to perform a role mapping on.</p> </li> <li> <p>Click the <strong>Role mappings</strong> tab.</p> </li> <li> <p>Click <strong>Assign role</strong>.</p> </li> <li> <p>Select the role you want to assign to the user from the dialog.</p> </li> <li> <p>Click <strong>Assign</strong>.</p> </li> </ol> </div> <div class="paragraph"> <div class="title">Role mappings</div> <p><span class="image"><img src="./images/user-role-mappings.png" alt="Role mappings"></span></p> </div> <div class="paragraph"> <p>In the preceding example, we are assigning the composite role <strong>developer</strong> to a user. That role was created in the <a href="#_composite-roles">Composite Roles</a> topic.</p> </div> <div class="paragraph"> <div class="title">Effective role mappings</div> <p><span class="image"><img src="./images/effective-role-mappings.png" alt="Effective role mappings"></span></p> </div> <div class="paragraph"> <p>When the <strong>developer</strong> role is assigned, the <strong>employee</strong> role associated with the <strong>developer</strong> composite is displayed with <strong>Inherited</strong> "True". <strong>Inherited</strong> roles are the roles explicitly assigned to users and roles that are inherited from composites.</p> </div> </div> <div class="sect2"> <h3 id="_default_roles"><a class="anchor" href="#_default_roles"></a>Using default roles</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/roles-groups/proc-using-default-roles.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/roles-groups/proc-using-default-roles.adoc&amp;description=%0A%0AFile:%20server_admin/topics/roles-groups/proc-using-default-roles.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>Use default roles to automatically assign user role mappings when a user is created or imported through <a href="#_identity_broker">Identity Brokering</a>.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Realm settings</strong> in the menu.</p> </li> <li> <p>Click the <strong>User registration</strong> tab.</p> <div class="paragraph"> <div class="title">Default roles</div> <p><span class="image"><img src="./images/default-roles.png" alt="Default roles"></span></p> </div> </li> </ol> </div> <div class="paragraph"> <p>This screenshot shows that some <em>default roles</em> already exist.</p> </div> </div> <div class="sect2"> <h3 id="_role_scope_mappings"><a class="anchor" href="#_role_scope_mappings"></a>Role scope mappings</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/roles-groups/con-role-scope-mappings.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/roles-groups/con-role-scope-mappings.adoc&amp;description=%0A%0AFile:%20server_admin/topics/roles-groups/con-role-scope-mappings.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>On creation of an OIDC access token or SAML assertion, the user role mappings become claims within the token or assertion. Applications use these claims to make access decisions on the resources controlled by the application. Keycloak digitally signs access tokens and applications reuse them to invoke remotely secured REST services. However, these tokens have an associated risk. An attacker can obtain these tokens and use their permissions to compromise your networks. To prevent this situation, use <em>Role Scope Mappings</em>.</p> </div> <div class="paragraph"> <p><em>Role Scope Mappings</em> limit the roles declared inside an access token. When a client requests a user authentication, the access token they receive contains only the role mappings that are explicitly specified for the client&#8217;s scope. The result is that you limit the permissions of each individual access token instead of giving the client access to all the users permissions.</p> </div> <div class="paragraph"> <p>By default, each client gets all the role mappings of the user. You can view the role mappings for a client.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Clients</strong> in the menu.</p> </li> <li> <p>Click the client to go to the details.</p> </li> <li> <p>Click the <strong>Client scopes</strong> tab.</p> </li> <li> <p>Click the link in the row with <em>Dedicated scope and mappers for this client</em></p> </li> <li> <p>Click the <strong>Scope</strong> tab.</p> </li> </ol> </div> <div class="paragraph"> <div class="title">Full scope</div> <p><span class="image"><img src="./images/full-client-scope.png" alt="Full scope"></span></p> </div> <div class="paragraph"> <p>By default, the effective roles of scopes are every declared role in the realm. To change this default behavior, toggle <strong>Full Scope Allowed</strong> to <strong>OFF</strong> and declare the specific roles you want in each client. You can also use <a href="#_client_scopes">client scopes</a> to define the same role scope mappings for a set of clients.</p> </div> <div class="paragraph"> <div class="title">Partial scope</div> <p><span class="image"><img src="./images/client-scope.png" alt="Partial scope"></span></p> </div> </div> <div class="sect2"> <h3 id="proc-managing-groups_server_administration_guide"><a class="anchor" href="#proc-managing-groups_server_administration_guide"></a>Groups</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/roles-groups/proc-managing-groups.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/roles-groups/proc-managing-groups.adoc&amp;description=%0A%0AFile:%20server_admin/topics/roles-groups/proc-managing-groups.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>Groups in Keycloak manage a common set of attributes and role mappings for each user. Users can be members of any number of groups and inherit the attributes and role mappings assigned to each group.</p> </div> <div class="paragraph"> <p>To manage groups, click <strong>Groups</strong> in the menu.</p> </div> <div class="paragraph"> <div class="title">Groups</div> <p><span class="image"><img src="./images/groups.png" alt="groups"></span></p> </div> <div class="paragraph"> <p>Groups are hierarchical. A group can have multiple subgroups but a group can have only one parent. Subgroups inherit the attributes and role mappings from their parent. Users inherit the attributes and role mappings from their parent as well.</p> </div> <div class="paragraph"> <p>If you have a parent group and a child group, and a user that belongs only to the child group, the user in the child group inherits the attributes and role mappings of both the parent group and the child group.</p> </div> <div class="paragraph"> <p>The hierarchy of a group is sometimes represented using the group path. The path is the complete list of names that represents the hierarchy of a specific group, from top to bottom and separated by slashes <code>/</code> (similar to files in a File System). For example a path can be <code>/top/level1/level2</code> which means that <code>top</code> is a top level group and is parent of <code>level1</code>, which in turn is parent of <code>level2</code>. This path represents unambiguously the hierarchy for the group <code>level2</code>.</p> </div> <div class="paragraph"> <p>Because of historical reasons Keycloak, does not escape slashes in the group name itself. Therefore a group named <code>level1/group</code> under <code>top</code> uses the path <code>/top/level1/group</code>, which is misleading. Keycloak can be started with the option <code>--spi-group-jpa-escape-slashes-in-group-path</code> to <code>true</code> and then the slashes in the name are escaped with the character <code>~</code>. The escape char marks that the slash is part of the name and has no hierarchical meaning. The previous path example would be <code>/top/level1~/group</code> when escaped.</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">bin/kc.[sh|bat] start --spi-group-jpa-escape-slashes-in-group-path=true</code></pre> </div> </div> <div class="paragraph"> <p>The following example includes a top-level <strong>Sales</strong> group and a child <strong>North America</strong> subgroup.</p> </div> <div class="paragraph"> <p>To add a group:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Click the group.</p> </li> <li> <p>Click <strong>Create group</strong>.</p> </li> <li> <p>Enter a group name.</p> </li> <li> <p>Click <strong>Create</strong>.</p> </li> <li> <p>Click the group name.</p> <div class="paragraph"> <p>The group management page is displayed.</p> </div> <div class="paragraph"> <div class="title">Group</div> <p><span class="image"><img src="./images/group.png" alt="group"></span></p> </div> </li> </ol> </div> <div class="paragraph"> <p>Attributes and role mappings you define are inherited by the groups and users that are members of the group.</p> </div> <div class="paragraph"> <p>To add a user to a group:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Click <strong>Users</strong> in the menu.</p> </li> <li> <p>Click the user that you want to perform a role mapping on. If the user is not displayed, click <strong>View all users</strong>.</p> </li> <li> <p>Click <strong>Groups</strong>.</p> <div class="paragraph"> <div class="title">User groups</div> <p><span class="image"><img src="./images/user-groups.png" alt="user groups"></span></p> </div> </li> <li> <p>Click <strong>Join Group</strong>.</p> </li> <li> <p>Select a group from the dialog.</p> </li> <li> <p>Select a group from the <strong>Available Groups</strong> tree.</p> </li> <li> <p>Click <strong>Join</strong>.</p> </li> </ol> </div> <div class="paragraph"> <p>To remove a group from a user:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Click <strong>Users</strong> in the menu.</p> </li> <li> <p>Click the user to be removed from the group.</p> </li> <li> <p>Click <strong>Leave</strong> on the group table row.</p> </li> </ol> </div> <div class="paragraph"> <p>In this example, the user <em>jimlincoln</em> is in the <em>North America</em> group. You can see <em>jimlincoln</em> displayed under the <strong>Members</strong> tab for the group.</p> </div> <div class="paragraph"> <div class="title">Group membership</div> <p><span class="image"><img src="./images/group-membership.png" alt="group membership"></span></p> </div> <div class="sect3"> <h4 id="con-comparing-groups-roles_server_administration_guide"><a class="anchor" href="#con-comparing-groups-roles_server_administration_guide"></a>Groups compared to roles</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/roles-groups/con-comparing-groups-roles.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/roles-groups/con-comparing-groups-roles.adoc&amp;description=%0A%0AFile:%20server_admin/topics/roles-groups/con-comparing-groups-roles.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>Groups and roles have some similarities and differences. In Keycloak, groups are a collection of users to which you apply roles and attributes. Roles define types of users, and applications assign permissions and access control to roles.</p> </div> <div class="paragraph"> <p><a href="#_composite-roles">Composite Roles</a> are similar to Groups as they provide the same functionality. The difference between them is conceptual. Composite roles apply the permission model to a set of services and applications. Use composite roles to manage applications and services.</p> </div> <div class="paragraph"> <p>Groups focus on collections of users and their roles in an organization. Use groups to manage users.</p> </div> </div> <div class="sect3"> <h4 id="proc-specifying-default-groups_server_administration_guide"><a class="anchor" href="#proc-specifying-default-groups_server_administration_guide"></a>Using default groups</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/roles-groups/proc-specifying-default-groups.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/roles-groups/proc-specifying-default-groups.adoc&amp;description=%0A%0AFile:%20server_admin/topics/roles-groups/proc-specifying-default-groups.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>To automatically assign group membership to any users who is created or who is imported through <a href="#_identity_broker">Identity Brokering</a>, you use default groups.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Click <strong>Realm settings</strong> in the menu.</p> </li> <li> <p>Click the <strong>User registration</strong> tab.</p> </li> <li> <p>Click the <strong>Default Groups</strong> tab.</p> <div class="paragraph"> <div class="title">Default groups</div> <p><span class="image"><img src="./images/default-groups.png" alt="Default groups"></span></p> </div> </li> </ol> </div> <div class="paragraph"> <p>This screenshot shows that some <em>default groups</em> already exist.</p> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="configuring-authentication_server_administration_guide"><a class="anchor" href="#configuring-authentication_server_administration_guide"></a>Configuring authentication</h2> <div class="sectionbody"> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/authentication.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/authentication.adoc&amp;description=%0A%0AFile:%20server_admin/topics/authentication.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>This chapter covers several authentication topics. These topics include:</p> </div> <div class="ulist"> <ul> <li> <p>Enforcing strict password and One Time Password (OTP) policies.</p> </li> <li> <p>Managing different credential types.</p> </li> <li> <p>Logging in with Kerberos.</p> </li> <li> <p>Disabling and enabling built-in credential types.</p> </li> </ul> </div> <div class="sect2"> <h3 id="_password-policies"><a class="anchor" href="#_password-policies"></a>Password policies</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/authentication/password-policies.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/authentication/password-policies.adoc&amp;description=%0A%0AFile:%20server_admin/topics/authentication/password-policies.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>When Keycloak creates a realm, it does not associate password policies with the realm. You can set a simple password with no restrictions on its length, security, or complexity. Simple passwords are unacceptable in production environments. Keycloak has a set of password policies available through the Admin Console.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Authentication</strong> in the menu.</p> </li> <li> <p>Click the <strong>Policies</strong> tab.</p> </li> <li> <p>Select the policy to add in the <strong>Add policy</strong> drop-down box.</p> </li> <li> <p>Enter a value that applies to the policy chosen.</p> </li> <li> <p>Click <strong>Save</strong>.</p> <div class="paragraph"> <p>Password policy <span class="image"><img src="./images/password-policy.png" alt="Password Policy"></span></p> </div> </li> </ol> </div> <div class="paragraph"> <p>After saving the policy, Keycloak enforces the policy for new users.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>The new policy will not be effective for existing users. Therefore, make sure that you set the password policy from the beginning of the realm creation or add "Update password" to existing users or use "Expire password" to make sure that users update their passwords in next "N" days, which will actually adjust to new password policies.</p> </div> </td> </tr> </table> </div> <div class="sect3"> <h4 id="password-policy-types"><a class="anchor" href="#password-policy-types"></a>Password policy types</h4> <div class="sect4"> <h5 id="hashalgorithm"><a class="anchor" href="#hashalgorithm"></a>HashAlgorithm</h5> <div class="paragraph"> <p>Passwords are not stored in cleartext. Before storage or validation, Keycloak hashes passwords using standard hashing algorithms.</p> </div> <div class="paragraph"> <p>Supported password hashing algorithms include:</p> </div> <div class="ulist"> <ul> <li> <p>argon2:: Argon2 (default for non-FIPS deployments)</p> </li> <li> <p>pbkdf2-sha512:: PBKDF2 with SHA512 (default for FIPS deployments)</p> </li> <li> <p>pbkdf2-sha256:: PBKDF2 with SHA256</p> </li> <li> <p>pbkdf2:: PBKDF2 with SHA1 (deprecated)</p> </li> </ul> </div> <div class="paragraph"> <p>It is highly recommended to use Argon2 when possible as it has significantly less CPU requirements compared to PBKDF2, while at the same time being more secure.</p> </div> <div class="paragraph"> <p>The default password hashing algorithm for the server can be configured with <code>--spi-password-hashing-provider-default=&lt;algorithm&gt;</code>.</p> </div> <div class="paragraph"> <p>To prevent excessive memory and CPU usage, the parallel computation of hashes by Argon2 is by default limited to the number of cores available to the JVM. To configure the Argon2 hashing provider, use its provider options.</p> </div> <div class="paragraph"> <p>See the <a href="https://www.keycloak.org/docs/26.0.6/server_development/">Server Developer Guide</a> on how to add your own hashing algorithm.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>If you change the hashing algorithm, password hashes in storage will not change until the user logs in.</p> </div> </td> </tr> </table> </div> </div> <div class="sect4"> <h5 id="hashing-iterations"><a class="anchor" href="#hashing-iterations"></a>Hashing iterations</h5> <div class="paragraph"> <p>Specifies the number of times Keycloak hashes passwords before storage or verification. The default value is -1, which uses the default hashing intervals for the selected hashing algorithm:</p> </div> <div class="ulist"> <ul> <li> <p>argon2:: 5</p> </li> <li> <p>pbkdf2-sha512:: 210,000</p> </li> <li> <p>pbkdf2-sha256:: 600,000</p> </li> <li> <p>pbkdf2:: 1,300,000</p> </li> </ul> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>In most cases the hashing iterations should not be changed from the recommended default values. Lower values for iterations provide insufficient security, while higher values result in higher CPU power requirements.</p> </div> </td> </tr> </table> </div> </div> <div class="sect4"> <h5 id="digits"><a class="anchor" href="#digits"></a>Digits</h5> <div class="paragraph"> <p>The number of numerical digits required in the password string.</p> </div> </div> <div class="sect4"> <h5 id="lowercase-characters"><a class="anchor" href="#lowercase-characters"></a>Lowercase characters</h5> <div class="paragraph"> <p>The number of lower case letters required in the password string.</p> </div> </div> <div class="sect4"> <h5 id="uppercase-characters"><a class="anchor" href="#uppercase-characters"></a>Uppercase characters</h5> <div class="paragraph"> <p>The number of upper case letters required in the password string.</p> </div> </div> <div class="sect4"> <h5 id="special-characters"><a class="anchor" href="#special-characters"></a>Special characters</h5> <div class="paragraph"> <p>The number of special characters required in the password string.</p> </div> </div> <div class="sect4"> <h5 id="not-username"><a class="anchor" href="#not-username"></a>Not username</h5> <div class="paragraph"> <p>The password cannot be the same as the username.</p> </div> </div> <div class="sect4"> <h5 id="not-email"><a class="anchor" href="#not-email"></a>Not email</h5> <div class="paragraph"> <p>The password cannot be the same as the email address of the user.</p> </div> </div> <div class="sect4"> <h5 id="regular-expression"><a class="anchor" href="#regular-expression"></a>Regular expression</h5> <div class="paragraph"> <p>Password must match one or more defined Java regular expression patterns. See <a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/regex/Pattern.html">Java&#8217;s regular expression documentation</a> for the syntax of those expressions.</p> </div> </div> <div class="sect4"> <h5 id="expire-password"><a class="anchor" href="#expire-password"></a>Expire password</h5> <div class="paragraph"> <p>The number of days the password is valid. When the number of days has expired, the user must change their password.</p> </div> </div> <div class="sect4"> <h5 id="not-recently-used"><a class="anchor" href="#not-recently-used"></a>Not recently used</h5> <div class="paragraph"> <p>Password cannot be already used by the user. Keycloak stores a history of used passwords. The number of old passwords stored is configurable in Keycloak.</p> </div> </div> <div class="sect4"> <h5 id="not-recently-used-in-days"><a class="anchor" href="#not-recently-used-in-days"></a>Not recently used (In Days)</h5> <div class="paragraph"> <p>Password cannot be reused within the configured time period (in days). If the new password was last set within this period, the user will be forced to provide a different one.</p> </div> </div> <div class="sect4"> <h5 id="password-blacklist"><a class="anchor" href="#password-blacklist"></a>Password blacklist</h5> <div class="paragraph"> <p>Password must not be in a blacklist file.</p> </div> <div class="ulist"> <ul> <li> <p>Blacklist files are UTF-8 plain-text files with Unix line endings. Every line represents a blacklisted password.</p> </li> <li> <p>Keycloak compares passwords in a case-insensitive manner.</p> </li> <li> <p>The value of the blacklist file must be the name of the blacklist file, for example, <code>100k_passwords.txt</code>.</p> </li> <li> <p>Blacklist files resolve against <code>${kc.home.dir}/data/password-blacklists/</code> by default. Customize this path using:</p> <div class="ulist"> <ul> <li> <p>The <code>keycloak.password.blacklists.path</code> system property.</p> </li> <li> <p>The <code>blacklistsPath</code> property of the <code>passwordBlacklist</code> policy SPI configuration. To configure the blacklist folder using the CLI, use <code>--spi-password-policy-password-blacklist-blacklists-path=/path/to/blacklistsFolder</code>.</p> </li> </ul> </div> </li> </ul> </div> <div class="paragraph"> <div class="title">A note about False Positives</div> <p>The current implementation uses a BloomFilter for fast and memory efficient containment checks, such as whether a given password is contained in a blacklist, with the possibility for false positives.</p> </div> <div class="ulist"> <ul> <li> <p>By default a false positive probability of <code>0.01%</code> is used.</p> </li> <li> <p>To change the false positive probability by CLI configuration, use <code>--spi-password-policy-password-blacklist-false-positive-probability=0.00001</code>.</p> </li> </ul> </div> </div> <div class="sect4"> <h5 id="maximum-authentication-age"><a class="anchor" href="#maximum-authentication-age"></a>Maximum Authentication Age</h5> <div class="paragraph"> <p>Specifies the maximum age of a user authentication in seconds with which the user can update a password without re-authentication. A value of <code>0</code> indicates that the user has to always re-authenticate with their current password before they can update the password. See <a href="#con-aia-reauth_server_administration_guide">AIA section</a> for some additional details about this policy.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> The Maximum Authentication Age is configurable also when configuring the required action <strong>Update Password</strong> in the <strong>Required Actions</strong> tab in the Admin Console. The better choice is to use the required action for the configuration because the <em>Maximum Authentication Age</em> password policy might be deprecated/removed in the future. </td> </tr> </table> </div> </div> </div> </div> <div class="sect2"> <h3 id="one-time-password-otp-policies"><a class="anchor" href="#one-time-password-otp-policies"></a>One Time Password (OTP) policies</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/authentication/otp-policies.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/authentication/otp-policies.adoc&amp;description=%0A%0AFile:%20server_admin/topics/authentication/otp-policies.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Keycloak has several policies for setting up a FreeOTP or Google Authenticator One-Time Password generator.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Authentication</strong> in the menu.</p> </li> <li> <p>Click the <strong>Policy</strong> tab.</p> </li> <li> <p>Click the <strong>OTP Policy</strong> tab.</p> </li> </ol> </div> <div class="paragraph"> <div class="title">Otp Policy</div> <p><span class="image"><img src="./images/otp-policy.png" alt="OTP Policy"></span></p> </div> <div class="paragraph"> <p>Keycloak generates a QR code on the OTP set-up page, based on information configured in the <strong>OTP Policy</strong> tab. FreeOTP and Google Authenticator scan the QR code when configuring OTP.</p> </div> <div class="sect3"> <h4 id="time-based-or-counter-based-one-time-passwords"><a class="anchor" href="#time-based-or-counter-based-one-time-passwords"></a>Time-based or counter-based one time passwords</h4> <div class="paragraph"> <p>The algorithms available in Keycloak for your OTP generators are time-based and counter-based.</p> </div> <div class="paragraph"> <p>With Time-Based One Time Passwords (TOTP), the token generator will hash the current time and a shared secret. The server validates the OTP by comparing the hashes within a window of time to the submitted value. TOTPs are valid for a short window of time.</p> </div> <div class="paragraph"> <p>With Counter-Based One Time Passwords (HOTP), Keycloak uses a shared counter rather than the current time. The Keycloak server increments the counter with each successful OTP login. Valid OTPs change after a successful login.</p> </div> <div class="paragraph"> <p>TOTP is more secure than HOTP because the matchable OTP is valid for a short window of time, while the OTP for HOTP is valid for an indeterminate amount of time. HOTP is more user-friendly than TOTP because no time limit exists to enter the OTP.</p> </div> <div class="paragraph"> <p>HOTP requires a database update every time the server increments the counter. This update is a performance drain on the authentication server during heavy load. To increase efficiency, TOTP does not remember passwords used, so there is no need to perform database updates. The drawback is that it is possible to reuse TOTPs in the valid time interval.</p> </div> </div> <div class="sect3"> <h4 id="totp-configuration-options"><a class="anchor" href="#totp-configuration-options"></a>TOTP configuration options</h4> <div class="sect4"> <h5 id="otp-hash-algorithm"><a class="anchor" href="#otp-hash-algorithm"></a>OTP hash algorithm</h5> <div class="paragraph"> <p>The default algorithm is SHA1. The other, more secure options are SHA256 and SHA512.</p> </div> </div> <div class="sect4"> <h5 id="number-of-digits"><a class="anchor" href="#number-of-digits"></a>Number of digits</h5> <div class="paragraph"> <p>The length of the OTP. Short OTP&#8217;s are user-friendly, easier to type, and easier to remember. Longer OTP&#8217;s are more secure than shorter OTP&#8217;s.</p> </div> </div> <div class="sect4"> <h5 id="look-around-window"><a class="anchor" href="#look-around-window"></a>Look around window</h5> <div class="paragraph"> <p>The number of intervals the server attempts to match the hash. This option is present in Keycloak if the clock of the TOTP generator or authentication server becomes out-of-sync. The default value of 1 is adequate. For example, if the time interval for a token is 30 seconds, the default value of 1 means it will accept valid tokens in the 90-second window (time interval 30 seconds + look ahead 30 seconds + look behind 30 seconds). Every increment of this value increases the valid window by 60 seconds (look ahead 30 seconds + look behind 30 seconds).</p> </div> </div> <div class="sect4"> <h5 id="otp-token-period"><a class="anchor" href="#otp-token-period"></a>OTP token period</h5> <div class="paragraph"> <p>The time interval in seconds the server matches a hash. Each time the interval passes, the token generator generates a TOTP.</p> </div> </div> <div class="sect4"> <h5 id="reusable-code"><a class="anchor" href="#reusable-code"></a>Reusable code</h5> <div class="paragraph"> <p>Determine whether OTP tokens can be reused in the authentication process or user needs to wait for the next token. Users cannot reuse those tokens by default, and the administrator needs to explicitly specify that those tokens can be reused.</p> </div> </div> </div> <div class="sect3"> <h4 id="hotp-configuration-options"><a class="anchor" href="#hotp-configuration-options"></a>HOTP configuration options</h4> <div class="sect4"> <h5 id="otp-hash-algorithm-2"><a class="anchor" href="#otp-hash-algorithm-2"></a>OTP hash algorithm</h5> <div class="paragraph"> <p>The default algorithm is SHA1. The other, more secure options are SHA256 and SHA512.</p> </div> </div> <div class="sect4"> <h5 id="number-of-digits-2"><a class="anchor" href="#number-of-digits-2"></a>Number of digits</h5> <div class="paragraph"> <p>The length of the OTP. Short OTPs are user-friendly, easier to type, and easier to remember. Longer OTPs are more secure than shorter OTPs.</p> </div> </div> <div class="sect4"> <h5 id="look-around-window-2"><a class="anchor" href="#look-around-window-2"></a>Look around window</h5> <div class="paragraph"> <p>The number of previous and following intervals the server attempts to match the hash. This option is present in Keycloak if the clock of the TOTP generator or authentication server become out-of-sync. The default value of 1 is adequate. This option is present in Keycloak to cover when the user&#8217;s counter gets ahead of the server.</p> </div> </div> <div class="sect4"> <h5 id="initial-counter"><a class="anchor" href="#initial-counter"></a>Initial counter</h5> <div class="paragraph"> <p>The value of the initial counter.</p> </div> </div> </div> </div> <div class="sect2"> <h3 id="_authentication-flows"><a class="anchor" href="#_authentication-flows"></a>Authentication flows</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/authentication/flows.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/authentication/flows.adoc&amp;description=%0A%0AFile:%20server_admin/topics/authentication/flows.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>An <em>authentication flow</em> is a container of authentications, screens, and actions, during log in, registration, and other Keycloak workflows.</p> </div> <div class="sect3"> <h4 id="built-in-flows"><a class="anchor" href="#built-in-flows"></a>Built-in flows</h4> <div class="paragraph"> <p>Keycloak has several built-in flows. You cannot modify these flows, but you can alter the flow&#8217;s requirements to suit your needs.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Authentication</strong> in the menu.</p> </li> <li> <p>Click on the <em>Browser</em> item in the list to see the details.</p> </li> </ol> </div> <div class="paragraph"> <div class="title">Browser flow</div> <p><span class="image"><img src="./images/browser-flow.png" alt="Browser Flow"></span></p> </div> <div class="sect4"> <h5 id="auth-type"><a class="anchor" href="#auth-type"></a>Auth type</h5> <div class="paragraph"> <p>The name of the authentication or the action to execute. If an authentication is indented, it is in a sub-flow. It may or may not be executed, depending on the behavior of its parent.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Cookie</p> <div class="paragraph"> <p>The first time a user logs in successfully, Keycloak sets a session cookie. If the cookie is already set, this authentication type is successful. Since the cookie provider returned success and each execution at this level of the flow is <em>alternative</em>, Keycloak does not perform any other execution. This results in a successful login.</p> </div> </li> <li> <p>Kerberos</p> <div class="paragraph"> <p>This authenticator is disabled by default and is skipped during the Browser Flow.</p> </div> </li> <li> <p>Identity Provider Redirector</p> <div class="paragraph"> <p>This action is configured through the <strong>Actions</strong> &gt; <strong>Config</strong> link. It redirects to another IdP for <a href="#_identity_broker">identity brokering</a>.</p> </div> </li> <li> <p>Forms</p> <div class="paragraph"> <p>Since this sub-flow is marked as <em>alternative</em>, it will not be executed if the <strong>Cookie</strong> authentication type passed. This sub-flow contains an additional authentication type that needs to be executed. Keycloak loads the executions for this sub-flow and processes them.</p> </div> </li> </ol> </div> <div class="paragraph"> <p>The first execution is the <strong>Username Password Form</strong>, an authentication type that renders the username and password page. It is marked as <em>required</em>, so the user must enter a valid username and password.</p> </div> <div class="paragraph"> <p>The second execution is the <strong>Browser - Conditional OTP</strong> sub-flow. This sub-flow is <em>conditional</em> and executes depending on the result of the <strong>Condition - User Configured</strong> execution. If the result is true, Keycloak loads the executions for this sub-flow and processes them.</p> </div> <div class="paragraph"> <p>The next execution is the <strong>Condition - User Configured</strong> authentication. This authentication checks if Keycloak has configured other executions in the flow for the user. The <strong>Browser - Conditional OTP</strong> sub-flow executes only when the user has a configured OTP credential.</p> </div> <div class="paragraph"> <p>The final execution is the <strong>OTP Form</strong>. Keycloak marks this execution as <em>required</em> but it runs only when the user has an OTP credential set up because of the setup in the <em>conditional</em> sub-flow. If not, the user does not see an OTP form.</p> </div> </div> <div class="sect4"> <h5 id="requirement"><a class="anchor" href="#requirement"></a>Requirement</h5> <div class="paragraph"> <p>A set of radio buttons that control the execution of an action executes.</p> </div> <div class="sect5"> <h6 id="_execution-requirements"><a class="anchor" href="#_execution-requirements"></a>Required</h6> <div class="paragraph"> <p>All <em>Required</em> elements in the flow must be successfully sequentially executed. The flow terminates if a required element fails.</p> </div> </div> <div class="sect5"> <h6 id="alternative"><a class="anchor" href="#alternative"></a>Alternative</h6> <div class="paragraph"> <p>Only a single element must successfully execute for the flow to evaluate as successful. Because the <em>Required</em> flow elements are sufficient to mark a flow as successful, any <em>Alternative</em> flow element within a flow containing <em>Required</em> flow elements will not execute.</p> </div> </div> <div class="sect5"> <h6 id="disabled"><a class="anchor" href="#disabled"></a>Disabled</h6> <div class="paragraph"> <p>The element does not count to mark a flow as successful.</p> </div> </div> <div class="sect5"> <h6 id="conditional"><a class="anchor" href="#conditional"></a>Conditional</h6> <div class="paragraph"> <p>This requirement type is only set on sub-flows.</p> </div> <div class="ulist"> <ul> <li> <p>A <em>Conditional</em> sub-flow contains executions. These executions must evaluate to logical statements.</p> </li> <li> <p>If all executions evaluate as <em>true</em>, the <em>Conditional</em> sub-flow acts as <em>Required</em>.</p> </li> <li> <p>If any executions evaluate as <em>false</em>, the <em>Conditional</em> sub-flow acts as <em>Disabled</em>.</p> </li> <li> <p>If you do not set an execution, the <em>Conditional</em> sub-flow acts as <em>Disabled</em>.</p> </li> <li> <p>If a flow contains executions and the flow is not set to <em>Conditional</em>, Keycloak does not evaluate the executions, and the executions are considered functionally <em>Disabled</em>.</p> </li> </ul> </div> </div> </div> </div> <div class="sect3"> <h4 id="creating-flows"><a class="anchor" href="#creating-flows"></a>Creating flows</h4> <div class="paragraph"> <p>Important functionality and security considerations apply when you design a flow.</p> </div> <div class="paragraph"> <p>To create a flow, perform the following:</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Authentication</strong> in the menu.</p> </li> <li> <p>Click <strong>Create flow</strong>.</p> </li> </ol> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>You can copy and then modify an existing flow. Click the "Action list" (the three dots at the end of the row), click <strong>Duplicate</strong>, and enter a name for the new flow.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>When creating a new flow, you must create a top-level flow first with the following options:</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Name</dt> <dd> <p>The name of the flow.</p> </dd> <dt class="hdlist1">Description</dt> <dd> <p>The description you can set to the flow.</p> </dd> <dt class="hdlist1">Top-Level Flow Type</dt> <dd> <p>The type of flow. The type <strong>client</strong> is used only for the authentication of clients (applications). For all other cases, choose <strong>basic</strong>.</p> </dd> </dl> </div> <div class="paragraph"> <div class="title">Create a top-level flow</div> <p><span class="image"><img src="./images/Create-top-level-flow.png" alt="Top Level Flow"></span></p> </div> <div class="paragraph"> <p>When Keycloak has created the flow, Keycloak displays the <strong>Add step</strong>, and <strong>Add sub-flow</strong> buttons.</p> </div> <div class="paragraph"> <div class="title">An empty new flow</div> <p><span class="image"><img src="./images/New-flow.png" alt="New Flow"></span></p> </div> <div class="paragraph"> <p>Three factors determine the behavior of flows and sub-flows.</p> </div> <div class="ulist"> <ul> <li> <p>The structure of the flow and sub-flows.</p> </li> <li> <p>The executions within the flows</p> </li> <li> <p>The requirements set within the sub-flows and the executions.</p> </li> </ul> </div> <div class="paragraph"> <p>Executions have a wide variety of actions, from sending a reset email to validating an OTP. Add executions with the <strong>Add step</strong> button.</p> </div> <div class="paragraph"> <div class="title">Adding an authentication execution</div> <p><span class="image"><img src="./images/Create-authentication-execution.png" alt="Adding an Authentication Execution"></span></p> </div> <div class="paragraph"> <p>Authentication executions can optionally have a reference value configured. This can be utilized by the <em>Authentication Method Reference (AMR)</em> protocol mapper to populate the <em>amr</em> claim in OIDC access and ID tokens (for more information on the AMR claim, see <a href="https://www.rfc-editor.org/rfc/rfc8176.html">RFC-8176</a>). When the <em>Authentication Method Reference (AMR)</em> protocol mapper is configured for a client, it will populate the <em>amr</em> claim with the reference value for any authenticator execution the user successfully completes during the authentication flow.</p> </div> <div class="paragraph"> <div class="title">Adding an authenticator reference value</div> <p><span class="image"><img src="./images/config-authenticator-reference.png" alt="Configuring an Authenticator Reference Value"></span></p> </div> <div class="paragraph"> <p>Two types of executions exist, <em>automatic executions</em> and <em>interactive executions</em>. <em>Automatic executions</em> are similar to the <strong>Cookie</strong> execution and will automatically perform their action in the flow. <em>Interactive executions</em> halt the flow to get input. Executions executing successfully set their status to <em>success</em>. For a flow to complete, it needs at least one execution with a status of <em>success</em>.</p> </div> <div class="paragraph"> <p>You can add sub-flows to top-level flows with the <strong>Add sub-flow</strong> button. The <strong>Add sub-flow</strong> button displays the <strong>Create Execution Flow</strong> page. This page is similar to the <strong>Create Top Level Form</strong> page. The difference is that the <strong>Flow Type</strong> can be <strong>basic</strong> (default) or <strong>form</strong>. The <strong>form</strong> type constructs a sub-flow that generates a form for the user, similar to the built-in <strong>Registration</strong> flow. Sub-flows success depends on how their executions evaluate, including their contained sub-flows. See the <a href="#_execution-requirements">execution requirements section</a> for an in-depth explanation of how sub-flows work.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>After adding an execution, check the requirement has the correct value.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>All elements in a flow have a <strong>Delete</strong> option next to the element. Some executions have a <strong>⚙️</strong> menu item (the gear icon) to configure the execution. It is also possible to add executions and sub-flows to sub-flows with the <strong>Add step</strong> and <strong>Add sub-flow</strong> links.</p> </div> <div class="paragraph"> <p>Since the order of execution is important, you can move executions and sub-flows up and down by dragging their names.</p> </div> <div class="admonitionblock warning"> <table> <tr> <td class="icon"> <i class="fa icon-warning" title="Warning"></i> </td> <td class="content"> <div class="paragraph"> <p>Make sure to properly test your configuration when you configure the authentication flow to confirm that no security holes exist in your setup. We recommend that you test various corner cases. For example, consider testing the authentication behavior for a user when you remove various credentials from the user&#8217;s account before authentication.</p> </div> <div class="paragraph"> <p>As an example, when 2nd-factor authenticators, such as OTP Form or WebAuthn Authenticator, are configured in the flow as REQUIRED and the user does not have credential of particular type, the user will be able to set up the particular credential during authentication itself. This situation means that the user does not authenticate with this credential as he set up it right during the authentication. So for browser authentication, make sure to configure your authentication flow with some 1st-factor credentials such as Password or WebAuthn Passwordless Authenticator.</p> </div> </td> </tr> </table> </div> </div> <div class="sect3"> <h4 id="creating-a-password-less-browser-login-flow"><a class="anchor" href="#creating-a-password-less-browser-login-flow"></a>Creating a password-less browser login flow</h4> <div class="paragraph"> <p>To illustrate the creation of flows, this section describes creating an advanced browser login flow. The purpose of this flow is to allow a user a choice between logging in using a password-less manner with <a href="#webauthn_server_administration_guide">WebAuthn</a>, or two-factor authentication with a password and OTP.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Authentication</strong> in the menu.</p> </li> <li> <p>Click the <strong>Flows</strong> tab.</p> </li> <li> <p>Click <strong>Create flow</strong>.</p> </li> <li> <p>Enter <code>Browser Password-less</code> as a name.</p> </li> <li> <p>Click <strong>Create</strong>.</p> </li> <li> <p>Click <strong>Add execution</strong>.</p> </li> <li> <p>Select <strong>Cookie</strong> from the list.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> <li> <p>Select <strong>Alternative</strong> for the <strong>Cookie</strong> authentication type to set its requirement to alternative.</p> </li> <li> <p>Click <strong>Add step</strong>.</p> </li> <li> <p>Select <strong>Kerberos</strong> from the list.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> <li> <p>Click <strong>Add step</strong>.</p> </li> <li> <p>Select <strong>Identity Provider Redirector</strong> from the list.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> <li> <p>Select <strong>Alternative</strong> for the <strong>Identity Provider Redirector</strong> authentication type to set its requirement to alternative.</p> </li> <li> <p>Click <strong>Add sub-flow</strong>.</p> </li> <li> <p>Enter <strong>Forms</strong> as a name.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> <li> <p>Select <strong>Alternative</strong> for the <strong>Forms</strong> authentication type to set its requirement to alternative.</p> <div class="paragraph"> <div class="title">The common part with the browser flow</div> <p><span class="image"><img src="./images/Passwordless-browser-login-common.png" alt="Passwordless browser login"></span></p> </div> </li> <li> <p>Click <strong>+</strong> menu of the <strong>Forms</strong> execution.</p> </li> <li> <p>Select <strong>Add step</strong>.</p> </li> <li> <p>Select <strong>Username Form</strong> from the list.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> </ol> </div> <div class="paragraph"> <p>At this stage, the form requires a username but no password. We must enable password authentication to avoid security risks.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Click <strong>+</strong> menu of the <strong>Forms</strong> sub-flow.</p> </li> <li> <p>Click <strong>Add sub-flow</strong>.</p> </li> <li> <p>Enter <code>Authentication</code> as name.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> <li> <p>Select <strong>Required</strong> for the <strong>Authentication</strong> authentication type to set its requirement to required.</p> </li> <li> <p>Click <strong>+</strong> menu of the <strong>Authentication</strong> sub-flow.</p> </li> <li> <p>Click <strong>Add step</strong>.</p> </li> <li> <p>Select <strong>WebAuthn Passwordless Authenticator</strong> from the list.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> <li> <p>Select <strong>Alternative</strong> for the <strong>Webauthn Passwordless Authenticator</strong> authentication type to set its requirement to alternative.</p> </li> <li> <p>Click <strong>+</strong> menu of the <strong>Authentication</strong> sub-flow.</p> </li> <li> <p>Click <strong>Add sub-flow</strong>.</p> </li> <li> <p>Enter <code>Password with OTP</code> as name.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> <li> <p>Select <strong>Alternative</strong> for the <strong>Password with OTP</strong> authentication type to set its requirement to alternative.</p> </li> <li> <p>Click <strong>+</strong> menu of the <strong>Password with OTP</strong> sub-flow.</p> </li> <li> <p>Click <strong>Add step</strong>.</p> </li> <li> <p>Select <strong>Password Form</strong> from the list.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> <li> <p>Select <strong>Required</strong> for the <strong>Password Form</strong> authentication type to set its requirement to required.</p> </li> <li> <p>Click <strong>+</strong> menu of the <strong>Password with OTP</strong> sub-flow.</p> </li> <li> <p>Click <strong>Add step</strong>.</p> </li> <li> <p>Select <strong>OTP Form</strong> from the list.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> <li> <p>Click <strong>Required</strong> for the <strong>OTP Form</strong> authentication type to set its requirement to required.</p> </li> </ol> </div> <div class="paragraph"> <p>Finally, change the bindings.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Click the <strong>Action</strong> menu at the top of the screen.</p> </li> <li> <p>Select <strong>Bind flow</strong> from the menu.</p> </li> <li> <p>Click the <strong>Browser Flow</strong> drop-down list.</p> </li> <li> <p>Click <strong>Save</strong>.</p> </li> </ol> </div> <div class="paragraph"> <div class="title">A password-less browser login</div> <p><span class="image"><img src="./images/Passwordless-browser-login.png" alt="Passwordless browser login"></span></p> </div> <div class="paragraph"> <p>After entering the username, the flow works as follows:</p> </div> <div class="paragraph"> <p>If users have WebAuthn passwordless credentials recorded, they can use these credentials to log in directly. This is the password-less login. The user can also select <strong>Password with OTP</strong> because the <code>WebAuthn Passwordless</code> execution and the <code>Password with OTP</code> flow are set to <strong>Alternative</strong>. If they are set to <strong>Required</strong>, the user has to enter WebAuthn, password, and OTP.</p> </div> <div class="paragraph"> <p>If the user selects the <strong>Try another way</strong> link with <code>WebAuthn passwordless</code> authentication, the user can choose between <code>Password</code> and <code>Passkey</code> (WebAuthn passwordless). When selecting the password, the user will need to continue and log in with the assigned OTP. If the user has no WebAuthn credentials, the user must enter the password and then the OTP. If the user has no OTP credential, they will be asked to record one.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>Since the WebAuthn Passwordless execution is set to <strong>Alternative</strong> rather than <strong>Required</strong>, this flow will never ask the user to register a WebAuthn credential. For a user to have a Webauthn credential, an administrator must add a required action to the user. Do this by:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Enabling the <strong>Webauthn Register Passwordless</strong> required action in the realm (see the <a href="#webauthn_server_administration_guide">WebAuthn</a> documentation).</p> </li> <li> <p>Setting the required action using the <strong>Credential Reset</strong> part of a user&#8217;s <a href="#ref-user-credentials_server_administration_guide">Credentials</a> management menu.</p> </li> </ol> </div> <div class="paragraph"> <p>Creating an advanced flow such as this can have side effects. For example, if you enable the ability to reset the password for users, this would be accessible from the password form. In the default <code>Reset Credentials</code> flow, users must enter their username. Since the user has already entered a username earlier in the <code>Browser Password-less</code> flow, this action is unnecessary for Keycloak and suboptimal for user experience. To correct this problem, you can:</p> </div> <div class="ulist"> <ul> <li> <p>Duplicate the <code>Reset Credentials</code> flow. Set its name to <code>Reset Credentials for password-less</code>, for example.</p> </li> <li> <p>Click <strong>Delete</strong> (trash icon) of the <strong>Choose user</strong> step.</p> </li> <li> <p>In the <strong>Action</strong> menu, select <strong>Bind flow</strong> and select <strong>Reset credentials flow</strong> from the dropdown and click <strong>Save</strong></p> </li> </ul> </div> </td> </tr> </table> </div> </div> <div class="sect3"> <h4 id="_step-up-flow"><a class="anchor" href="#_step-up-flow"></a>Creating a browser login flow with step-up mechanism</h4> <div class="paragraph"> <p>This section describes how to create advanced browser login flow using the step-up mechanism. The purpose of step-up authentication is to allow access to clients or resources based on a specific authentication level of a user.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Authentication</strong> in the menu.</p> </li> <li> <p>Click the <strong>Flows</strong> tab.</p> </li> <li> <p>Click <strong>Create flow</strong>.</p> </li> <li> <p>Enter <code>Browser Incl Step up Mechanism</code> as a name.</p> </li> <li> <p>Click <strong>Save</strong>.</p> </li> <li> <p>Click <strong>Add execution</strong>.</p> </li> <li> <p>Select <strong>Cookie</strong> from the list.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> <li> <p>Select <strong>Alternative</strong> for the <strong>Cookie</strong> authentication type to set its requirement to alternative.</p> </li> <li> <p>Click <strong>Add sub-flow</strong>.</p> </li> <li> <p>Enter <strong>Auth Flow</strong> as a name.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> <li> <p>Click <strong>Alternative</strong> for the <strong>Auth Flow</strong> authentication type to set its requirement to alternative.</p> </li> </ol> </div> <div class="paragraph"> <p>Now you configure the flow for the first authentication level.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Click <strong>+</strong> menu of the <strong>Auth Flow</strong>.</p> </li> <li> <p>Click <strong>Add sub-flow</strong>.</p> </li> <li> <p>Enter <code>1st Condition Flow</code> as a name.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> <li> <p>Click <strong>Conditional</strong> for the <strong>1st Condition Flow</strong> authentication type to set its requirement to conditional.</p> </li> <li> <p>Click <strong>+</strong> menu of the <strong>1st Condition Flow</strong>.</p> </li> <li> <p>Click <strong>Add condition</strong>.</p> </li> <li> <p>Select <strong>Conditional - Level Of Authentication</strong> from the list.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> <li> <p>Click <strong>Required</strong> for the <strong>Conditional - Level Of Authentication</strong> authentication type to set its requirement to required.</p> </li> <li> <p>Click <strong>⚙️</strong> (gear icon).</p> </li> <li> <p>Enter <code>Level 1</code> as an alias.</p> </li> <li> <p>Enter <code>1</code> for the Level of Authentication (LoA).</p> </li> <li> <p>Set Max Age to <strong>36000</strong>. This value is in seconds and it is equivalent to 10 hours, which is the default <code>SSO Session Max</code> timeout set in the realm. As a result, when a user authenticates with this level, subsequent SSO logins can reuse this level and the user does not need to authenticate with this level until the end of the user session, which is 10 hours by default.</p> </li> <li> <p>Click <strong>Save</strong></p> <div class="paragraph"> <div class="title">Configure the condition for the first authentication level</div> <p><span class="image"><img src="./images/authentication-step-up-condition-1.png" alt="Authentication step up condition 1"></span></p> </div> </li> <li> <p>Click <strong>+</strong> menu of the <strong>1st Condition Flow</strong>.</p> </li> <li> <p>Click <strong>Add step</strong>.</p> </li> <li> <p>Select <strong>Username Password Form</strong> from the list.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> </ol> </div> <div class="paragraph"> <p>Now you configure the flow for the second authentication level.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Click <strong>+</strong> menu of the <strong>Auth Flow</strong>.</p> </li> <li> <p>Click <strong>Add sub-flow</strong>.</p> </li> <li> <p>Enter <code>2nd Condition Flow</code> as an alias.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> <li> <p>Click <strong>Conditional</strong> for the <strong>2nd Condition Flow</strong> authentication type to set its requirement to conditional.</p> </li> <li> <p>Click <strong>+</strong> menu of the <strong>2nd Condition Flow</strong>.</p> </li> <li> <p>Click <strong>Add condition</strong>.</p> </li> <li> <p>Select <strong>Conditional - Level Of Authentication</strong> from the item list.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> <li> <p>Click <strong>Required</strong> for the <strong>Conditional - Level Of Authentication</strong> authentication type to set its requirement to required.</p> </li> <li> <p>Click <strong>⚙️</strong> (gear icon).</p> </li> <li> <p>Enter <code>Level 2</code> as an alias.</p> </li> <li> <p>Enter <code>2</code> for the Level of Authentication (LoA).</p> </li> <li> <p>Set Max Age to <strong>0</strong>. As a result, when a user authenticates, this level is valid just for the current authentication, but not any subsequent SSO authentications. So the user will always need to authenticate again with this level when this level is requested.</p> </li> <li> <p>Click <strong>Save</strong></p> <div class="paragraph"> <div class="title">Configure the condition for the second authentication level</div> <p><span class="image"><img src="./images/authentication-step-up-condition-2.png" alt="Autehtnication step up condition 2"></span></p> </div> </li> <li> <p>Click <strong>+</strong> menu of the <strong>2nd Condition Flow</strong>.</p> </li> <li> <p>Click <strong>Add step</strong>.</p> </li> <li> <p>Select <strong>OTP Form</strong> from the list.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> <li> <p>Click <strong>Required</strong> for the <strong>OTP Form</strong> authentication type to set its requirement to required.</p> </li> </ol> </div> <div class="paragraph"> <p>Finally, change the bindings.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Click the <strong>Action</strong> menu at the top of the screen.</p> </li> <li> <p>Select <strong>Bind flow</strong> from the list.</p> </li> <li> <p>Select <strong>Browser Flow</strong> in the dropdown.</p> </li> <li> <p>Click <strong>Save</strong>.</p> </li> </ol> </div> <div class="paragraph"> <div class="title">Browser login with step-up mechanism</div> <p><span class="image"><img src="./images/authentication-step-up-flow.png" alt="Authentication step up flow"></span></p> </div> <div class="paragraph"> <div class="title">Request a certain authentication level</div> <p>To use the step-up mechanism, you specify a requested level of authentication (LoA) in your authentication request. The <code>claims</code> parameter is used for this purpose:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>https://{DOMAIN}/realms/{REALMNAME}/protocol/openid-connect/auth?client_id={CLIENT-ID}&amp;redirect_uri={REDIRECT-URI}&amp;scope=openid&amp;response_type=code&amp;response_mode=query&amp;nonce=exg16fxdjcu&amp;claims=%7B%22id_token%22%3A%7B%22acr%22%3A%7B%22essential%22%3Atrue%2C%22values%22%3A%5B%22gold%22%5D%7D%7D%7D</code></pre> </div> </div> <div class="paragraph"> <p>The <code>claims</code> parameter is specified in a JSON representation:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>claims= { "id_token": { "acr": { "essential": true, "values": ["gold"] } } }</code></pre> </div> </div> <div class="paragraph"> <p>The Keycloak javascript adapter has support for easy construct of this JSON and sending it in the login request. See <strong>Keycloak JavaScript adapter</strong> in the <a href="https://www.keycloak.org/guides#securing-apps">securing apps</a> section for more details.</p> </div> <div class="paragraph"> <p>You can also use simpler parameter <code>acr_values</code> instead of <code>claims</code> parameter to request particular levels as non-essential. This is mentioned in the OIDC specification.</p> </div> <div class="paragraph"> <p>You can also configure the default level for the particular client, which is used when the parameter <code>acr_values</code> or the parameter <code>claims</code> with the <code>acr</code> claim is not present. For further details, see <a href="#_mapping-acr-to-loa-client">Client ACR configuration</a>).</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> To request the acr_values as text (such as <code>gold</code>) instead of a numeric value, you configure the mapping between the ACR and the LoA. It is possible to configure it at the realm level (recommended) or at the client level. For configuration see <a href="#_mapping-acr-to-loa-realm">ACR to LoA Mapping</a>. </td> </tr> </table> </div> <div class="paragraph"> <p>For more details see the <a href="https://openid.net/specs/openid-connect-core-1_0.html#acrSemantics">official OIDC specification</a>.</p> </div> <div class="paragraph"> <p><strong>Flow logic</strong></p> </div> <div class="paragraph"> <p>The logic for the previous configured authentication flow is as follows:<br> If a client request a high authentication level, meaning Level of Authentication 2 (LoA 2), a user has to perform full 2-factor authentication: Username/Password + OTP. However, if a user already has a session in Keycloak, that was logged in with username and password (LoA 1), the user is only asked for the second authentication factor (OTP).</p> </div> <div class="paragraph"> <p>The option <strong>Max Age</strong> in the condition determines how long (how much seconds) the subsequent authentication level is valid. This setting helps to decide whether the user will be asked to present the authentication factor again during a subsequent authentication. If the particular level X is requested by the <code>claims</code> or <code>acr_values</code> parameter and user already authenticated with level X, but it is expired (for example max age is configured to 300 and user authenticated before 310 seconds) then the user will be asked to re-authenticate again with the particular level. However if the level is not yet expired, the user will be automatically considered as authenticated with that level.</p> </div> <div class="paragraph"> <p>Using <strong>Max Age</strong> with the value 0 means, that particular level is valid just for this single authentication. Hence every re-authentication requesting that level will need to authenticate again with that level. This is useful for operations that require higher security in the application (e.g. send payment) and always require authentication with the specific level.</p> </div> <div class="admonitionblock warning"> <table> <tr> <td class="icon"> <i class="fa icon-warning" title="Warning"></i> </td> <td class="content"> Note that parameters such as <code>claims</code> or <code>acr_values</code> might be changed by the user in the URL when the login request is sent from the client to the Keycloak via the user&#8217;s browser. This situation can be mitigated if client uses PAR (Pushed authorization request), a request object, or other mechanisms that prevents the user from rewrite the parameters in the URL. Hence after the authentication, clients are encouraged to check the ID Token to double-check that <code>acr</code> in the token corresponds to the expected level. </td> </tr> </table> </div> <div class="paragraph"> <p>If no explicit level is requested by parameters, the Keycloak will require the authentication with the first LoA condition found in the authentication flow, such as the Username/Password in the preceding example. When a user was already authenticated with that level and that level expired, the user is not required to re-authenticate, but <code>acr</code> in the token will have the value 0. This result is considered as authentication based solely on <code>long-lived browser cookie</code> as mentioned in the section 2 of OIDC Core 1.0 specification.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> During the first authentication of the user, the first configured subflow with the <strong>Conditional - Level Of Authentication</strong> is always executed (regardless of the requested level) as the user does not yet have any level. Therefore, we recommend that the first level subflow contains the minimal required authenticators for user authentication. In addition, ensure that the subflows with different values of <strong>Conditional - Level Of Authentication</strong> are ordered starting with the lowest as shown in the example above. For example, if you configure a subflow with level 2 and then add another subflow with level 1, the level 2 subflow will be always asked during the first authentication, which may not be the desired behavior. </td> </tr> </table> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> A conflict situation may arise when an admin specifies several flows, sets different LoA levels to each, and assigns the flows to different clients. However, the rule is always the same: if a user has a certain level, it needs only have that level to connect to a client. It&#8217;s up to the admin to make sure that the LoA is coherent. </td> </tr> </table> </div> <div class="paragraph"> <p><strong>Example scenario</strong></p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Max Age is configured as 300 seconds for level 1 condition.</p> </li> <li> <p>Login request is sent without requesting any acr. Level 1 will be used and the user needs to authenticate with username and password. The token will have <code>acr=1</code>.</p> </li> <li> <p>Another login request is sent after 100 seconds. The user is automatically authenticated due to the SSO and the token will return <code>acr=1</code>.</p> </li> <li> <p>Another login request is sent after another 201 seconds (301 seconds since authentication in point 2). The user is automatically authenticated due to the SSO, but the token will return <code>acr=0</code> due the level 1 is considered expired.</p> </li> <li> <p>Another login request is sent, but now it will explicitly request ACR of level 1 in the <code>claims</code> parameter. User will be asked to re-authenticate with username/password and then <code>acr=1</code> will be returned in the token.</p> </li> </ol> </div> <div class="paragraph"> <p><strong>ACR claim in the token</strong></p> </div> <div class="paragraph"> <p>ACR claim is added to the token by the <code>acr loa level</code> protocol mapper defined in the <code>acr</code> client scope. This client scope is the realm default client scope and hence will be added to all newly created clients in the realm.</p> </div> <div class="paragraph"> <p>In case you do not want <code>acr</code> claim inside tokens or you need some custom logic for adding it, you can remove the client scope from your client.</p> </div> <div class="paragraph"> <p>Note when the login request initiates a request with the <code>claims</code> parameter requesting <code>acr</code> as <code>essential</code> claim, then Keycloak will always return one of the specified levels. If it is not able to return one of the specified levels (For example if the requested level is unknown or bigger than configured conditions in the authentication flow), then Keycloak will throw an error.</p> </div> </div> <div class="sect3"> <h4 id="_registration-rc-client-flows"><a class="anchor" href="#_registration-rc-client-flows"></a>Registration or Reset credentials requested by client</h4> <div class="paragraph"> <p>Usually when the user is redirected to the Keycloak from client application, the <code>browser</code> flow is triggered. This flow may allow the user to <a href="#con-user-registration_server_administration_guide">register</a> in case that realm registration is enabled and the user clicks <code>Register</code> on the login screen. Also, if <a href="#enabling-forgot-password">Forget password</a> is enabled for the realm, the user can click <code>Forget password</code> on the login screen, which triggers the <code>Reset credentials</code> flow where users can reset credentials after email address confirmation.</p> </div> <div class="paragraph"> <p>Sometimes it can be useful for the client application to directly redirect the user to the <strong>Registration</strong> screen or to the <strong>Reset credentials</strong> flow. The resulting action will match the action of when the user clicks <strong>Register</strong> or <strong>Forget password</strong> on the normal login screen. Automatic redirect to the registration or reset-credentials screen can be done as follows:</p> </div> <div class="ulist"> <ul> <li> <p>When the client wants the user to be redirected directly to the registration, the OIDC client should replace the very last snippet from the OIDC login URL path (<code>/auth</code>) with <code>/registrations</code> . So the full URL might be similar to the following: <code><a href="https://keycloak.example.com/realms/your_realm/protocol/openid-connect/registrations" class="bare">https://keycloak.example.com/realms/your_realm/protocol/openid-connect/registrations</a></code>.</p> </li> <li> <p>When the client wants a user to be redirected directly to the <code>Reset credentials</code> flow, the OIDC client should replace the very last snippet from the OIDC login URL path (<code>/auth</code>) with <code>/forgot-credentials</code> .</p> </li> </ul> </div> <div class="admonitionblock warning"> <table> <tr> <td class="icon"> <i class="fa icon-warning" title="Warning"></i> </td> <td class="content"> The preceding steps are the only supported method for a client to directly request a registration or reset-credentials flow. For security purposes, it is not supported and recommended for client applications to bypass OIDC/SAML flows and directly redirect to other Keycloak endpoints (such as for instance endpoints under <code>/realms/realm_name/login-actions</code> or <code>/realms/realm_name/broker</code>). </td> </tr> </table> </div> </div> </div> <div class="sect2"> <h3 id="_user_session_limits"><a class="anchor" href="#_user_session_limits"></a>User session limits</h3> <div class="paragraph"> <p>Limits on the number of session that a user can have can be configured. Sessions can be limited per realm or per client.</p> </div> <div class="paragraph"> <p>To add session limits to a flow, perform the following steps.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Click <strong>Add step</strong> for the flow.</p> </li> <li> <p>Select <strong>User session count limiter</strong> from the item list.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> <li> <p>Click <strong>Required</strong> for the <strong>User Session Count Limiter</strong> authentication type to set its requirement to required.</p> </li> <li> <p>Click <strong>⚙️</strong> (gear icon) for the <strong>User Session Count Limiter</strong>.</p> </li> <li> <p>Enter an alias for this config.</p> </li> <li> <p>Enter the required maximum number of sessions that a user can have in this realm. For example, if 2 is the value, 2 SSO sessions is the maximum that each user can have in this realm. If 0 is the value, this check is disabled.</p> </li> <li> <p>Enter the required maximum number of sessions a user can have for the client. For example, if 2 is the value, then 2 SSO sessions is the maximum in this realm for each client. So when a user is trying to authenticate to client <code>foo</code>, but that user has already authenticated in 2 SSO sessions to client <code>foo</code>, either the authentication will be denied or an existing sessions will be killed based on the behavior configured. If a value of 0 is used, this check is disabled. If both session limits and client session limits are enabled, it makes sense to have client session limits to be always lower than session limits. The limit per client can never exceed the limit of all SSO sessions of this user.</p> </li> <li> <p>Select the behavior that is required when the user tries to create a session after the limit is reached. Available behaviors are:</p> <div class="ulist"> <ul> <li> <p><strong>Deny new session</strong> - when a new session is requested and the session limit is reached, no new sessions can be created.</p> </li> <li> <p><strong>Terminate oldest session</strong> - when a new session is requested and the session limit has been reached, the oldest session will be removed and the new session created.</p> </li> </ul> </div> </li> <li> <p>Optionally, add a custom error message to be displayed when the limit is reached.</p> </li> </ol> </div> <div class="paragraph"> <p>Note that the user session limits should be added to your bound <strong>Browser flow</strong>, <strong>Direct grant flow</strong>, <strong>Reset credentials</strong> and also to any <strong>Post broker login flow</strong>. The authenticator should be added at the point when the user is already known during authentication (usually at the end of the authentication flow) and should be typically REQUIRED. Note that it is not possible to have ALTERNATIVE and REQUIRED executions at the same level.</p> </div> <div class="paragraph"> <p>For most of authenticators like <code>Direct grant flow</code>, <code>Reset credentials</code> or <code>Post broker login flow</code>, it is recommended to add the authenticator as REQUIRED at the end of the authentication flow. Here is an example for the <code>Reset credentials</code> flow:</p> </div> <div class="paragraph"> <p><span class="image"><img src="./images/authentication-user-session-limits-resetcred.png" alt="Authentication User Session Limits Reset Credentials Flow"></span></p> </div> <div class="paragraph"> <p>For <code>Browser</code> flow, consider not adding the Session Limits authenticator at the top level flow. This recommendation is due to the <code>Cookie</code> authenticator, which automatically re-authenticates users based on SSO cookie. It is at the top level and it is better to not check session limits during SSO re-authentication because a user session already exists. So instead, consider adding a separate ALTERNATIVE subflow, such as the following <code>authenticate-user-with-session-limit</code> example at the same level like <code>Cookie</code>. Then you can add a REQUIRED subflow, in the following <code>real-authentication-subflow`example, as a nested subflow of `authenticate-user-with-session-limit</code> and add a <code>User Session Limit</code> at the same level as well. Inside the <code>real-authentication-subflow</code>, you can add real authenticators in a similar fashion to the default browser flow. The following example flow allows to users to authenticate with an identity provider or with password and OTP:</p> </div> <div class="paragraph"> <p><span class="image"><img src="./images/authentication-user-session-limits-browser.png" alt="Authentication User Session Limits Browser Flow"></span></p> </div> <div class="paragraph"> <p>Regarding <code>Post Broker login flow</code>, you can add the <code>User Session Limits</code> as the only authenticator in the authentication flow as long as you have no other authenticators that you trigger after authentication with your identity provider. However, make sure that this flow is configured as <code>Post Broker Flow</code> at your identity providers. This requirement exists needed so that the authentication with Identity providers also participates in the session limits.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> Currently, the administrator is responsible for maintaining consistency between the different configurations. So make sure that all your flows use same the configuration of <code>User Session Limits</code>. </td> </tr> </table> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> User session limit feature is not available for CIBA. </td> </tr> </table> </div> </div> <div class="sect2"> <h3 id="script-authenticator"><a class="anchor" href="#script-authenticator"></a>Script Authenticator</h3> <div class="paragraph"> <p>Ability to upload scripts through the Admin Console and REST endpoints is deprecated.</p> </div> <div class="paragraph"> <p>For more details see <a href="https://www.keycloak.org/docs/26.0.6/server_development/#_script_providers">JavaScript Providers</a>.</p> </div> </div> <div class="sect2"> <h3 id="_kerberos"><a class="anchor" href="#_kerberos"></a>Kerberos</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/authentication/kerberos.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/authentication/kerberos.adoc&amp;description=%0A%0AFile:%20server_admin/topics/authentication/kerberos.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Keycloak supports login with a Kerberos ticket through the Simple and Protected GSSAPI Negotiation Mechanism (SPNEGO) protocol. SPNEGO authenticates transparently through the web browser after the user authenticates the session. For non-web cases, or when a ticket is not available during login, Keycloak supports login with Kerberos username and password.</p> </div> <div class="paragraph"> <p>A typical use case for web authentication is the following:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>The user logs into the desktop.</p> </li> <li> <p>The user accesses a web application secured by Keycloak using a browser.</p> </li> <li> <p>The application redirects to Keycloak login.</p> </li> <li> <p>Keycloak renders the HTML login screen with status 401 and HTTP header <code>WWW-Authenticate: Negotiate</code></p> </li> <li> <p>If the browser has a Kerberos ticket from desktop login, the browser transfers the desktop sign-on information to Keycloak in header <code>Authorization: Negotiate 'spnego-token'</code>. Otherwise, it displays the standard login screen, and the user enters the login credentials.</p> </li> <li> <p>Keycloak validates the token from the browser and authenticates the user.</p> </li> <li> <p>If using LDAPFederationProvider with Kerberos authentication support, Keycloak provisions user data from LDAP. If using KerberosFederationProvider, Keycloak lets the user update the profile and pre-fill login data.</p> </li> <li> <p>Keycloak returns to the application. Keycloak and the application communicate through OpenID Connect or SAML messages. Keycloak acts as a broker to Kerberos/SPNEGO login. Therefore Keycloak authenticating through Kerberos is hidden from the application.</p> </li> </ol> </div> <div class="admonitionblock warning"> <table> <tr> <td class="icon"> <i class="fa icon-warning" title="Warning"></i> </td> <td class="content"> <div class="paragraph"> <p>The <a href="https://www.ietf.org/rfc/rfc4559.txt">Negotiate</a> www-authenticate scheme allows NTLM as a fallback to Kerberos and on some web browsers in Windows NTLM is supported by default. If a www-authenticate challenge comes from a server outside a browsers permitted list, users may encounter an NTLM dialog prompt. A user would need to click the cancel button on the dialog to continue as Keycloak does not support this mechanism. This situation can happen if Intranet web browsers are not strictly configured or if Keycloak serves users in both the Intranet and Internet. A <a href="https://github.com/keycloak/keycloak/issues/8989">custom authenticator</a> can be used to restrict Negotiate challenges to a whitelist of hosts.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>Perform the following steps to set up Kerberos authentication:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>The setup and configuration of the Kerberos server (KDC).</p> </li> <li> <p>The setup and configuration of the Keycloak server.</p> </li> <li> <p>The setup and configuration of the client machines.</p> </li> </ol> </div> <div class="sect3"> <h4 id="setup-of-kerberos-server"><a class="anchor" href="#setup-of-kerberos-server"></a>Setup of Kerberos server</h4> <div class="paragraph"> <p>The steps to set up a Kerberos server depends on the operating system (OS) and the Kerberos vendor. Consult Windows Active Directory, MIT Kerberos, and your OS documentation for instructions on setting up and configuring a Kerberos server.</p> </div> <div class="paragraph"> <p>During setup, perform these steps:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Add some user principals to your Kerberos database. You can also integrate your Kerberos with LDAP, so user accounts provision from the LDAP server.</p> </li> <li> <p>Add service principal for "HTTP" service. For example, if the Keycloak server runs on <code>www.mydomain.org</code>, add the service principal <code>HTTP/www.mydomain.org@&lt;kerberos realm&gt;</code>.</p> <div class="paragraph"> <p>On MIT Kerberos, you run a "kadmin" session. On a machine with MIT Kerberos, you can use the command:</p> </div> </li> </ol> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>sudo kadmin.local</code></pre> </div> </div> <div class="paragraph"> <p>Then, add HTTP principal and export its key to a keytab file with commands such as:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>addprinc -randkey HTTP/www.mydomain.org@MYDOMAIN.ORG ktadd -k /tmp/http.keytab HTTP/www.mydomain.org@MYDOMAIN.ORG</code></pre> </div> </div> <div class="paragraph"> <p>Ensure the keytab file <code>/tmp/http.keytab</code> is accessible on the host where Keycloak is running.</p> </div> </div> <div class="sect3"> <h4 id="setup-and-configuration-of-keycloak-server"><a class="anchor" href="#setup-and-configuration-of-keycloak-server"></a>Setup and configuration of Keycloak server</h4> <div id="_server_setup" class="paragraph"> <p>Install a Kerberos client on your machine.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Install a Kerberos client. If your machine runs Fedora, Ubuntu, or RHEL, install the <a href="https://www.freeipa.org/page/Downloads">freeipa-client</a> package, containing a Kerberos client and other utilities.</p> </li> <li> <p>Configure the Kerberos client (on Linux, the configuration settings are in the <a href="https://web.mit.edu/kerberos/krb5-1.21/doc/admin/conf_files/krb5_conf.html">/etc/krb5.conf</a> file ).</p> <div class="paragraph"> <p>Add your Kerberos realm to the configuration and configure the HTTP domains your server runs on.</p> </div> <div class="paragraph"> <p>For example, for the MYDOMAIN.ORG realm, you can configure the <code>domain_realm</code> section like this:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>[domain_realm] .mydomain.org = MYDOMAIN.ORG mydomain.org = MYDOMAIN.ORG</code></pre> </div> </div> </li> <li> <p>Export the keytab file with the HTTP principal and ensure the file is accessible to the process running the Keycloak server. For production, ensure that the file is readable by this process only.</p> <div class="paragraph"> <p>For the MIT Kerberos example above, we exported keytab to the <code>/tmp/http.keytab</code> file. If your <em>Key Distribution Centre (KDC)</em> and Keycloak run on the same host, the file is already available.</p> </div> </li> </ol> </div> <div class="sect4"> <h5 id="enabling-spnego-processing"><a class="anchor" href="#enabling-spnego-processing"></a>Enabling SPNEGO processing</h5> <div class="paragraph"> <p>By default, Keycloak disables SPNEGO protocol support. To enable it, go to the <a href="#_authentication-flows">browser flow</a> and enable <strong>Kerberos</strong>.</p> </div> <div class="paragraph"> <div class="title">Browser flow</div> <p><span class="image"><img src="./images/browser-flow.png" alt="Browser Flow"></span></p> </div> <div class="paragraph"> <p>Set the <strong>Kerberos</strong> requirement from <em>disabled</em> to <em>alternative</em> (Kerberos is optional) or <em>required</em> (browser must have Kerberos enabled). If you have not configured the browser to work with SPNEGO or Kerberos, Keycloak falls back to the regular login screen.</p> </div> </div> <div class="sect4"> <h5 id="configure-kerberos-user-storage-federation-providers"><a class="anchor" href="#configure-kerberos-user-storage-federation-providers"></a>Configure Kerberos user storage federation providers</h5> <div class="paragraph"> <p>You must now use <a href="#_user-storage-federation">User Storage Federation</a> to configure how Keycloak interprets Kerberos tickets. Two different federation providers exist with Kerberos authentication support.</p> </div> <div class="paragraph"> <p>To authenticate with Kerberos backed by an LDAP server, configure the <a href="#_ldap">LDAP Federation Provider</a>.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Go to the configuration page for your LDAP provider.</p> <div class="paragraph"> <div class="title">Ldap kerberos integration</div> <p><span class="image"><img src="./images/ldap-kerberos.png" alt="LDAP Kerberos Integration"></span></p> </div> </li> <li> <p>Toggle <strong>Allow Kerberos authentication</strong> to <strong>ON</strong></p> </li> </ol> </div> <div class="paragraph"> <p><strong>Allow Kerberos authentication</strong> makes Keycloak use the Kerberos principal access user information so information can import into the Keycloak environment.</p> </div> <div class="paragraph"> <p>If an LDAP server is not backing up your Kerberos solution, use the <strong>Kerberos</strong> User Storage Federation Provider.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>User Federation</strong> in the menu.</p> </li> <li> <p>Select <strong>Kerberos</strong> from the <strong>Add provider</strong> select box.</p> <div class="paragraph"> <div class="title">Kerberos user storage provider</div> <p><span class="image"><img src="./images/kerberos-provider.png" alt="Kerberos User Storage Provider"></span></p> </div> </li> </ol> </div> <div class="paragraph"> <p>The <strong>Kerberos</strong> provider parses the Kerberos ticket for simple principal information and imports the information into the local Keycloak database. User profile information, such as first name, last name, and email, are not provisioned.</p> </div> </div> </div> <div class="sect3"> <h4 id="setup-and-configuration-of-client-machines"><a class="anchor" href="#setup-and-configuration-of-client-machines"></a>Setup and configuration of client machines</h4> <div class="paragraph"> <p>Client machines must have a Kerberos client and set up the <code>krb5.conf</code> as described <a href="#_server_setup">above</a>. The client machines must also enable SPNEGO login support in their browser. See <a href="https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/7/html/system-level_authentication_guide/configuring_applications_for_sso">configuring Firefox for Kerberos</a> if you are using the Firefox browser.</p> </div> <div class="paragraph"> <p>The <code>.mydomain.org</code> URI must be in the <code>network.negotiate-auth.trusted-uris</code> configuration option.</p> </div> <div class="paragraph"> <p>In Windows domains, clients do not need to adjust their configuration. Internet Explorer and Edge can already participate in SPNEGO authentication.</p> </div> </div> <div class="sect3"> <h4 id="example-setups"><a class="anchor" href="#example-setups"></a>Example setups</h4> <div class="sect4"> <h5 id="keycloak-and-freeipa-docker-image"><a class="anchor" href="#keycloak-and-freeipa-docker-image"></a>Keycloak and FreeIPA docker image</h5> <div class="paragraph"> <p>When you install <a href="https://www.docker.com/">docker</a>, run a docker image with the FreeIPA server installed. FreeIPA provides an integrated security solution with MIT Kerberos and 389 LDAP server. The image also contains a Keycloak server configured with an LDAP Federation provider and enabled SPNEGO/Kerberos authentication against the FreeIPA server. See details <a href="https://github.com/mposolda/keycloak-freeipa-docker/blob/master/README.md">here</a>.</p> </div> </div> <div class="sect4"> <h5 id="apacheds-testing-kerberos-server"><a class="anchor" href="#apacheds-testing-kerberos-server"></a>ApacheDS testing Kerberos server</h5> <div class="paragraph"> <p>For quick testing and unit tests, use a simple <a href="https://directory.apache.org/apacheds/">ApacheDS</a> Kerberos server. You must build Keycloak from the source and then run the Kerberos server with the maven-exec-plugin from our test suite. See details <a href="https://github.com/keycloak/keycloak/blob/main/docs/tests.md#kerberos-server">here</a>.</p> </div> </div> </div> <div class="sect3"> <h4 id="credential-delegation"><a class="anchor" href="#credential-delegation"></a>Credential delegation</h4> <div class="paragraph"> <p>Kerberos supports the credential delegation. Applications may need access to the Kerberos ticket so they can reuse it to interact with other services secured by Kerberos. Because the Keycloak server processed the SPNEGO protocol, you must propagate the GSS credential to your application within the OpenID Connect token claim or a SAML assertion attribute. Keycloak transmits this to your application from the Keycloak server. To insert this claim into the token or assertion, each application must enable the built-in protocol mapper <code>gss delegation credential</code>. This mapper is available in the <strong>Mappers</strong> tab of the application&#8217;s client page. See <a href="#_protocol-mappers">Protocol Mappers</a> chapter for more details.</p> </div> <div class="paragraph"> <p>Applications must deserialize the claim it receives from Keycloak before using it to make GSS calls against other services. When you deserialize the credential from the access token to the GSSCredential object, create the GSSContext with this credential passed to the <code>GSSManager.createContext</code> method. For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Obtain accessToken in your application.</span> KeycloakPrincipal keycloakPrincipal = (KeycloakPrincipal) servletReq.getUserPrincipal(); AccessToken accessToken = keycloakPrincipal.getKeycloakSecurityContext().getToken(); <span class="comment">// Retrieve Kerberos credential from accessToken and deserialize it</span> <span class="predefined-type">String</span> serializedGssCredential = (<span class="predefined-type">String</span>) accessToken.getOtherClaims(). get(org.keycloak.common.constants.KerberosConstants.GSS_DELEGATION_CREDENTIAL); GSSCredential deserializedGssCredential = org.keycloak.common.util.KerberosSerializationUtils. deserializeCredential(serializedGssCredential); <span class="comment">// Create GSSContext to call other Kerberos-secured services</span> GSSContext context = gssManager.createContext(serviceName, krb5Oid, deserializedGssCredential, GSSContext.DEFAULT_LIFETIME);</code></pre> </div> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>Configure <code>forwardable</code> Kerberos tickets in <code>krb5.conf</code> file and add support for delegated credentials to your browser.</p> </div> </td> </tr> </table> </div> <div class="admonitionblock warning"> <table> <tr> <td class="icon"> <i class="fa icon-warning" title="Warning"></i> </td> <td class="content"> <div class="paragraph"> <p>Credential delegation has security implications, so use it only if necessary and only with HTTPS. See <a href="https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/7/html/system-level_authentication_guide/configuring_applications_for_sso">this article</a> for more details and an example.</p> </div> </td> </tr> </table> </div> </div> <div class="sect3"> <h4 id="cross-realm-trust"><a class="anchor" href="#cross-realm-trust"></a>Cross-realm trust</h4> <div class="paragraph"> <p>In the Kerberos protocol, the <code>realm</code> is a set of Kerberos principals. The definition of these principals exists in the Kerberos database, which is typically an LDAP server.</p> </div> <div class="paragraph"> <p>The Kerberos protocol allows cross-realm trust. For example, if 2 Kerberos realms, A and B, exist, then cross-realm trust will allow the users from realm A to access realm B&#8217;s resources. Realm B trusts realm A.</p> </div> <div class="paragraph"> <div class="title">Kerberos cross-realm trust</div> <p><span class="image"><img src="./images/kerberos-trust-basic.png" alt="kerberos trust basic"></span></p> </div> <div class="paragraph"> <p>The Keycloak server supports cross-realm trust. To implement this, perform the following:</p> </div> <div class="ulist"> <ul> <li> <p>Configure the Kerberos servers for the cross-realm trust. Implementing this step depends on the Kerberos server implementations. This step is necessary to add the Kerberos principal <code>krbtgt/B@A</code> to the Kerberos databases of realm A and B. This principal must have the same keys on both Kerberos realms. The principals must have the same password, key version numbers, and ciphers in both realms. Consult the Kerberos server documentation for more details.</p> </li> </ul> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>The cross-realm trust is unidirectional by default. You must add the principal <code>krbtgt/A@B</code> to both Kerberos databases for bidirectional trust between realm A and realm B. However, trust is transitive by default. If realm B trusts realm A and realm C trusts realm B, then realm C trusts realm A without the principal, <code>krbtgt/C@A</code>, available. Additional configuration (for example, <code>capaths</code>) may be necessary on the Kerberos client-side so clients can find the trust path. Consult the Kerberos documentation for more details.</p> </div> </td> </tr> </table> </div> <div class="ulist"> <ul> <li> <p>Configure Keycloak server</p> <div class="ulist"> <ul> <li> <p>When using an LDAP storage provider with Kerberos support, configure the server principal for realm B, as in this example: <code>HTTP/mydomain.com@B</code>. The LDAP server must find the users from realm A if users from realm A are to successfully authenticate to Keycloak, because Keycloak must perform the SPNEGO flow and then find the users.</p> </li> </ul> </div> </li> </ul> </div> <div class="paragraph"> <p>Finding users is based on the LDAP storage provider option <code>Kerberos principal attribute</code>. When this is configured for instance with value like <code>userPrincipalName</code>, then after SPNEGO authentication of user <code>john@A</code>, Keycloak will try to lookup LDAP user with attribute <code>userPrincipalName</code> equivalent to <code>john@A</code>. If <code>Kerberos principal attribute</code> is left empty, then Keycloak will lookup the LDAP user based on the prefix of his kerberos principal with the realm omitted. For example, Kerberos principal user <code>john@A</code> must be available in the LDAP under username <code>john</code>, so typically under an LDAP DN such as <code>uid=john,ou=People,dc=example,dc=com</code>. If you want users from realm A and B to authenticate, ensure that LDAP can find users from both realms A and B.</p> </div> <div class="ulist"> <ul> <li> <p>When using a Kerberos user storage provider (typically, Kerberos without LDAP integration), configure the server principal as <code>HTTP/mydomain.com@B</code>, and users from Kerberos realms A and B must be able to authenticate.</p> </li> </ul> </div> <div class="paragraph"> <p>Users from multiple Kerberos realms are allowed to authenticate as every user would have attribute <code>KERBEROS_PRINCIPAL</code> referring to the kerberos principal used for authentication and this is used for further lookups of this user. To avoid conflicts when there is user <code>john</code> in both kerberos realms <code>A</code> and <code>B</code>, the username of the Keycloak user might contain the kerberos realm lowercased. For instance username would be <code>john@a</code>. Just in case when realm matches with the configured <code>Kerberos realm</code>, the realm suffix might be omitted from the generated username. For instance username would be <code>john</code> for the Kerberos principal <code>john@A</code> as long as the <code>Kerberos realm</code> is configured on the Kerberos provider is <code>A</code>.</p> </div> </div> <div class="sect3"> <h4 id="troubleshooting"><a class="anchor" href="#troubleshooting"></a>Troubleshooting</h4> <div class="paragraph"> <p>If you have issues, enable additional logging to debug the problem:</p> </div> <div class="ulist"> <ul> <li> <p>Enable <code>Debug</code> flag in the Admin Console for Kerberos or LDAP federation providers</p> </li> <li> <p>Enable TRACE logging for category <code>org.keycloak</code> to receive more information in server logs</p> </li> <li> <p>Add system properties <code>-Dsun.security.krb5.debug=true</code> and <code>-Dsun.security.spnego.debug=true</code></p> </li> </ul> </div> </div> </div> <div class="sect2"> <h3 id="_x509"><a class="anchor" href="#_x509"></a>X.509 client certificate user authentication</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/authentication/x509.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/authentication/x509.adoc&amp;description=%0A%0AFile:%20server_admin/topics/authentication/x509.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Keycloak supports logging in with an X.509 client certificate if you have configured the server to use mutual SSL authentication.</p> </div> <div class="paragraph"> <p>A typical workflow:</p> </div> <div class="ulist"> <ul> <li> <p>A client sends an authentication request over SSL/TLS channel.</p> </li> <li> <p>During the SSL/TLS handshake, the server and the client exchange their x.509/v3 certificates.</p> </li> <li> <p>The container (WildFly) validates the certificate PKIX path and the certificate expiration date.</p> </li> <li> <p>The x.509 client certificate authenticator validates the client certificate by using the following methods:</p> <div class="ulist"> <ul> <li> <p>Checks the certificate revocation status by using CRL or CRL Distribution Points.</p> </li> <li> <p>Checks the Certificate revocation status by using OCSP (Online Certificate Status Protocol).</p> </li> <li> <p>Validates whether the key in the certificate matches the expected key.</p> </li> <li> <p>Validates whether the extended key in the certificate matches the expected extended key.</p> </li> </ul> </div> </li> <li> <p>If any of the these checks fail, the x.509 authentication fails. Otherwise, the authenticator extracts the certificate identity and maps it to an existing user.</p> </li> </ul> </div> <div class="paragraph"> <p>When the certificate maps to an existing user, the behavior diverges depending on the authentication flow:</p> </div> <div class="ulist"> <ul> <li> <p>In the Browser Flow, the server prompts users to confirm their identity or sign in with a username and password.</p> </li> <li> <p>In the Direct Grant Flow, the server signs in the user.</p> </li> </ul> </div> <div class="admonitionblock important"> <table> <tr> <td class="icon"> <i class="fa icon-important" title="Important"></i> </td> <td class="content"> Note that it is the responsibility of the web container to validate certificate PKIX path. X.509 authenticator on the Keycloak side provides just the additional support for check the certificate expiration, certificate revocation status and key usage. If you are using Keycloak deployed behind reverse proxy, make sure that your reverse proxy is configured to validate PKIX path. If you do not use reverse proxy and users directly access the WildFly, you should be fine as WildFly makes sure that PKIX path is validated as long as it is configured as described below. </td> </tr> </table> </div> <div class="sect3"> <h4 id="features-2"><a class="anchor" href="#features-2"></a>Features</h4> <div class="paragraph"> <p>Supported Certificate Identity Sources:</p> </div> <div class="ulist"> <ul> <li> <p>Match SubjectDN by using regular expressions</p> </li> <li> <p>X500 Subject&#8217;s email attribute</p> </li> <li> <p>X500 Subject&#8217;s email from Subject Alternative Name Extension (RFC822Name General Name)</p> </li> <li> <p>X500 Subject&#8217;s other name from Subject Alternative Name Extension. This other name is the User Principal Name (UPN), typically.</p> </li> <li> <p>X500 Subject&#8217;s Common Name attribute</p> </li> <li> <p>Match IssuerDN by using regular expressions</p> </li> <li> <p>Certificate Serial Number</p> </li> <li> <p>Certificate Serial Number and IssuerDN</p> </li> <li> <p>SHA-256 Certificate thumbprint</p> </li> <li> <p>Full certificate in PEM format</p> </li> </ul> </div> <div class="sect4"> <h5 id="regular-expressions"><a class="anchor" href="#regular-expressions"></a>Regular expressions</h5> <div class="paragraph"> <p>Keycloak extracts the certificate identity from Subject DN or Issuer DN by using a regular expression as a filter. For example, this regular expression matches the email attribute:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>emailAddress=(.*?)(?:,|$)</code></pre> </div> </div> <div class="paragraph"> <p>The regular expression filtering applies if the <code>Identity Source</code> is set to either <code>Match SubjectDN using regular expression</code> or <code>Match IssuerDN using regular expression</code>.</p> </div> <div class="sect5"> <h6 id="mapping-certificate-identity-to-an-existing-user"><a class="anchor" href="#mapping-certificate-identity-to-an-existing-user"></a>Mapping certificate identity to an existing user</h6> <div class="paragraph"> <p>The certificate identity mapping can map the extracted user identity to an existing user&#8217;s username, email, or a custom attribute whose value matches the certificate identity. For example, setting <code>Identity source</code> to <em>Subject&#8217;s email</em> or <code>User mapping method</code> to <em>Username or email</em> makes the X.509 client certificate authenticator use the email attribute in the certificate&#8217;s Subject DN as the search criteria when searching for an existing user by username or by email.</p> </div> <div class="admonitionblock important"> <table> <tr> <td class="icon"> <i class="fa icon-important" title="Important"></i> </td> <td class="content"> <div class="ulist"> <ul> <li> <p>If you disable <strong>Login with email</strong> at realm settings, the same rules apply to certificate authentication. Users are unable to log in by using the email attribute.</p> </li> <li> <p>Using <code>Certificate Serial Number and IssuerDN</code> as an identity source requires two custom attributes for the serial number and the IssuerDN.</p> </li> <li> <p><code>SHA-256 Certificate thumbprint</code> is the lowercase hexadecimal representation of SHA-256 certificate thumbprint.</p> </li> <li> <p>Using <code>Full certificate in PEM format</code> as an identity source is limited to the custom attributes mapped to external federation sources, such as LDAP. Keycloak cannot store certificates in its database due to length limitations, so in the case of LDAP, you must enable <code>Always Read Value From LDAP</code>.</p> </li> </ul> </div> </td> </tr> </table> </div> </div> <div class="sect5"> <h6 id="extended-certificate-validation"><a class="anchor" href="#extended-certificate-validation"></a>Extended certificate validation</h6> <div class="ulist"> <ul> <li> <p>Revocation status checking using CRL.</p> </li> <li> <p>Revocation status checking using CRL/Distribution Point.</p> </li> <li> <p>Revocation status checking using OCSP/Responder URI.</p> </li> <li> <p>Certificate KeyUsage validation.</p> </li> <li> <p>Certificate ExtendedKeyUsage validation.</p> </li> </ul> </div> </div> </div> </div> <div class="sect3"> <h4 id="_browser_flow"><a class="anchor" href="#_browser_flow"></a>Adding X.509 client certificate authentication to browser flows</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Click <strong>Authentication</strong> in the menu.</p> </li> <li> <p>Click the <strong>Browser</strong> flow.</p> </li> <li> <p>From the <strong>Action</strong> list, select <strong>Duplicate</strong>.</p> </li> <li> <p>Enter a name for the copy.</p> </li> <li> <p>Click <strong>Duplicate</strong>.</p> </li> <li> <p>Click <strong>Add step</strong>.</p> </li> <li> <p>Click "X509/Validate Username Form".</p> </li> <li> <p>Click <strong>Add</strong>.</p> <div class="paragraph"> <div class="title">X509 execution</div> <p><span class="image"><img src="./images/x509-execution.png" alt="X509 Execution"></span></p> </div> </li> <li> <p>Click and drag the "X509/Validate Username Form" over the "Browser Forms" execution.</p> </li> <li> <p>Set the requirement to "ALTERNATIVE".</p> <div class="paragraph"> <div class="title">X509 browser flow</div> <p><span class="image"><img src="./images/x509-browser-flow.png" alt="X509 Browser Flow"></span></p> </div> </li> <li> <p>Click the <strong>Action</strong> menu.</p> </li> <li> <p>Click the <strong>Bind flow</strong>.</p> </li> <li> <p>Click the <strong>Browser flow</strong> from the drop-down list.</p> </li> <li> <p>Click <strong>Save</strong>.</p> <div class="paragraph"> <div class="title">X509 browser flow bindings</div> <p><span class="image"><img src="./images/x509-browser-flow-bindings.png" alt="X509 Browser Flow Bindings"></span></p> </div> </li> </ol> </div> </div> <div class="sect3"> <h4 id="_x509-config"><a class="anchor" href="#_x509-config"></a>Configuring X.509 client certificate authentication</h4> <div class="paragraph"> <div class="title">X509 configuration</div> <p><span class="image"><img src="./images/x509-configuration.png" alt="X509 Configuration"></span></p> </div> <div class="dlist"> <dl> <dt class="hdlist1"><strong>User Identity Source</strong></dt> <dd> <p>Defines the method for extracting the user identity from a client certificate.</p> </dd> <dt class="hdlist1"><strong>Canonical DN representation enabled</strong></dt> <dd> <p>Defines whether to use canonical format to determine a distinguished name. The official <a href="https://docs.oracle.com/javase/8/docs/api/javax/security/auth/x500/X500Principal.html#getName-java.lang.String-">Java API documentation</a> describes the format. This option affects the two User Identity Sources <em>Match SubjectDN using regular expression</em> and <em>Match IssuerDN using regular expression</em> only. Enable this option when you set up a new Keycloak instance. Disable this option to retain backward compatibility with existing Keycloak instances.</p> </dd> <dt class="hdlist1"><strong>Enable Serial Number hexadecimal representation</strong></dt> <dd> <p>Represent the <a href="https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.2">serial number</a> as hexadecimal. The serial number with the sign bit set to 1 must be left padded with 00 octet. For example, a serial number with decimal value <em>161</em>, or <em>a1</em> in hexadecimal representation is encoded as <em>00a1</em>, according to RFC5280. See <a href="https://datatracker.ietf.org/doc/html/rfc5280#appendix-B">RFC5280, appendix-B</a> for more details.</p> </dd> <dt class="hdlist1"><strong>A regular expression</strong></dt> <dd> <p>A regular expression to use as a filter for extracting the certificate identity. The expression must contain a single group.</p> </dd> <dt class="hdlist1"><strong>User Mapping Method</strong></dt> <dd> <p>Defines the method to match the certificate identity with an existing user. <em>Username or email</em> searches for existing users by username or email. <em>Custom Attribute Mapper</em> searches for existing users with a custom attribute that matches the certificate identity. The name of the custom attribute is configurable.</p> </dd> <dt class="hdlist1"><strong>A name of user attribute</strong></dt> <dd> <p>A custom attribute whose value matches against the certificate identity. Use multiple custom attributes when attribute mapping is related to multiple values, For example, 'Certificate Serial Number and IssuerDN'.</p> </dd> <dt class="hdlist1"><strong>CRL Checking Enabled</strong></dt> <dd> <p>Check the revocation status of the certificate by using the Certificate Revocation List. The location of the list is defined in the <strong>CRL file path</strong> attribute.</p> </dd> <dt class="hdlist1"><strong>Enable CRL Distribution Point to check certificate revocation status</strong></dt> <dd> <p>Use CDP to check the certificate revocation status. Most PKI authorities include CDP in their certificates.</p> </dd> <dt class="hdlist1"><strong>CRL file path</strong></dt> <dd> <p>The path to a file containing a CRL list. The value must be a path to a valid file if the <strong>CRL Checking Enabled</strong> option is enabled.</p> </dd> <dt class="hdlist1"><strong>OCSP Checking Enabled</strong></dt> <dd> <p>Checks the certificate revocation status by using Online Certificate Status Protocol.</p> </dd> <dt class="hdlist1"><strong>OCSP Fail-Open Behavior</strong></dt> <dd> <p>By default the OCSP check must return a positive response in order to continue with a successful authentication. Sometimes however this check can be inconclusive: for example, the OCSP server could be unreachable, overloaded, or the client certificate may not contain an OCSP responder URI. When this setting is turned ON, authentication will be denied only if an explicit negative response is received by the OCSP responder and the certificate is definitely revoked. If a valid OCSP response is not available the authentication attempt will be accepted.</p> </dd> <dt class="hdlist1"><strong>OCSP Responder URI</strong></dt> <dd> <p>Override the value of the OCSP responder URI in the certificate.</p> </dd> <dt class="hdlist1"><strong>Validate Key Usage</strong></dt> <dd> <p>Verifies the certificate&#8217;s KeyUsage extension bits are set. For example, "digitalSignature,KeyEncipherment" verifies if bits 0 and 2 in the KeyUsage extension are set. Leave this parameter empty to disable the Key Usage validation. See <a href="https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.3">RFC5280, Section-4.2.1.3</a> for more information. Keycloak raises an error when a key usage mismatch occurs.</p> </dd> <dt class="hdlist1"><strong>Validate Extended Key Usage</strong></dt> <dd> <p>Verifies one or more purposes defined in the Extended Key Usage extension. See <a href="https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.12">RFC5280, Section-4.2.1.12</a> for more information. Leave this parameter empty to disable the Extended Key Usage validation. Keycloak raises an error when flagged as critical by the issuing CA and a key usage extension mismatch occurs.</p> </dd> <dt class="hdlist1"><strong>Validate Certificate Policy</strong></dt> <dd> <p>Verifies one or more policy OIDs as defined in the Certificate Policy extension. See <a href="https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4">RFC5280, Section-4.2.1.4</a>. Leave the parameter empty to disable the Certificate Policy validation. Multiple policies should be separated using a comma.</p> </dd> <dt class="hdlist1"><strong>Certificate Policy Validation Mode</strong></dt> <dd> <p>When more than one policy is specified in the <code>Validate Certificate Policy</code> setting, it decides whether the matching should check for all requested policies to be present, or one match is enough for a successful authentication. Default value is <code>All</code>, meaning that all requested policies should be present in the client certificate.</p> </dd> <dt class="hdlist1"><strong>Bypass identity confirmation</strong></dt> <dd> <p>If enabled, X.509 client certificate authentication does not prompt the user to confirm the certificate identity. Keycloak signs in the user upon successful authentication.</p> </dd> <dt class="hdlist1"><strong>Revalidate client certificate</strong></dt> <dd> <p>If set, the client certificate trust chain will be always verified at the application level using the certificates present in the configured trust store. This can be useful if the underlying web server does not enforce client certificate chain validation, for example because it is behind a non-validating load balancer or reverse proxy, or when the number of allowed CAs is too large for the mutual SSL negotiation (most browsers cap the maximum SSL negotiation packet size at 32767 bytes, which corresponds to about 200 advertised CAs). By default this option is off.</p> </dd> </dl> </div> </div> <div class="sect3"> <h4 id="adding-x-509-client-certificate-authentication-to-a-direct-grant-flow"><a class="anchor" href="#adding-x-509-client-certificate-authentication-to-a-direct-grant-flow"></a>Adding X.509 Client Certificate Authentication to a Direct Grant Flow</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Click <strong>Authentication</strong> in the menu.</p> </li> <li> <p>Select <strong>Duplicate</strong> from the "Action list" to make a copy of the built-in "Direct grant" flow.</p> </li> <li> <p>Enter a name for the copy.</p> </li> <li> <p>Click <strong>Duplicate</strong>.</p> </li> <li> <p>Click the created flow.</p> </li> <li> <p>Click the trash can icon 🗑️ of the "Username Validation" and click <strong>Delete</strong>.</p> </li> <li> <p>Click the trash can icon 🗑️ of the "Password" and click <strong>Delete</strong>.</p> </li> <li> <p>Click <strong>Add step</strong>.</p> </li> <li> <p>Click "X509/Validate Username".</p> </li> <li> <p>Click <strong>Add</strong>.</p> <div class="paragraph"> <div class="title">X509 direct grant execution</div> <p><span class="image"><img src="./images/x509-directgrant-execution.png" alt="X509 Direct Grant Execution"></span></p> </div> </li> <li> <p>Set up the x509 authentication configuration by following the steps described in the <a href="#_browser_flow">x509 Browser Flow</a> section.</p> </li> <li> <p>Click the <strong>Bindings</strong> tab.</p> </li> <li> <p>Click the <strong>Direct Grant Flow</strong> drop-down list.</p> </li> <li> <p>Click the newly created "x509 Direct Grant" flow.</p> </li> <li> <p>Click <strong>Save</strong>.</p> <div class="paragraph"> <div class="title">X509 direct grant flow bindings</div> <p><span class="image"><img src="./images/x509-directgrant-flow-bindings.png" alt="X509 Direct Grant Flow Bindings"></span></p> </div> </li> </ol> </div> <div class="sect4"> <h5 id="example-using-curl"><a class="anchor" href="#example-using-curl"></a>Example using CURL</h5> <div class="paragraph"> <p>The following example shows how to obtain an access token for a user in the realm <code>test</code> with the direct grant flow. The example is using <strong>OAuth2 Resource Owner Password Credentials Grant</strong> in the <a href="https://www.keycloak.org/guides#securing-apps">securing apps</a> section and the confidential client <code>resource-owner</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">curl \ -d &quot;client_id=resource-owner&quot; \ -d &quot;client_secret=40cc097b-2a57-4c17-b36a-8fdf3fc2d578&quot; \ -d &quot;grant_type=password&quot; \ --cacert /tmp/truststore.pem \ --cert /tmp/keystore.pem:kssecret \ &quot;https://localhost:8543/realms/test/protocol/openid-connect/token&quot;</code></pre> </div> </div> <div class="paragraph"> <p>The file <code>/tmp/truststore.pem</code> points to the file with the truststore containing the certificate of the Keycloak server. The file <code>/tmp/keystore.pem</code> contains the private key and certificates corresponding to the Keycloak user, which would be successfully authenticated by this request. It is dependent on the configuration of the authenticator on how exactly is the content from the certificate mapped to the Keycloak user as described in <a href="#_x509-config">the configuration section</a>. The <code>kssecret</code> might be the password of this keystore file.</p> </div> <div class="paragraph"> <p>According to your environment, it might be needed to use more options to CURL commands like for instance:</p> </div> <div class="ulist"> <ul> <li> <p>Option <code>--insecure</code> if you are using self-signed certificates</p> </li> <li> <p>Option <code>--capath</code> to include the whole directory containing the certificate authority path</p> </li> <li> <p>Options <code>--cert-type</code> or <code>--key-type</code> in case you want to use different files than <code>PEM</code></p> </li> </ul> </div> <div class="paragraph"> <p>Please consult the documentation of the <code>curl</code> tool for the details if needed. If you are using other tools than <code>curl</code>, consult the documentation of your tool. However, the setup would be similar. A need exists to include keystore and truststore as well as client credentials in case you are using a confidential client.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> If it is possible, it is preferred to use <a href="#_service_accounts">Service accounts</a> together with the MTLS client authentication (client authenticator <code>X509 Certificate</code>) rather than using the Direct grant with X.509 authentication as direct grant may require sharing of the user certificate with client applications. When using service account, the tokens are obtained on behalf of the client itself, which in general is better and more secure practice. </td> </tr> </table> </div> </div> </div> </div> <div class="sect2"> <h3 id="webauthn_server_administration_guide"><a class="anchor" href="#webauthn_server_administration_guide"></a>W3C Web Authentication (WebAuthn)</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/authentication/webauthn.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/authentication/webauthn.adoc&amp;description=%0A%0AFile:%20server_admin/topics/authentication/webauthn.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Keycloak provides support for <a href="https://www.w3.org/TR/webauthn/">W3C Web Authentication (WebAuthn)</a>. Keycloak works as a WebAuthn&#8217;s <a href="https://www.w3.org/TR/webauthn/#webauthn-relying-party">Relying Party (RP)</a>.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>WebAuthn&#8217;s operations success depends on the user&#8217;s WebAuthn supporting authenticator, browser, and platform. Make sure your authenticator, browser, and platform support the WebAuthn specification.</p> </div> </td> </tr> </table> </div> <div class="sect3"> <h4 id="setup"><a class="anchor" href="#setup"></a>Setup</h4> <div class="paragraph"> <p>The setup procedure of WebAuthn support for 2FA is the following:</p> </div> <div class="sect4"> <h5 id="_webauthn-register"><a class="anchor" href="#_webauthn-register"></a>Enable WebAuthn authenticator registration</h5> <div class="olist arabic"> <ol class="arabic"> <li> <p>Click <strong>Authentication</strong> in the menu.</p> </li> <li> <p>Click the <strong>Required Actions</strong> tab.</p> </li> <li> <p>Toggle the <strong>Webauthn Register</strong> switch to <strong>ON</strong>.</p> </li> </ol> </div> <div class="paragraph"> <p>Toggle the <strong>Default Action</strong> switch to <strong>ON</strong> if you want all new users to be required to register their WebAuthn credentials.</p> </div> </div> </div> <div class="sect3"> <h4 id="_webauthn-authenticator-setup"><a class="anchor" href="#_webauthn-authenticator-setup"></a>Adding WebAuthn authentication to a browser flow</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Click <strong>Authentication</strong> in the menu.</p> </li> <li> <p>Click the <strong>Browser</strong> flow.</p> </li> <li> <p>Select <strong>Duplicate</strong> from the "Action list" to make a copy of the built-in <strong>Browser</strong> flow.</p> </li> <li> <p>Enter "WebAuthn Browser" as the name of the copy.</p> </li> <li> <p>Click <strong>Duplicate</strong>.</p> </li> <li> <p>Click the name to go to the details</p> </li> <li> <p>Click the trash can icon 🗑️ of the "WebAuthn Browser Browser - Conditional OTP" and click <strong>Delete</strong>.</p> </li> </ol> </div> <div class="paragraph"> <p>If you require WebAuthn for all users:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Click <strong>+</strong> menu of the <strong>WebAuthn Browser Forms</strong>.</p> </li> <li> <p>Click <strong>Add step</strong>.</p> </li> <li> <p>Click <strong>WebAuthn Authenticator</strong>.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> <li> <p>Select <strong>Required</strong> for the <strong>WebAuthn Authenticator</strong> authentication type to set its requirement to required.</p> <div class="paragraph"> <p><span class="image"><img src="./images/webauthn-browser-flow-required.png" alt="Webauthn browser flow required"></span></p> </div> </li> <li> <p>Click the <strong>Action</strong> menu at the top of the screen.</p> </li> <li> <p>Select <strong>Bind flow</strong> from the drop-down list.</p> </li> <li> <p>Select <strong>Browser</strong> from the drop-down list.</p> </li> <li> <p>Click <strong>Save</strong>.</p> </li> </ol> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>If a user does not have WebAuthn credentials, the user must register WebAuthn credentials.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>Users can log in with WebAuthn if they have a WebAuthn credential registered only. So instead of adding the <strong>WebAuthn Authenticator</strong> execution, you can:</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>+</strong> menu of the <strong>WebAuthn Browser Forms</strong> row.</p> </li> <li> <p>Click <strong>Add sub-flow</strong>.</p> </li> <li> <p>Enter "Conditional 2FA" for the <em>name</em> field.</p> </li> <li> <p>Select <strong>Conditional</strong> for the <strong>Conditional 2FA</strong> to set its requirement to conditional.</p> </li> <li> <p>On the <strong>Conditional 2FA</strong> row, click the plus sign + and select <strong>Add condition</strong>.</p> </li> <li> <p>Click <strong>Add condition</strong>.</p> </li> <li> <p>Select <strong>Condition - User Configured</strong>.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> <li> <p>Select <strong>Required</strong> for the <strong>Condition - User Configured</strong> to set its requirement to required.</p> </li> <li> <p>Drag and drop <strong>WebAuthn Authenticator</strong> into the <strong>Conditional 2FA</strong> flow</p> </li> <li> <p>Select <strong>Alternative</strong> for the <strong>WebAuthn Authenticator</strong> to set its requirement to alternative.</p> <div class="paragraph"> <p><span class="image"><img src="./images/webauthn-browser-flow-conditional.png" alt="Webauthn browser flow conditional"></span></p> </div> </li> </ol> </div> <div class="paragraph"> <p>The user can choose between using WebAuthn and OTP for the second factor:</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>On the <strong>Conditional 2FA</strong> row, click the plus sign + and select <strong>Add step</strong>.</p> </li> <li> <p>Select <strong>OTP Form</strong> from the list.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> <li> <p>Select <strong>Alternative</strong> for the <strong>OTP Form</strong> to set its requirement to alternative.</p> <div class="paragraph"> <p><span class="image"><img src="./images/webauthn-browser-flow-conditional-with-OTP.png" alt="WebAuthn browser flow conditional with OTP"></span></p> </div> </li> </ol> </div> </div> <div class="sect3"> <h4 id="authenticate-with-webauthn-authenticator"><a class="anchor" href="#authenticate-with-webauthn-authenticator"></a>Authenticate with WebAuthn authenticator</h4> <div class="paragraph"> <p>After registering a WebAuthn authenticator, the user carries out the following operations:</p> </div> <div class="ulist"> <ul> <li> <p>Open the login form. The user must authenticate with a username and password.</p> </li> <li> <p>The user&#8217;s browser asks the user to authenticate by using their WebAuthn authenticator.</p> </li> </ul> </div> </div> <div class="sect3"> <h4 id="managing-webauthn-as-an-administrator"><a class="anchor" href="#managing-webauthn-as-an-administrator"></a>Managing WebAuthn as an administrator</h4> <div class="sect4"> <h5 id="managing-credentials"><a class="anchor" href="#managing-credentials"></a>Managing credentials</h5> <div class="paragraph"> <p>Keycloak manages WebAuthn credentials similarly to other credentials from <a href="#ref-user-credentials_server_administration_guide">User credential management</a>:</p> </div> <div class="ulist"> <ul> <li> <p>Keycloak assigns users a required action to create a WebAuthn credential from the <strong>Reset Actions</strong> list and select <strong>Webauthn Register</strong>.</p> </li> <li> <p>Administrators can delete a WebAuthn credential by clicking <strong>Delete</strong>.</p> </li> <li> <p>Administrators can view the credential&#8217;s data, such as the AAGUID, by selecting <strong>Show data&#8230;&#8203;</strong>.</p> </li> <li> <p>Administrators can set a label for the credential by setting a value in the <strong>User Label</strong> field and saving the data.</p> </li> </ul> </div> </div> <div class="sect4"> <h5 id="_webauthn-policy"><a class="anchor" href="#_webauthn-policy"></a>Managing policy</h5> <div class="paragraph"> <p>Administrators can configure WebAuthn related operations as <strong>WebAuthn Policy</strong> per realm.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Authentication</strong> in the menu.</p> </li> <li> <p>Click the <strong>Policy</strong> tab.</p> </li> <li> <p>Click the <strong>WebAuthn Policy</strong> tab.</p> </li> <li> <p>Configure the items within the policy (see description below).</p> </li> <li> <p>Click <strong>Save</strong>.</p> </li> </ol> </div> <div class="paragraph"> <p>The configurable items and their description are as follows:</p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 50%;"> <col style="width: 50%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Configuration</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Relying Party Entity Name</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The readable server name as a WebAuthn Relying Party. This item is mandatory and applies to the registration of the WebAuthn authenticator. The default setting is "keycloak". For more details, see <a href="https://www.w3.org/TR/webauthn/#dictionary-pkcredentialentity">WebAuthn Specification</a>.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Signature Algorithms</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The algorithms telling the WebAuthn authenticator which signature algorithms to use for the <a href="https://www.w3.org/TR/webauthn/#iface-pkcredential">Public Key Credential</a>. Keycloak uses the Public Key Credential to sign and verify <a href="https://www.w3.org/TR/webauthn/#authentication-assertion">Authentication Assertions</a>. If no algorithms exist, the default <a href="https://datatracker.ietf.org/doc/html/rfc8152#section-8.1">ES256</a> and <a href="https://datatracker.ietf.org/doc/html/rfc7518#section-3.1">RS256</a> is adapted. ES256 and RS256 are an optional configuration item applying to the registration of WebAuthn authenticators. For more details, see <a href="https://www.w3.org/TR/webauthn/#dictdef-publickeycredentialparameters">WebAuthn Specification</a>.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Relying Party ID</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The ID of a WebAuthn Relying Party that determines the scope of <a href="https://www.w3.org/TR/webauthn/#public-key-credential">Public Key Credentials</a>. The ID must be the origin&#8217;s effective domain. This ID is an optional configuration item applied to the registration of WebAuthn authenticators. If this entry is blank, Keycloak adapts the host part of Keycloak&#8217;s base URL. For more details, see <a href="https://www.w3.org/TR/webauthn/">WebAuthn Specification</a>.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Attestation Conveyance Preference</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The WebAuthn API implementation on the browser (<a href="https://www.w3.org/TR/webauthn/#webauthn-client">WebAuthn Client</a>) is the preferential method to generate Attestation statements. This preference is an optional configuration item applying to the registration of the WebAuthn authenticator. If no option exists, its behavior is the same as selecting "none". For more details, see <a href="https://www.w3.org/TR/webauthn/">WebAuthn Specification</a>.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Authenticator Attachment</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The acceptable attachment pattern of a WebAuthn authenticator for the WebAuthn Client. This pattern is an optional configuration item applying to the registration of the WebAuthn authenticator. For more details, see <a href="https://www.w3.org/TR/webauthn/#enumdef-authenticatorattachment">WebAuthn Specification</a>.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Require Discoverable Credential</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The option requiring that the WebAuthn authenticator generates the Public Key Credential as <a href="https://www.w3.org/TR/webauthn-3/">Client-side discoverable Credential</a>. This option applies to the registration of the WebAuthn authenticator. If left blank, its behavior is the same as selecting "No". For more details, see <a href="https://www.w3.org/TR/webauthn/#dom-authenticatorselectioncriteria-requireresidentkey">WebAuthn Specification</a>.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">User Verification Requirement</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The option requiring that the WebAuthn authenticator confirms the verification of a user. This is an optional configuration item applying to the registration of a WebAuthn authenticator and the authentication of a user by a WebAuthn authenticator. If no option exists, its behavior is the same as selecting "preferred". For more details, see <a href="https://www.w3.org/TR/webauthn/#dom-authenticatorselectioncriteria-userverification">WebAuthn Specification for registering a WebAuthn authenticator</a> and <a href="https://www.w3.org/TR/webauthn/#dom-publickeycredentialrequestoptions-userverification">WebAuthn Specification for authenticating the user by a WebAuthn authenticator</a>.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Timeout</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The timeout value, in seconds, for registering a WebAuthn authenticator and authenticating the user by using a WebAuthn authenticator. If set to zero, its behavior depends on the WebAuthn authenticator&#8217;s implementation. The default value is 0. For more details, see <a href="https://www.w3.org/TR/webauthn/#dom-publickeycredentialcreationoptions-timeout">WebAuthn Specification for registering a WebAuthn authenticator</a> and <a href="https://www.w3.org/TR/webauthn/#dom-publickeycredentialrequestoptions-timeout">WebAuthn Specification for authenticating the user by a WebAuthn authenticator</a>.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Avoid Same Authenticator Registration</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">If enabled, Keycloak cannot re-register an already registered WebAuthn authenticator.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Acceptable AAGUIDs</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The white list of AAGUIDs which a WebAuthn authenticator must register against.</p></td> </tr> </tbody> </table> </div> </div> <div class="sect3"> <h4 id="attestation-statement-verification"><a class="anchor" href="#attestation-statement-verification"></a>Attestation statement verification</h4> <div class="paragraph"> <p>When registering a WebAuthn authenticator, Keycloak verifies the trustworthiness of the attestation statement generated by the WebAuthn authenticator. Keycloak requires the trust anchor&#8217;s certificates imported into the <a href="https://www.keycloak.org/server/keycloak-truststore">truststore</a>.</p> </div> <div class="paragraph"> <p>To omit this validation, disable this truststore or set the WebAuthn policy&#8217;s configuration item "Attestation Conveyance Preference" to "none".</p> </div> </div> <div class="sect3"> <h4 id="managing-webauthn-credentials-as-a-user"><a class="anchor" href="#managing-webauthn-credentials-as-a-user"></a>Managing WebAuthn credentials as a user</h4> <div class="sect4"> <h5 id="register-webauthn-authenticator"><a class="anchor" href="#register-webauthn-authenticator"></a>Register WebAuthn authenticator</h5> <div class="paragraph"> <p>The appropriate method to register a WebAuthn authenticator depends on whether the user has already registered an account on Keycloak.</p> </div> </div> <div class="sect4"> <h5 id="new-user"><a class="anchor" href="#new-user"></a>New user</h5> <div class="paragraph"> <p>If the <strong>WebAuthn Register</strong> required action is <strong>Default Action</strong> in a realm, new users must set up the Passkey after their first login.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Open the login form.</p> </li> <li> <p>Click <strong>Register</strong>.</p> </li> <li> <p>Fill in the items on the form.</p> </li> <li> <p>Click <strong>Register</strong>.</p> </li> </ol> </div> <div class="paragraph"> <p>After successfully registering, the browser asks the user to enter the text of their WebAuthn authenticator&#8217;s label.</p> </div> </div> <div class="sect4"> <h5 id="existing-user"><a class="anchor" href="#existing-user"></a>Existing user</h5> <div class="paragraph"> <p>If <code>WebAuthn Authenticator</code> is set up as required as shown in the first example, then when existing users try to log in, they are required to register their WebAuthn authenticator automatically:</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Open the login form.</p> </li> <li> <p>Enter the items on the form.</p> </li> <li> <p>Click <strong>Save</strong>.</p> </li> <li> <p>Click <strong>Login</strong>.</p> </li> </ol> </div> <div class="paragraph"> <p>After successful registration, the user&#8217;s browser asks the user to enter the text of their WebAuthn authenticator&#8217;s label.</p> </div> </div> </div> <div class="sect3"> <h4 id="_webauthn_passwordless"><a class="anchor" href="#_webauthn_passwordless"></a>Passwordless WebAuthn together with Two-Factor</h4> <div class="paragraph"> <p>Keycloak uses WebAuthn for two-factor authentication, but you can use WebAuthn as the first-factor authentication. In this case, users with <code>passwordless</code> WebAuthn credentials can authenticate to Keycloak without a password. Keycloak can use WebAuthn as both the passwordless and two-factor authentication mechanism in the context of a realm and a single authentication flow.</p> </div> <div class="paragraph"> <p>An administrator typically requires that Passkeys registered by users for the WebAuthn passwordless authentication meet different requirements. For example, the Passkeys may require users to authenticate to the Passkey using a PIN, or the Passkey attests with a stronger certificate authority.</p> </div> <div class="paragraph"> <p>Because of this, Keycloak permits administrators to configure a separate <code>WebAuthn Passwordless Policy</code>. There is a required <code>Webauthn Register Passwordless</code> action of type and separate authenticator of type <code>WebAuthn Passwordless Authenticator</code>.</p> </div> <div class="sect4"> <h5 id="setup-2"><a class="anchor" href="#setup-2"></a>Setup</h5> <div class="paragraph"> <p>Set up WebAuthn passwordless support as follows:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>(if not already present) Register a new required action for WebAuthn passwordless support. Use the steps described in <a href="#_webauthn-register">Enable WebAuthn Authenticator Registration</a>. Register the <code>Webauthn Register Passwordless</code> action.</p> </li> <li> <p>Configure the policy. You can use the steps and configuration options described in <a href="#_webauthn-policy">Managing Policy</a>. Perform the configuration in the Admin Console in the tab <strong>WebAuthn Passwordless Policy</strong>. Typically the requirements for the Passkey will be stronger than for the two-factor policy. For example, you can set the <strong>User Verification Requirement</strong> to <strong>Required</strong> when you configure the passwordless policy.</p> </li> <li> <p>Configure the authentication flow. Use the <strong>WebAuthn Browser</strong> flow described in <a href="#_webauthn-authenticator-setup">Adding WebAuthn Authentication to a Browser Flow</a>. Configure the flow as follows:</p> <div class="ulist"> <ul> <li> <p>The <strong>WebAuthn Browser Forms</strong> subflow contains <strong>Username Form</strong> as the first authenticator. Delete the default <strong>Username Password Form</strong> authenticator and add the <strong>Username Form</strong> authenticator. This action requires the user to provide a username as the first step.</p> </li> <li> <p>There will be a required subflow, which can be named <strong>Passwordless Or Two-factor</strong>, for example. This subflow indicates the user can authenticate with Passwordless WebAuthn credential or with Two-factor authentication.</p> </li> <li> <p>The flow contains <strong>WebAuthn Passwordless Authenticator</strong> as the first alternative.</p> </li> <li> <p>The second alternative will be a subflow named <strong>Password And Two-factor Webauthn</strong>, for example. This subflow contains a <strong>Password Form</strong> and a <strong>WebAuthn Authenticator</strong>.</p> </li> </ul> </div> </li> </ol> </div> <div class="paragraph"> <p>The final configuration of the flow looks similar to this:</p> </div> <div class="paragraph"> <div class="title">PasswordLess flow</div> <p><span class="image"><img src="./images/webauthn-passwordless-flow.png" alt="PasswordLess flow"></span></p> </div> <div class="paragraph"> <p>You can now add <strong>WebAuthn Register Passwordless</strong> as the required action to a user, already known to Keycloak, to test this. During the first authentication, the user must use the password and second-factor WebAuthn credential. The user does not need to provide the password and second-factor WebAuthn credential if they use the WebAuthn Passwordless credential.</p> </div> </div> </div> <div class="sect3"> <h4 id="_webauthn_loginless"><a class="anchor" href="#_webauthn_loginless"></a>LoginLess WebAuthn</h4> <div class="paragraph"> <p>Keycloak uses WebAuthn for two-factor authentication, but you can use WebAuthn as the first-factor authentication. In this case, users with <code>passwordless</code> WebAuthn credentials can authenticate to Keycloak without submitting a login or a password. Keycloak can use WebAuthn as both the loginless/passwordless and two-factor authentication mechanism in the context of a realm.</p> </div> <div class="paragraph"> <p>An administrator typically requires that Passkeys registered by users for the WebAuthn loginless authentication meet different requirements. Loginless authentication requires users to authenticate to the Passkey (for example by using a PIN code or a fingerprint) and that the cryptographic keys associated with the loginless credential are stored physically on the Passkey. Not all Passkeys meet that kind of requirement. Check with your Passkey vendor if your device supports 'user verification' and 'discoverable credential'. See <a href="#_webauthn-supported-keys">Supported Passkeys</a>.</p> </div> <div class="paragraph"> <p>Keycloak permits administrators to configure the <code>WebAuthn Passwordless Policy</code> in a way that allows loginless authentication. Note that loginless authentication can only be configured with <code>WebAuthn Passwordless Policy</code> and with <code>WebAuthn Passwordless</code> credentials. WebAuthn loginless authentication and WebAuthn passwordless authentication can be configured on the same realm but will share the same policy <code>WebAuthn Passwordless Policy</code>.</p> </div> <div class="sect4"> <h5 id="setup-3"><a class="anchor" href="#setup-3"></a>Setup</h5> <div class="paragraph"> <div class="title">Procedure</div> <p>Set up WebAuthn Loginless support as follows:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>(if not already present) Register a new required action for WebAuthn passwordless support. Use the steps described in <a href="#_webauthn-register">Enable WebAuthn Authenticator Registration</a>. Register the <code>Webauthn Register Passwordless</code> action.</p> </li> <li> <p>Configure the <code>WebAuthn Passwordless Policy</code>. Perform the configuration in the Admin Console, <code>Authentication</code> section, in the tab <code>Policies</code> &#8594; <code>WebAuthn Passwordless Policy</code>. You have to set <strong>User Verification Requirement</strong> to <strong>required</strong> and <strong>Require Discoverable Credential</strong> to <strong>Yes</strong> when you configure the policy for loginless scenario. Note that since there isn&#8217;t a dedicated Loginless policy it won&#8217;t be possible to mix authentication scenarios with user verification=no/discoverable credential=no and loginless scenarios (user verification=yes/discoverable credential=yes). Storage capacity is usually very limited on Passkeys meaning that you won&#8217;t be able to store many discoverable credentials on your Passkey.</p> </li> <li> <p>Configure the authentication flow. Create a new authentication flow, add the "WebAuthn Passwordless" execution and set the Requirement setting of the execution to <strong>Required</strong></p> </li> </ol> </div> <div class="paragraph"> <p>The final configuration of the flow looks similar to this:</p> </div> <div class="paragraph"> <div class="title">LoginLess flow</div> <p><span class="image"><img src="./images/webauthn-loginless-flow.png" alt="LoginLess flow"></span></p> </div> <div class="paragraph"> <p>You can now add the required action <code>WebAuthn Register Passwordless</code> to a user, already known to Keycloak, to test this. The user with the required action configured will have to authenticate (with a username/password for example) and will then be prompted to register a Passkey to be used for loginless authentication.</p> </div> </div> <div class="sect4"> <h5 id="vendor-specific-remarks"><a class="anchor" href="#vendor-specific-remarks"></a>Vendor specific remarks</h5> <div class="sect5"> <h6 id="compatibility-check-list"><a class="anchor" href="#compatibility-check-list"></a>Compatibility check list</h6> <div class="paragraph"> <p>Loginless authentication with Keycloak requires the Passkey to meet the following features</p> </div> <div class="ulist"> <ul> <li> <p>FIDO2 compliance: not to be confused with FIDO/U2F</p> </li> <li> <p>User verification: the ability for the Passkey to authenticate the user (prevents someone finding your Passkey to be able to authenticate loginless and passwordless)</p> </li> <li> <p>Discoverable Credential: the ability for the Passkey to store the login and the cryptographic keys associated with the client application</p> </li> </ul> </div> </div> <div class="sect5"> <h6 id="windows-hello"><a class="anchor" href="#windows-hello"></a>Windows Hello</h6> <div class="paragraph"> <p>To use Windows Hello based credentials to authenticate against Keycloak, configure the <strong>Signature Algorithms</strong> setting of the <code>WebAuthn Passwordless Policy</code> to include the <strong>RS256</strong> value. Note that some browsers don&#8217;t allow access to platform Passkey (like Windows Hello) inside private windows.</p> </div> </div> <div class="sect5"> <h6 id="_webauthn-supported-keys"><a class="anchor" href="#_webauthn-supported-keys"></a>Supported Passkeys</h6> <div class="paragraph"> <p>The following Passkeys have been successfully tested for loginless authentication with Keycloak:</p> </div> <div class="ulist"> <ul> <li> <p>Windows Hello (Windows 10 21H1/21H2)</p> </li> <li> <p>Yubico Yubikey 5 NFC</p> </li> <li> <p>Feitian ePass FIDO-NFC</p> </li> </ul> </div> </div> </div> </div> </div> <div class="sect2"> <h3 id="passkeys_server_administration_guide"><a class="anchor" href="#passkeys_server_administration_guide"></a>Passkeys</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/authentication/passkeys.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/authentication/passkeys.adoc&amp;description=%0A%0AFile:%20server_admin/topics/authentication/passkeys.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Keycloak provides preview support for <a href="https://fidoalliance.org/passkeys/">Passkeys</a>. Keycloak works as a Passkeys Relying Party (RP).</p> </div> <div class="paragraph"> <p>Passkey registration and authentication are realized by the features of <a href="#webauthn_server_administration_guide">WebAuthn</a>. Therefore, users of Keycloak can do Passkey registration and authentication by existing <a href="#webauthn_server_administration_guide">WebAuthn registration and authentication</a>.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>Both synced Passkeys and device-bound Passkeys can be used for both Same-Device and Cross-Device Authentication (CDA). However, Passkeys operations success depends on the user&#8217;s environment. Make sure which operations can succeed in <a href="https://passkeys.dev/device-support/">the environment</a>.</p> </div> </td> </tr> </table> </div> <div class="sect3"> <h4 id="_passkeys-conditional-ui"><a class="anchor" href="#_passkeys-conditional-ui"></a>Passkey Authentication with Conditional UI</h4> <div class="paragraph"> <p>Passkey Authentication with Conditional UI can authenticate a user with its passkey in the same way as in <a href="#_webauthn_loginless">LoginLess WebAuthn</a>. This authentication shows a user a list of passkeys stored on a device where the user runs a browser. Therefore, the user can select one of the passkeys in the list to authenticate them. Compared with <a href="#_webauthn_loginless">LoginLess WebAuthn</a>, the authentication improves the user&#8217;s experience of authentication.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>This authentication uses the <a href="https://github.com/w3c/webauthn/wiki/Explainer:-WebAuthn-Conditional-UI/">WebAuthn Conditional UI</a>. Therefore, this authentication success depends on the user&#8217;s environment. If the environment does not support WebAuthn Conditional UI, this authentication falls back to <a href="#_webauthn_loginless">LoginLess WebAuthn</a>.</p> </div> </td> </tr> </table> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>Passkey Authentication is <strong>Preview</strong> and is not fully supported. This feature is disabled by default.</p> </div> <div class="paragraph"> <p>To enable start the server with <code>--features=preview</code> or <code>--features=passkeys</code></p> </div> </td> </tr> </table> </div> <div class="sect4"> <h5 id="setup-4"><a class="anchor" href="#setup-4"></a>Setup</h5> <div class="paragraph"> <div class="title">Procedure</div> <p>Set up Passkey Authentication with Conditional UI as follows:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>(if not already present) Register a new required action for WebAuthn passwordless support. Use the steps described in <a href="#_webauthn-register">Enable WebAuthn Authenticator Registration</a>. Register the <code>Webauthn Register Passwordless</code> action.</p> </li> <li> <p>Configure the <code>WebAuthn Passwordless Policy</code>. Perform the configuration in the Admin Console, <code>Authentication</code> section, in the tab <code>Policies</code> &#8594; <code>WebAuthn Passwordless Policy</code>. Set <strong>User Verification Requirement</strong> to <strong>required</strong> and <strong>Require discoverable credential</strong> to <strong>Yes</strong> when you configure the policy for loginless scenario. Note that since there is no dedicated Loginless policy, it is impossible to mix authentication scenarios with user verification=no/discoverable credential=no and loginless scenarios (user verification=yes/discoverable credential=yes).</p> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> Storage capacity is usually very limited on hardware passkeys meaning that you cannot store many discoverable credentials on your passkey. However, this limitation may be mitigated for instance if you use an Android phone backed by a Google account as a passkey device or an iPhone backed by Bitwarden. </td> </tr> </table> </div> </li> <li> <p>Configure the authentication flow. Create a new authentication flow, add the <strong>Passkeys Conditional UI Authenticator</strong> execution and set the Requirement setting of the execution to <strong>Required</strong>.</p> <div class="paragraph"> <p>The final configuration of the flow looks similar to this: <span class="image"><img src="./images/passkey-conditional-ui-flow.png" alt="Passkey Authentication with Conditional UI flow flow"></span></p> </div> </li> <li> <p>Bind the flow above as a <strong>browser</strong> authentication flow in the realm as described in the <a href="#_webauthn-register">WebAuthn section above</a>.</p> </li> </ol> </div> <div class="paragraph"> <p>The authentication flow above requires that user must already have passkey credential on his or her account to be able to log in. This requirement means that all users in the realm must have passkeys already set. That can be achieved for instance by enabling user registration as described below.</p> </div> </div> <div class="sect4"> <h5 id="setup-of-the-registration-for-passkeys-conditional-ui"><a class="anchor" href="#setup-of-the-registration-for-passkeys-conditional-ui"></a>Setup of the registration for passkeys conditional UI</h5> <div class="olist arabic"> <ol class="arabic"> <li> <p>Enable <a href="#con-user-registration_server_administration_guide">registration</a> for your realm</p> </li> <li> <p>In the <a href="#configuring-authentication_server_administration_guide">authentication flows</a> of the realm, select flow <strong>registration</strong> and switch the authenticator <strong>Password validation</strong> to <strong>Disabled</strong>. This means that newly registered users will not be required to create the passwords in this example setup. Users must always use passkeys instead of passwords.</p> </li> <li> <p>Return to the <strong>Required actions</strong> sub-tab of the tab <strong>Authentication</strong> tab and find the <code>Webauthn Register Passwordless</code> action and mark it with <strong>Set as default action</strong>. This means that it would be added to all new users after their registration.</p> </li> </ol> </div> <div class="paragraph"> <p>The alternative to the registration flow setup is to add the required action <code>WebAuthn Register Passwordless</code> to a user who is already known to Keycloak. The user with the required action configured will have to authenticate (with a username/password for example) and will then be prompted to register a passkey to be used for loginless authentication.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>We plan to improve the usability and allow integration of conditional passkeys with the existing authenticators and forms such as the default username / password form.</p> </div> </td> </tr> </table> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>From <a href="https://www.w3.org/TR/webauthn-3/">Web Authn Level 3</a>, <strong>Resident Key</strong> was replaced with <strong>Discoverable Credential</strong>.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>If a user&#8217;s browser supports <a href="https://github.com/w3c/webauthn/wiki/Explainer:-WebAuthn-Conditional-UI/">WebAuthn Conditional UI</a>, the follwing screen is shown.</p> </div> <div class="paragraph"> <div class="title">Passkey Authentication with Conditional UI</div> <p><span class="image"><img src="./images/passkey-conditional-ui-authentication.png" alt="Passkey Authentication with Conditional UI"></span></p> </div> <div class="paragraph"> <p>When the user clicks the <strong>Select your passkey</strong> textbox, a list of passkeys stored on a device where the user runs a browse is shown as follows.</p> </div> <div class="paragraph"> <div class="title">Passkey Authentication with Conditional UI Autofill</div> <p><span class="image"><img src="./images/passkey-conditional-ui-autofill.png" alt="Passkey Authentication with Conditional UI Autofill"></span></p> </div> <div class="paragraph"> <p>If a user&#8217;s browser does not support <a href="https://github.com/w3c/webauthn/wiki/Explainer:-WebAuthn-Conditional-UI/">WebAuthn Conditional UI</a>, the authenticaion falls back to the <a href="#_webauthn_loginless">LoginLess WebAuthn</a> as follows.</p> </div> <div class="paragraph"> <div class="title">Passkey Authentication with Conditional UI falling back to LoginLess WebAuthn</div> <p><span class="image"><img src="./images/passkey-conditional-ui-fallback-authentication.png" alt="Passkey Authentication with Conditional UI falling back to LoginLess WebAuthn"></span></p> </div> </div> </div> </div> <div class="sect2"> <h3 id="_recovery-codes"><a class="anchor" href="#_recovery-codes"></a>Recovery Codes (RecoveryCodes)</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/authentication/recovery-codes.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/authentication/recovery-codes.adoc&amp;description=%0A%0AFile:%20server_admin/topics/authentication/recovery-codes.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>You can configure Recovery codes for two-factor authentication by adding 'Recovery Authentication Code Form' as a two-factor authenticator to your authentication flow. For an example of configuring this authenticator, see <a href="#webauthn_server_administration_guide">WebAuthn</a>.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>RecoveryCodes is <strong>Preview</strong> and is not fully supported. This feature is disabled by default.</p> </div> <div class="paragraph"> <p>To enable start the server with <code>--features=preview</code> or <code>--features=recovery-codes</code></p> </div> </td> </tr> </table> </div> </div> <div class="sect2"> <h3 id="conditions-in-conditional-flows"><a class="anchor" href="#conditions-in-conditional-flows"></a>Conditions in conditional flows</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/authentication/conditions.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/authentication/conditions.adoc&amp;description=%0A%0AFile:%20server_admin/topics/authentication/conditions.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>As was mentioned in <a href="#_execution-requirements">Execution requirements</a>, <em>Condition</em> executions can be only contained in <em>Conditional</em> subflow. If all <em>Condition</em> executions evaluate as true, then the <em>Conditional</em> sub-flow acts as <em>Required</em>. You can process the next execution in the <em>Conditional</em> sub-flow. If some executions included in the <em>Conditional</em> sub-flow evaluate as false, then the whole sub-flow is considered as <em>Disabled</em>.</p> </div> <div class="sect3"> <h4 id="available-conditions"><a class="anchor" href="#available-conditions"></a>Available conditions</h4> <div class="dlist"> <dl> <dt class="hdlist1"><code>Condition - User Role</code></dt> <dd> <p>This execution has the ability to determine if the user has a role defined by <em>User role</em> field. If the user has the required role, the execution is considered as true and other executions are evaluated. The administrator has to define the following fields:</p> <div class="dlist"> <dl> <dt class="hdlist1">Alias</dt> <dd> <p>Describes a name of the execution, which will be shown in the authentication flow.</p> </dd> <dt class="hdlist1">User role</dt> <dd> <p>Role the user should have to execute this flow. To specify an application role the syntax is <code>appname.approle</code> (for example <code>myapp.myrole</code>).</p> </dd> </dl> </div> </dd> <dt class="hdlist1"><code>Condition - User Configured</code></dt> <dd> <p>This checks if the other executions in the flow are configured for the user. The Execution requirements section includes an example of the OTP form.</p> </dd> <dt class="hdlist1"><code>Condition - User Attribute</code></dt> <dd> <p>This checks if the user has set up the required attribute: optionally, the check can also evaluate the group attributes. There is a possibility to negate output, which means the user should not have the attribute. The <a href="#user-profile">User Attributes</a> section shows how to add a custom attribute. You can provide these fields:</p> <div class="dlist"> <dl> <dt class="hdlist1">Alias</dt> <dd> <p>Describes a name of the execution, which will be shown in the authentication flow.</p> </dd> <dt class="hdlist1">Attribute name</dt> <dd> <p>Name of the attribute to check.</p> </dd> <dt class="hdlist1">Expected attribute value</dt> <dd> <p>Expected value in the attribute.</p> </dd> <dt class="hdlist1">Include group attributes</dt> <dd> <p>If On, the condition checks if any of the joined group has one attribute matching the configured name and value: this option can affect performance</p> </dd> <dt class="hdlist1">Negate output</dt> <dd> <p>You can negate the output. In other words, the attribute should not be present.</p> </dd> </dl> </div> </dd> </dl> </div> </div> <div class="sect3"> <h4 id="explicitly-denyallow-access-in-conditional-flows"><a class="anchor" href="#explicitly-denyallow-access-in-conditional-flows"></a>Explicitly deny/allow access in conditional flows</h4> <div class="paragraph"> <p>You can allow or deny access to resources in a conditional flow. The two authenticators <code>Deny Access</code> and <code>Allow Access</code> control access to the resources by conditions.</p> </div> <div class="dlist"> <dl> <dt class="hdlist1"><code>Allow Access</code></dt> <dd> <p>Authenticator will always successfully authenticate. This authenticator is not configurable.</p> </dd> <dt class="hdlist1"><code>Deny Access</code></dt> <dd> <p>Access will always be denied. You can define an error message, which will be shown to the user. You can provide these fields:</p> <div class="dlist"> <dl> <dt class="hdlist1">Alias</dt> <dd> <p>Describes a name of the execution, which will be shown in the authentication flow.</p> </dd> <dt class="hdlist1">Error message</dt> <dd> <p>Error message which will be shown to the user. The error message could be provided as a particular message or as a property in order to use it with localization. (i.e. "<em>You do not have the role 'admin'.</em>", <em>my-property-deny</em> in messages properties) Leave blank for the default message defined as property <code>access-denied</code>.</p> </dd> </dl> </div> </dd> </dl> </div> <div class="paragraph"> <p>Here is an example how to deny access to all users who do not have the role <code>role1</code> and show an error message defined by a property <code>deny-role1</code>. This example includes <code>Condition - User Role</code> and <code>Deny Access</code> executions.</p> </div> <div class="paragraph"> <div class="title">Browser flow</div> <p><span class="image"><img src="./images/deny-access-flow.png" alt="Deny access flow"></span></p> </div> <div class="paragraph"> <div class="title">Condition - user role configuration</div> <p><span class="image"><img src="./images/deny-access-role-condition.png" alt="Deny access role settings"></span></p> </div> <div class="paragraph"> <div class="title">Configuration of the <code>Deny Access</code> is really easy. You can specify an arbitrary Alias and required message like this:</div> <p><span class="image"><img src="./images/deny-access-execution-cond.png" alt="Deny access execution settings"></span></p> </div> <div class="paragraph"> <p>The last thing is defining the property with an error message in the login theme <code>messages_en.properties</code> (for English):</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>deny-role1 = You do not have required role!</code></pre> </div> </div> </div> </div> <div class="sect2"> <h3 id="_authentication-sessions"><a class="anchor" href="#_authentication-sessions"></a>Authentication sessions</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/authentication/authentication-sessions.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/authentication/authentication-sessions.adoc&amp;description=%0A%0AFile:%20server_admin/topics/authentication/authentication-sessions.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>When a login page is opened for the first time in a web browser, Keycloak creates an object called authentication session that stores some useful information about the request. Whenever a new login page is opened from a different tab in the same browser, Keycloak creates a new record called authentication sub-session that is stored within the authentication session. Authentication requests can come from any type of clients such as the Admin CLI. In that case, a new authentication session is also created with one authentication sub-session. Please note that authentication sessions can be created also in other ways than using a browser flow.</p> </div> <div class="paragraph"> <p>The authentication session usually expires after 30 minutes by default. The exact time is specified by the <strong>Login timeout</strong> switch in the <strong>Sessions</strong> tab of the admin console when <a href="#_configuring-realms">configuring realms</a>.</p> </div> <div class="sect3"> <h4 id="authentication-in-more-browser-tabs"><a class="anchor" href="#authentication-in-more-browser-tabs"></a>Authentication in more browser tabs</h4> <div class="paragraph"> <p>As described in the previous section, a situation can involve a user who is trying to authenticate to the Keycloak server from multiple tabs of a single browser. However, when that user authenticates in one browser tab, the other browser tabs will automatically restart the authentication. This authentication occurs due to the small javascript available on the Keycloak login pages. The restart will typically authenticate the user in other browser tabs and redirect to clients because there is an SSO session now due to the fact that the user just successfully authenticated in first browser tab. Some rare exceptions exist when a user is not automatically authenticated in other browser tabs, such as for instance when using an OIDC parameter <em>prompt=login</em> or <a href="#_step-up-flow">step-up authentication</a> requesting a stronger authentication factor than the currently authenticated factor.</p> </div> <div class="paragraph"> <p>In some rare cases, it can happen that after authentication in the first browser tab, other browser tabs are not able to restart authentication because the authentication session is already expired. In this case, the particular browser tab will redirect the error about the expired authentication session back to the client in a protocol specific way. For more details, see the corresponding sections of <strong>OIDC documentation</strong> in the <a href="https://www.keycloak.org/guides#securing-apps">securing apps</a> section. When the client application receives such an error, it can immediately resubmit the OIDC/SAML authentication request to Keycloak as this should usually automatically authenticate the user due to the existing SSO session as described earlier. As a result, the end user is authenticated automatically in all browser tabs. The <strong>Keycloak JavaScript adapter</strong> in the <a href="https://www.keycloak.org/guides#securing-apps">securing apps</a> section, and <a href="#_identity_broker">Keycloak Identity provider</a> support to handle this error automatically and retry the authentication to the Keycloak server in such a case.</p> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="_identity_broker"><a class="anchor" href="#_identity_broker"></a>Integrating identity providers</h2> <div class="sectionbody"> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/identity-broker.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/identity-broker.adoc&amp;description=%0A%0AFile:%20server_admin/topics/identity-broker.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>An Identity Broker is an intermediary service connecting service providers with identity providers. The identity broker creates a relationship with an external identity provider to use the provider&#8217;s identities to access the internal services the service provider exposes.</p> </div> <div class="paragraph"> <p>From a user perspective, identity brokers provide a user-centric, centralized way to manage identities for security domains and realms. You can link an account with one or more identities from identity providers or create an account based on the identity information from them.</p> </div> <div class="paragraph"> <p>An identity provider derives from a specific protocol used to authenticate and send authentication and authorization information to users. It can be:</p> </div> <div class="ulist"> <ul> <li> <p>A social provider such as Facebook, Google, or Twitter.</p> </li> <li> <p>A business partner whose users need to access your services.</p> </li> <li> <p>A cloud-based identity service you want to integrate.</p> </li> </ul> </div> <div class="paragraph"> <p>Typically, Keycloak bases identity providers on the following protocols:</p> </div> <div class="ulist"> <ul> <li> <p><code>SAML v2.0</code></p> </li> <li> <p><code>OpenID Connect v1.0</code></p> </li> <li> <p><code>OAuth v2.0</code></p> </li> </ul> </div> <div class="sect2"> <h3 id="_identity_broker_overview"><a class="anchor" href="#_identity_broker_overview"></a>Brokering overview</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/identity-broker/overview.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/identity-broker/overview.adoc&amp;description=%0A%0AFile:%20server_admin/topics/identity-broker/overview.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>When using Keycloak as an identity broker, Keycloak does not force users to provide their credentials to authenticate in a specific realm. Keycloak displays a list of identity providers from which they can authenticate.</p> </div> <div class="paragraph"> <p>If you configure a default identity provider, Keycloak redirects users to the default provider.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>Different protocols may require different authentication flows. All the identity providers supported by Keycloak use the following flow.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <div class="title">Identity broker flow</div> <p><span class="image"><img src="./images/identity_broker_flow.png" alt="Identity broker flow"></span></p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>The unauthenticated user requests a protected resource in a client application.</p> </li> <li> <p>The client application redirects the user to Keycloak to authenticate.</p> </li> <li> <p>Keycloak displays the login page with a list of identity providers configured in a realm.</p> </li> <li> <p>The user selects one of the identity providers by clicking its button or link.</p> </li> <li> <p>Keycloak issues an authentication request to the target identity provider requesting authentication and redirects the user to the identity provider&#8217;s login page. The administrator has already set the connection properties and other configuration options for the Admin Console&#8217;s identity provider.</p> </li> <li> <p>The user provides credentials or consents to authenticate with the identity provider.</p> </li> <li> <p>Upon successful authentication by the identity provider, the user redirects back to Keycloak with an authentication response. Usually, the response contains a security token used by Keycloak to trust the identity provider&#8217;s authentication and retrieve user information.</p> </li> <li> <p>Keycloak checks if the response from the identity provider is valid. If valid, Keycloak imports and creates a user if the user does not already exist. Keycloak may ask the identity provider for further user information if the token does not contain that information. This behavior is <em>identity federation</em>. If the user already exists, Keycloak may ask the user to link the identity returned from the identity provider with the existing account. This behavior is <em>account linking</em>. With Keycloak, you can configure <em>Account linking</em> and specify it in the <a href="#_identity_broker_first_login">First Login Flow</a>. At this step, Keycloak authenticates the user and issues its token to access the requested resource in the service provider.</p> </li> <li> <p>When the user authenticates, Keycloak redirects the user to the service provider by sending the token previously issued during the local authentication.</p> </li> <li> <p>The service provider receives the token from Keycloak and permits access to the protected resource.</p> </li> </ol> </div> <div class="paragraph"> <p>Variations of this flow are possible. For example, the client application can request a specific identity provider rather than displaying a list of them, or you can set Keycloak to force users to provide additional information before federating their identity.</p> </div> <div class="paragraph"> <p>At the end of the authentication process, Keycloak issues its token to client applications. Client applications are separate from the external identity providers, so they cannot see the client application&#8217;s protocol or how they validate the user&#8217;s identity. The provider only needs to know about Keycloak.</p> </div> </div> <div class="sect2"> <h3 id="default_identity_provider"><a class="anchor" href="#default_identity_provider"></a>Default Identity Provider</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/identity-broker/default-provider.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/identity-broker/default-provider.adoc&amp;description=%0A%0AFile:%20server_admin/topics/identity-broker/default-provider.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Keycloak can redirect to an identity provider rather than displaying the login form. To enable this redirection:</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Authentication</strong> in the menu.</p> </li> <li> <p>Click the <strong>Browser</strong> flow.</p> </li> <li> <p>Click the gear icon <strong>⚙️</strong> on the <strong>Identity Provider Redirector</strong> row.</p> </li> <li> <p>Set <strong>Default Identity Provider</strong> to the identity provider you want to redirect users to.</p> </li> </ol> </div> <div class="paragraph"> <p>If Keycloak does not find the configured default identity provider, the login form is displayed.</p> </div> <div class="paragraph"> <p>This authenticator is responsible for processing the <code>kc_idp_hint</code> query parameter. See the <a href="#_client_suggested_idp">client suggested identity provider</a> section for more information.</p> </div> </div> <div class="sect2"> <h3 id="_general-idp-config"><a class="anchor" href="#_general-idp-config"></a>General configuration</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/identity-broker/configuration.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/identity-broker/configuration.adoc&amp;description=%0A%0AFile:%20server_admin/topics/identity-broker/configuration.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>The foundations of the identity broker configuration are identity providers (IDPs). Keycloak creates identity providers for each realm and enables them for every application by default. Users from a realm can use any of the registered identity providers when signing in to an application.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Identity Providers</strong> in the menu.</p> <div class="paragraph"> <div class="title">Identity Providers</div> <p><span class="image"><img src="./images/identity-providers.png" alt="Identity Providers"></span></p> </div> </li> <li> <p>Select an identity provider. Keycloak displays the configuration page for the identity provider you selected.</p> <div class="paragraph"> <div class="title">Add Facebook identity Provider</div> <p><span class="image"><img src="./images/add-identity-provider.png" alt="Add Facebook Identity Provider"></span></p> </div> <div class="paragraph"> <p>When you configure an identity provider, the identity provider appears on the Keycloak login page as an option. You can place custom icons on the login screen for each identity provider. See <a href="https://www.keycloak.org/docs/26.0.6/server_development/#custom-identity-providers-icons">custom icons</a> for more information.</p> </div> <div class="paragraph"> <div class="title">IDP login page</div> <p><span class="image"><img src="./images/identity-provider-login-page.png" alt="identity provider login page"></span></p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Social</dt> <dd> <p>Social providers enable social authentication in your realm. With Keycloak, users can log in to your application using a social network account. Supported providers include Twitter, Facebook, Google, LinkedIn, Instagram, Microsoft, PayPal, Openshift v3, GitHub, GitLab, Bitbucket, and Stack Overflow.</p> </dd> <dt class="hdlist1">Protocol-based</dt> <dd> <p>Protocol-based providers rely on specific protocols to authenticate and authorize users. Using these providers, you can connect to any identity provider compliant with a specific protocol. Keycloak provides support for SAML v2.0 and OpenID Connect v1.0 protocols. You can configure and broker any identity provider based on these open standards.</p> </dd> </dl> </div> </li> </ol> </div> <div class="paragraph"> <p>Although each type of identity provider has its configuration options, all share a common configuration. The following configuration options available:</p> </div> <table class="tableblock frame-all grid-all stretch"> <caption class="title">Table 1. Common Configuration</caption> <colgroup> <col style="width: 50%;"> <col style="width: 50%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Configuration</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Alias</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The alias is a unique identifier for an identity provider and references an internal identity provider. Keycloak uses the alias to build redirect URIs for OpenID Connect protocols that require a redirect URI or callback URL to communicate with an identity provider. All identity providers must have an alias. Alias examples include <code>facebook</code>, <code>google</code>, and <code>idp.acme.com</code>.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Enabled</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Toggles the provider ON or OFF.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Hide on Login Page</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">When <strong>ON</strong>, Keycloak does not display this provider as a login option on the login page. Clients can request this provider by using the 'kc_idp_hint' parameter in the URL to request a login.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Account Linking Only</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">When <strong>ON</strong>, Keycloak links existing accounts with this provider. This provider cannot log users in, and Keycloak does not display this provider as an option on the login page.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Store Tokens</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">When <strong>ON</strong>, Keycloak stores tokens from the identity provider.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Stored Tokens Readable</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">When <strong>ON</strong>, users can retrieve the stored identity provider token. This action also applies to the <em>broker</em> client-level role <em>read token</em>.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Trust Email</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">When <strong>ON</strong>, Keycloak trusts email addresses from the identity provider. If the realm requires email validation, users that log in from this identity provider do not need to perform the email verification process.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">GUI Order</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The sort order of the available identity providers on the login page.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Verify essential claim</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">When <strong>ON</strong>, ID tokens issued by the identity provider must have a specific claim, otherwise, the user can not authenticate through this broker</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Essential claim</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">When <strong>Verify essential claim</strong> is <strong>ON</strong>, the name of the JWT token claim to filter (match is case sensitive)</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Essential claim value</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">When <strong>Verify essential claim</strong> is <strong>ON</strong>, the value of the JWT token claim to match (supports regular expression format)</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">First Login Flow</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The authentication flow Keycloak triggers when users use this identity provider to log into Keycloak for the first time.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Post Login Flow</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The authentication flow Keycloak triggers when a user finishes logging in with the external identity provider.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Sync Mode</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Strategy to update user information from the identity provider through mappers. When choosing <strong>legacy</strong>, Keycloak used the current behavior. <strong>Import</strong> does not update user data and <strong>force</strong> updates user data when possible. See <a href="#_mappers">Identity Provider Mappers</a> for more information.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Case-sensitive username</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">If enabled, the original username from the identity provider is kept as is when federating users. Otherwise, the username from the identity provider is lower-cased and might not match the original value if it is case-sensitive. This setting only affects the username associated with the federated identity as usernames in the server are always in lower-case.</p></td> </tr> </tbody> </table> </div> <div class="sect2"> <h3 id="social-identity-providers"><a class="anchor" href="#social-identity-providers"></a>Social Identity Providers</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/identity-broker/social-login.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/identity-broker/social-login.adoc&amp;description=%0A%0AFile:%20server_admin/topics/identity-broker/social-login.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>A social identity provider can delegate authentication to a trusted, respected social media account. Keycloak includes support for social networks such as Google, Facebook, Twitter, GitHub, LinkedIn, Microsoft, and Stack Overflow.</p> </div> <div class="sect3"> <h4 id="bitbucket"><a class="anchor" href="#bitbucket"></a>Bitbucket</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/identity-broker/social/bitbucket.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/identity-broker/social/bitbucket.adoc&amp;description=%0A%0AFile:%20server_admin/topics/identity-broker/social/bitbucket.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>To log in with Bitbucket, perform the following procedure.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Identity Providers</strong> in the menu.</p> </li> <li> <p>From the <strong>Add provider</strong> list, select <strong>Bitbucket</strong>.</p> <div class="paragraph"> <div class="title">Add identity provider</div> <p><span class="image"><img src="./images/bitbucket-add-identity-provider.png" alt="Add Identity Provider"></span></p> </div> </li> <li> <p>Copy the value of <strong>Redirect URI</strong> to your clipboard.</p> </li> <li> <p>In a separate browser tab, perform the <a href="https://support.atlassian.com/bitbucket-cloud/docs/use-oauth-on-bitbucket-cloud/">OAuth on Bitbucket Cloud</a> process. When you click <strong>Add Consumer</strong>:</p> <div class="olist loweralpha"> <ol class="loweralpha" type="a"> <li> <p>Paste the value of <strong>Redirect URI</strong> into the <strong>Callback URL</strong> field.</p> </li> <li> <p>Ensure you select <strong>Email</strong> and <strong>Read</strong> in the <strong>Account</strong> section to permit your application to read email.</p> </li> </ol> </div> </li> <li> <p>Note the <strong>Key</strong> and <strong>Secret</strong> values Bitbucket displays when you create your consumer.</p> </li> <li> <p>In Keycloak, paste the value of the <code>Key</code> into the <strong>Client ID</strong> field.</p> </li> <li> <p>In Keycloak, paste the value of the <code>Secret</code> into the <strong>Client Secret</strong> field.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> </ol> </div> </div> <div class="sect3"> <h4 id="_facebook"><a class="anchor" href="#_facebook"></a>Facebook</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/identity-broker/social/facebook.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/identity-broker/social/facebook.adoc&amp;description=%0A%0AFile:%20server_admin/topics/identity-broker/social/facebook.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Identity Providers</strong> in the menu.</p> </li> <li> <p>From the <strong>Add provider</strong> list, select <strong>Facebook</strong>.</p> <div class="paragraph"> <div class="title">Add identity provider</div> <p><span class="image"><img src="./images/facebook-add-identity-provider.png" alt="Add Identity Provider"></span></p> </div> </li> <li> <p>Copy the value of <strong>Redirect URI</strong> to your clipboard.</p> </li> <li> <p>In a separate browser tab, open the <a href="https://developers.facebook.com/">Meta for Developers</a>.</p> <div class="olist loweralpha"> <ol class="loweralpha" type="a"> <li> <p>Click <strong>My Apps</strong>.</p> </li> <li> <p>Select <strong>Create App</strong>.</p> <div class="paragraph"> <div class="title">Add a use case</div> <p><span class="image"><img src="./images/meta-add-use-case.png" alt="Add a use case"></span></p> </div> </li> <li> <p>Select <strong>Other</strong>.</p> <div class="paragraph"> <div class="title">Select an app type</div> <p><span class="image"><img src="./images/meta-select-app-type.png" alt="Select an app type"></span></p> </div> </li> <li> <p>Select <strong>Consumer</strong>.</p> <div class="paragraph"> <div class="title">Create an app</div> <p><span class="image"><img src="./images/meta-create-app.png" alt="Create an app"></span></p> </div> </li> <li> <p>Fill in all required fields.</p> </li> <li> <p>Click <strong>Create app</strong>. Meta then brings you to the dashboard.</p> <div class="paragraph"> <div class="title">Add a product</div> <p><span class="image"><img src="./images/meta-add-product.png" alt="Add Product"></span></p> </div> </li> <li> <p>Click <strong>Set Up</strong> in the <strong>Facebook Login</strong> box.</p> </li> <li> <p>Select <strong>Web</strong>.</p> </li> <li> <p>Enter the <strong>Redirect URI&#8217;s</strong> value into the <strong>Site URL</strong> field and click <strong>Save</strong>.</p> </li> <li> <p>In the navigation panel, select <strong>App settings</strong> - <strong>Basic</strong>.</p> </li> <li> <p>Click <strong>Show</strong> in the <strong>App Secret</strong> field.</p> </li> <li> <p>Note the <strong>App ID</strong> and the <strong>App Secret</strong>.</p> </li> </ol> </div> </li> <li> <p>Enter the <a href="https://developers.facebook.com/docs/facebook-login/guides/access-tokens"><code>App ID</code> and <code>App Secret</code></a> values from your Facebook app into the <strong>Client ID</strong> and <strong>Client Secret</strong> fields in Keycloak.</p> </li> <li> <p>Click <strong>Add</strong></p> </li> <li> <p>Enter the required scopes into the <strong>Default Scopes</strong> field. By default, Keycloak uses the <strong>email</strong> scope. See <a href="https://developers.facebook.com/docs/graph-api">Graph API</a> for more information about Facebook scopes.</p> </li> </ol> </div> <div class="paragraph"> <p>Keycloak sends profile requests to <code>graph.facebook.com/me?fields=id,name,email,first_name,last_name</code> by default. The response contains the id, name, email, first_name, and last_name fields only. To fetch additional fields from the Facebook profile, add a corresponding scope and add the field name in the <code>Additional user&#8217;s profile fields</code> configuration option field.</p> </div> </div> <div class="sect3"> <h4 id="_github"><a class="anchor" href="#_github"></a>GitHub</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/identity-broker/social/github.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/identity-broker/social/github.adoc&amp;description=%0A%0AFile:%20server_admin/topics/identity-broker/social/github.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>To log in with GitHub, perform the following procedure.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Identity Providers</strong> in the menu.</p> </li> <li> <p>From the <strong>Add provider</strong> list, select <strong>Github</strong>.</p> <div class="paragraph"> <div class="title">Add identity provider</div> <p><span class="image"><img src="./images/github-add-identity-provider.png" alt="Add Identity Provider"></span></p> </div> </li> <li> <p>Copy the value of <strong>Redirect URI</strong> to your clipboard.</p> </li> <li> <p>In a separate browser tab, <a href="https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app">create an OAUTH app</a>.</p> <div class="olist loweralpha"> <ol class="loweralpha" type="a"> <li> <p>Enter the value of <strong>Redirect URI</strong> into the <strong>Authorization callback URL</strong> field when creating the app.</p> </li> <li> <p>Note the <strong>Client ID</strong> and <strong>Client secret</strong> on the management page of your OAUTH app.</p> </li> </ol> </div> </li> <li> <p>In Keycloak, paste the value of the <code>Client ID</code> into the <strong>Client ID</strong> field.</p> </li> <li> <p>In Keycloak, paste the value of the <code>Client secret</code> into the <strong>Client Secret</strong> field.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> </ol> </div> </div> <div class="sect3"> <h4 id="gitlab"><a class="anchor" href="#gitlab"></a>GitLab</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/identity-broker/social/gitlab.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/identity-broker/social/gitlab.adoc&amp;description=%0A%0AFile:%20server_admin/topics/identity-broker/social/gitlab.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Identity Providers</strong> in the menu.</p> </li> <li> <p>From the <strong>Add provider</strong> list, select <strong>GitLab</strong>.</p> <div class="paragraph"> <div class="title">Add identity provider</div> <p><span class="image"><img src="./images/gitlab-add-identity-provider.png" alt="Add Identity Provider"></span></p> </div> </li> <li> <p>Copy the value of <strong>Redirect URI</strong> to your clipboard.</p> </li> <li> <p>In a separate browser tab, <a href="https://docs.gitlab.com/ee/integration/oauth_provider.html">add a new GitLab application</a>.</p> <div class="olist loweralpha"> <ol class="loweralpha" type="a"> <li> <p>Use the <strong>Redirect URI</strong> in your clipboard as the <strong>Redirect URI</strong>.</p> </li> <li> <p>Note the <strong>Application ID</strong> and <strong>Secret</strong> when you save the application.</p> </li> </ol> </div> </li> <li> <p>In Keycloak, paste the value of the <code>Application ID</code> into the <strong>Client ID</strong> field.</p> </li> <li> <p>In Keycloak, paste the value of the <code>Secret</code> into the <strong>Client Secret</strong> field.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> </ol> </div> </div> <div class="sect3"> <h4 id="_google"><a class="anchor" href="#_google"></a>Google</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/identity-broker/social/google.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/identity-broker/social/google.adoc&amp;description=%0A%0AFile:%20server_admin/topics/identity-broker/social/google.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Identity Providers</strong> in the menu.</p> </li> <li> <p>From the <strong>Add provider</strong> list, select <strong>Google</strong>.</p> <div class="paragraph"> <div class="title">Add identity provider</div> <p><span class="image"><img src="./images/google-add-identity-provider.png" alt="Add Identity Provider"></span></p> </div> </li> <li> <p>Copy the value of <strong>Redirect URI</strong> to your clipboard.</p> </li> <li> <p>In a separate browser tab open <a href="https://console.cloud.google.com/">the Google Cloud Platform console</a>.</p> </li> <li> <p>In the Google dashboard for your Google app, in the Navigation menu on the left side, hover over <strong>APIs &amp; Services</strong> and then click on the <strong>OAuth consent screen</strong> option. Create a consent screen, ensuring that the user type of the consent screen is <strong>External</strong>.</p> </li> <li> <p>In the Google dashboard:</p> <div class="olist loweralpha"> <ol class="loweralpha" type="a"> <li> <p>Click the <strong>Credentials</strong> menu.</p> </li> <li> <p>Click <strong>CREATE CREDENTIALS</strong> - <strong>OAuth Client ID</strong>.</p> </li> <li> <p>From the <strong>Application type</strong> list, select <strong>Web application</strong>.</p> </li> <li> <p>Use the <strong>Redirect URI</strong> in your clipboard as the <strong>Authorized redirect URIs</strong></p> </li> <li> <p>Click <strong>Create</strong>.</p> </li> <li> <p>Note <strong>Your Client ID</strong> and <strong>Your Client secret</strong>.</p> </li> </ol> </div> </li> <li> <p>In Keycloak, paste the value of the <code>Your Client ID</code> into the <strong>Client ID</strong> field.</p> </li> <li> <p>In Keycloak, paste the value of the <code>Your Client secret</code> into the <strong>Client Secret</strong> field.</p> </li> <li> <p>Click <strong>Add</strong></p> </li> <li> <p>Enter the required scopes into the <strong>Default Scopes</strong> field. By default, Keycloak uses the following scopes: <strong>openid</strong> <strong>profile</strong> <strong>email</strong>. See the <a href="https://developers.google.com/oauthplayground/">OAuth Playground</a> for a list of Google scopes.</p> </li> <li> <p>To restrict access to your GSuite organization&#8217;s members only, enter the G Suite domain into the <strong>Hosted Domain</strong> field.</p> </li> <li> <p>Click <strong>Save</strong>.</p> </li> </ol> </div> </div> <div class="sect3"> <h4 id="instagram"><a class="anchor" href="#instagram"></a>Instagram</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/identity-broker/social/instagram.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/identity-broker/social/instagram.adoc&amp;description=%0A%0AFile:%20server_admin/topics/identity-broker/social/instagram.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Identity Providers</strong> in the menu.</p> </li> <li> <p>From the <strong>Add provider</strong> list, select <strong>Instagram</strong>.</p> <div class="paragraph"> <div class="title">Add identity provider</div> <p><span class="image"><img src="./images/instagram-add-identity-provider.png" alt="Add Identity Provider"></span></p> </div> </li> <li> <p>Copy the value of <strong>Redirect URI</strong> to your clipboard.</p> </li> <li> <p>In a separate browser tab, open the <a href="https://developers.facebook.com/">Meta for Developers</a>.</p> <div class="olist loweralpha"> <ol class="loweralpha" type="a"> <li> <p>Click <strong>My Apps</strong>.</p> </li> <li> <p>Select <strong>Create App</strong>.</p> <div class="paragraph"> <div class="title">Add a use case</div> <p><span class="image"><img src="./images/meta-add-use-case.png" alt="Add a use case"></span></p> </div> </li> <li> <p>Select <strong>Other</strong>.</p> <div class="paragraph"> <div class="title">Select an app type</div> <p><span class="image"><img src="./images/meta-select-app-type.png" alt="Select an app type"></span></p> </div> </li> <li> <p>Select <strong>Consumer</strong>.</p> <div class="paragraph"> <div class="title">Create an app</div> <p><span class="image"><img src="./images/meta-create-app.png" alt="Create an app"></span></p> </div> </li> <li> <p>Fill in all required fields.</p> </li> <li> <p>Click <strong>Create app</strong>. Meta then brings you to the dashboard.</p> </li> <li> <p>In the navigation panel, select <strong>App settings</strong> - <strong>Basic</strong>.</p> </li> <li> <p>Select <strong>+ Add Platform</strong> at the bottom of the page.</p> </li> <li> <p>Click <strong>[Website]</strong>.</p> </li> <li> <p>Enter a URL for your site.</p> <div class="paragraph"> <div class="title">Add a product</div> <p><span class="image"><img src="./images/meta-add-product.png" alt="Add Product"></span></p> </div> </li> <li> <p>Select <strong>Dashboard</strong> from the menu.</p> </li> <li> <p>Click <strong>Set Up</strong> in the <strong>Instagram Basic Display</strong> box.</p> </li> <li> <p>Click <strong>Create New App</strong>.</p> <div class="paragraph"> <div class="title">Create a New Instagram App ID</div> <p><span class="image"><img src="./images/instagram-create-instagram-app-id.png" alt="Create a New Instagram App ID"></span></p> </div> </li> <li> <p>Enter a value into the <strong>Display name</strong> field.</p> <div class="paragraph"> <div class="title">Set up the app</div> <p><span class="image"><img src="./images/instagram-app-settings.png" alt="Setup the App"></span></p> </div> </li> <li> <p>Paste the <strong>Redirect URL</strong> from Keycloak into the <strong>Valid OAuth Redirect URIs</strong> field.</p> </li> <li> <p>Paste the <strong>Redirect URL</strong> from Keycloak into the <strong>Deauthorize Callback URL</strong> field.</p> </li> <li> <p>Paste the <strong>Redirect URL</strong> from Keycloak into the <strong>Data Deletion Request URL</strong> field.</p> </li> <li> <p>Click <strong>Show</strong> in the <strong>Instagram App Secret</strong> field.</p> </li> <li> <p>Note the <strong>Instagram App ID</strong> and the <strong>Instagram App Secret</strong>.</p> </li> <li> <p>Click <strong>App Review</strong> - <strong>Requests</strong>.</p> </li> <li> <p>Follow the instructions on the screen.</p> </li> </ol> </div> </li> <li> <p>In Keycloak, paste the value of the <code>Instagram App ID</code> into the <strong>Client ID</strong> field.</p> </li> <li> <p>In Keycloak, paste the value of the <code>Instagram App Secret</code> into the <strong>Client Secret</strong> field.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> </ol> </div> </div> <div class="sect3"> <h4 id="_linkedin"><a class="anchor" href="#_linkedin"></a>LinkedIn</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/identity-broker/social/linked-in.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/identity-broker/social/linked-in.adoc&amp;description=%0A%0AFile:%20server_admin/topics/identity-broker/social/linked-in.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Identity Providers</strong> in the menu.</p> </li> <li> <p>From the <strong>Add provider</strong> list, select <strong>LinkedIn</strong>.</p> <div class="paragraph"> <div class="title">Add identity provider</div> <p><span class="image"><img src="./images/linked-in-add-identity-provider.png" alt="Add Identity Provider"></span></p> </div> </li> <li> <p>Copy the value of <strong>Redirect URI</strong> to your clipboard.</p> </li> <li> <p>In a separate browser tab, <a href="https://developer.linkedin.com">create an app</a> in the LinkedIn developer portal.</p> <div class="olist loweralpha"> <ol class="loweralpha" type="a"> <li> <p>After you create the app, click the <strong>Auth</strong> tab.</p> </li> <li> <p>Enter the value of <strong>Redirect URI</strong> into the <strong>Authorized redirect URLs for your app</strong> field.</p> </li> <li> <p>Note <strong>Your Client ID</strong> and <strong>Your Client Secret</strong>.</p> </li> <li> <p>Click the <strong>Products</strong> tab and <strong>Request access</strong> for the <strong>Sign In with LinkedIn using OpenID Connect</strong> product.</p> </li> </ol> </div> </li> <li> <p>In Keycloak, paste the value of the <code>Client ID</code> into the <strong>Client ID</strong> field.</p> </li> <li> <p>In Keycloak, paste the value of the <code>Client Secret</code> into the <strong>Client Secret</strong> field.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> </ol> </div> </div> <div class="sect3"> <h4 id="_microsoft"><a class="anchor" href="#_microsoft"></a>Microsoft</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/identity-broker/social/microsoft.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/identity-broker/social/microsoft.adoc&amp;description=%0A%0AFile:%20server_admin/topics/identity-broker/social/microsoft.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Identity Providers</strong> in the menu.</p> </li> <li> <p>From the <strong>Add provider</strong> list, select <strong>Microsoft</strong>.</p> <div class="paragraph"> <div class="title">Add identity provider</div> <p><span class="image"><img src="./images/microsoft-add-identity-provider.png" alt="Add Identity Provider"></span></p> </div> </li> <li> <p>Copy the value of <strong>Redirect URI</strong> to your clipboard.</p> </li> <li> <p>In a separate browser tab, register an app on <a href="https://azure.microsoft.com/en-us/">Microsoft Azure</a> under <strong>App registrations</strong>.</p> <div class="olist loweralpha"> <ol class="loweralpha" type="a"> <li> <p>In the Redirect URI section, select <strong>Web</strong> as a platform and paste the value of <strong>Redirect URI</strong> into the field.</p> </li> <li> <p>Find you application under <strong>App registrations</strong> and add a new client secret in the <strong>Certificates &amp; secrets</strong> section.</p> </li> <li> <p>Note the <strong>Value</strong> of the created secret.</p> </li> <li> <p>Note the <strong>Application (client) ID</strong> in the <strong>Overview</strong> section.</p> </li> </ol> </div> </li> <li> <p>In Keycloak, paste the value of the <code>Application (client) ID</code> into the <strong>Client ID</strong> field.</p> </li> <li> <p>In Keycloak, paste the <code>Value</code> of the secret into the <strong>Client Secret</strong> field.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> </ol> </div> </div> <div class="sect3"> <h4 id="openshift-3"><a class="anchor" href="#openshift-3"></a>OpenShift 3</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/identity-broker/social/openshift.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/identity-broker/social/openshift.adoc&amp;description=%0A%0AFile:%20server_admin/topics/identity-broker/social/openshift.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Identity Providers</strong> in the menu.</p> </li> <li> <p>From the <strong>Add provider</strong> list, select <strong>Openshift v3</strong>.</p> <div class="paragraph"> <div class="title">Add identity provider</div> <p><span class="image"><img src="./images/openshift-add-identity-provider.png" alt="Add Identity Provider"></span></p> </div> </li> <li> <p>Copy the value of <strong>Redirect URI</strong> to your clipboard.</p> </li> <li> <p>Register your client using the <code>oc</code> command-line tool.</p> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>$ oc create -f &lt;(echo ' kind: OAuthClient apiVersion: v1 metadata: name: kc-client <i class="conum" data-value="1"></i><b>(1)</b> secret: "..." <i class="conum" data-value="2"></i><b>(2)</b> redirectURIs: - "http://www.example.com/" <i class="conum" data-value="3"></i><b>(3)</b> grantMethod: prompt <i class="conum" data-value="4"></i><b>(4)</b> ')</code></pre> </div> </div> </li> </ol> </div> <div class="colist arabic"> <table> <tr> <td><i class="conum" data-value="1"></i><b>1</b></td> <td>The <code>name</code> of your OAuth client. Passed as <code>client_id</code> request parameter when making requests to <code><em>&lt;openshift_master&gt;</em>/oauth/authorize</code> and <code><em>&lt;openshift_master&gt;</em>/oauth/token</code>.</td> </tr> <tr> <td><i class="conum" data-value="2"></i><b>2</b></td> <td>The <code>secret</code> Keycloak uses for the <code>client_secret</code> request parameter.</td> </tr> <tr> <td><i class="conum" data-value="3"></i><b>3</b></td> <td>The <code>redirect_uri</code> parameter specified in requests to <code><em>&lt;openshift_master&gt;</em>/oauth/authorize</code> and <code><em>&lt;openshift_master&gt;</em>/oauth/token</code> must be equal to (or prefixed by) one of the URIs in <code>redirectURIs</code>. You can obtain this from the <strong>Redirect URI</strong> field in the Identity Provider screen</td> </tr> <tr> <td><i class="conum" data-value="4"></i><b>4</b></td> <td>The <code>grantMethod</code> Keycloak uses to determine the action when this client requests tokens but has not been granted access by the user. <div class="olist arabic"> <ol class="arabic"> <li> <p>In Keycloak, paste the value of the <strong>Client ID</strong> into the <strong>Client ID</strong> field.</p> </li> <li> <p>In Keycloak, paste the value of the <strong>Client Secret</strong> into the <strong>Client Secret</strong> field.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> </ol> </div></td> </tr> </table> </div> </div> <div class="sect3"> <h4 id="openshift-4"><a class="anchor" href="#openshift-4"></a>OpenShift 4</h4> <div class="olist arabic"> <div class="title">Prerequisites</div> <ol class="arabic"> <li> <p>A certificate of the OpenShift 4 instance stored in the Keycloak Truststore.</p> </li> <li> <p>A Keycloak server configured in order to use the truststore. For more information, see the <a href="https://www.keycloak.org/server/keycloak-truststore">Configuring a Truststore</a> guide.</p> </li> </ol> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Identity Providers</strong> in the menu.</p> </li> <li> <p>From the <strong>Add provider</strong> list, select <strong>Openshift v4</strong>.</p> </li> <li> <p>Enter the <strong>Client ID</strong> and <strong>Client Secret</strong> and in the <strong>Base URL</strong> field, enter the API URL of your OpenShift 4 instance. Additionally, you can copy the <strong>Redirect URI</strong> to your clipboard.</p> <div class="paragraph"> <div class="title">Add identity provider</div> <p><span class="image"><img src="./images/openshift-4-add-identity-provider.png" alt="Add Identity Provider"></span></p> </div> </li> <li> <p>Register your client, either via OpenShift 4 Console (Home &#8594; API Explorer &#8594; OAuth Client &#8594; Instances) or using the <code>oc</code> command-line tool.</p> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>$ oc create -f &lt;(echo ' kind: OAuthClient apiVersion: oauth.openshift.io/v1 metadata: name: kc-client <i class="conum" data-value="1"></i><b>(1)</b> secret: "..." <i class="conum" data-value="2"></i><b>(2)</b> redirectURIs: - "&lt;here you can paste the Redirect URI that you copied in the previous step&gt;" <i class="conum" data-value="3"></i><b>(3)</b> grantMethod: prompt <i class="conum" data-value="4"></i><b>(4)</b> ')</code></pre> </div> </div> </li> </ol> </div> <div class="colist arabic"> <table> <tr> <td><i class="conum" data-value="1"></i><b>1</b></td> <td>The <code>name</code> of your OAuth client. Passed as <code>client_id</code> request parameter when making requests to <code><em>&lt;openshift_master&gt;</em>/oauth/authorize</code> and <code><em>&lt;openshift_master&gt;</em>/oauth/token</code>. The <code>name</code> parameter must be the same in the <code>OAuthClient</code> object and the Keycloak configuration.</td> </tr> <tr> <td><i class="conum" data-value="2"></i><b>2</b></td> <td>The <code>secret</code> Keycloak uses as the <code>client_secret</code> request parameter.</td> </tr> <tr> <td><i class="conum" data-value="3"></i><b>3</b></td> <td>The <code>redirect_uri</code> parameter specified in requests to <code><em>&lt;openshift_master&gt;</em>/oauth/authorize</code> and <code><em>&lt;openshift_master&gt;</em>/oauth/token</code> must be equal to (or prefixed by) one of the URIs in <code>redirectURIs</code>. The easiest way to configure it correctly is to copy-paste it from Keycloak OpenShift 4 Identity Provider configuration page (<code>Redirect URI</code> field).</td> </tr> <tr> <td><i class="conum" data-value="4"></i><b>4</b></td> <td>The <code>grantMethod</code> Keycloak uses to determine the action when this client requests tokens but has not been granted access by the user.</td> </tr> </table> </div> <div class="paragraph"> <p>In the end you should see the OpenShift 4 Identity Provider on the login page of your Keycloak instance. After clicking on it, you should be redirected to the OpenShift 4 login page.</p> </div> <div class="paragraph"> <div class="title">Result</div> <p><span class="image"><img src="./images/openshift-4-result.png" alt="Result"></span></p> </div> <div class="paragraph"> <p>See <a href="https://docs.okd.io/latest/authentication/configuring-oauth-clients.html#oauth-register-additional-client_configuring-oauth-clients">official OpenShift documentation</a> for more information.</p> </div> </div> <div class="sect3"> <h4 id="paypal"><a class="anchor" href="#paypal"></a>PayPal</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/identity-broker/social/paypal.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/identity-broker/social/paypal.adoc&amp;description=%0A%0AFile:%20server_admin/topics/identity-broker/social/paypal.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Identity Providers</strong> in the menu.</p> </li> <li> <p>From the <strong>Add provider</strong> list, select <strong>PayPal</strong>.</p> <div class="paragraph"> <div class="title">Add identity provider</div> <p><span class="image"><img src="./images/paypal-add-identity-provider.png" alt="Add Identity Provider"></span></p> </div> </li> <li> <p>Copy the value of <strong>Redirect URI</strong> to your clipboard.</p> </li> <li> <p>In a separate browser tab, open the <a href="https://developer.paypal.com/developer/applications">PayPal Developer applications area</a>.</p> <div class="olist loweralpha"> <ol class="loweralpha" type="a"> <li> <p>Click <strong>Create App</strong> to create a PayPal app.</p> </li> <li> <p>Note the <strong>Client ID</strong> and <strong>Client Secret</strong>. Click the <strong>Show</strong> link to view the secret.</p> </li> <li> <p>Ensure <strong>Log in with PayPal</strong> is checked.</p> </li> <li> <p>Under Log in with PayPal click on <strong>Advanced Settings</strong>.</p> </li> <li> <p>Set the value of the <strong>Return URL</strong> field to the value of <strong>Redirect URI</strong> from Keycloak. Note that the URL can not contain <code>localhost</code>. If you want to use Keycloak locally, replace the <code>localhost</code> in the <strong>Return URL</strong> by <code>127.0.0.1</code> and then access Keycloak using <code>127.0.0.1</code> in the browser instead of <code>localhost</code>.</p> </li> <li> <p>Ensure <strong>Full Name</strong> and <strong>Email</strong> fields are checked.</p> </li> <li> <p>Click <strong>Save</strong> and then <strong>Save Changes</strong>.</p> </li> </ol> </div> </li> <li> <p>In Keycloak, paste the value of the <code>Client ID</code> into the <strong>Client ID</strong> field.</p> </li> <li> <p>In Keycloak, paste the value of the <code>Secret key 1</code> into the <strong>Client Secret</strong> field.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> </ol> </div> </div> <div class="sect3"> <h4 id="_stackoverflow"><a class="anchor" href="#_stackoverflow"></a>Stack Overflow</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/identity-broker/social/stack-overflow.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/identity-broker/social/stack-overflow.adoc&amp;description=%0A%0AFile:%20server_admin/topics/identity-broker/social/stack-overflow.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Identity Providers</strong> in the menu.</p> </li> <li> <p>From the <strong>Add provider</strong> list, select <strong>Stack Overflow</strong>.</p> <div class="paragraph"> <div class="title">Add identity provider</div> <p><span class="image"><img src="./images/stack-overflow-add-identity-provider.png" alt="Add Identity Provider"></span></p> </div> </li> <li> <p>In a separate browser tab, log into <a href="https://stackapps.com/apps/oauth/register">registering your application on Stack Apps</a>.</p> <div class="paragraph"> <div class="title">Register application</div> <p><span class="image"><img src="./images/stack-overflow-app-register.png" alt="Register Application"></span></p> </div> <div class="olist loweralpha"> <ol class="loweralpha" type="a"> <li> <p>Enter your application name into the <strong>Application Name</strong> field.</p> </li> <li> <p>Enter the OAuth domain into the <strong>OAuth Domain</strong> field.</p> </li> <li> <p>Click <strong>Register Your Application</strong>.</p> <div class="paragraph"> <div class="title">Settings</div> <p><span class="image"><img src="./images/stack-overflow-app-settings.png" alt="Settings"></span></p> </div> </li> </ol> </div> </li> <li> <p>Note the <strong>Client Id</strong>, <strong>Client Secret</strong>, and <strong>Key</strong>.</p> </li> <li> <p>In Keycloak, paste the value of the <code>Client Id</code> into the <strong>Client ID</strong> field.</p> </li> <li> <p>In Keycloak, paste the value of the <code>Client Secret</code> into the <strong>Client Secret</strong> field.</p> </li> <li> <p>In Keycloak, paste the value of the <code>Key</code> into the <strong>Key</strong> field.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> </ol> </div> </div> <div class="sect3"> <h4 id="_twitter"><a class="anchor" href="#_twitter"></a>Twitter</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/identity-broker/social/twitter.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/identity-broker/social/twitter.adoc&amp;description=%0A%0AFile:%20server_admin/topics/identity-broker/social/twitter.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="olist arabic"> <div class="title">Prerequisites</div> <ol class="arabic"> <li> <p>A Twitter developer account.</p> </li> </ol> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Identity Providers</strong> in the menu.</p> </li> <li> <p>From the <strong>Add provider</strong> list, select <strong>Twitter</strong>.</p> <div class="paragraph"> <div class="title">Add identity provider</div> <p><span class="image"><img src="./images/twitter-add-identity-provider.png" alt="Add Identity Provider"></span></p> </div> </li> <li> <p>Copy the value of <strong>Redirect URI</strong> to your clipboard.</p> </li> <li> <p>In a separate browser tab, create an app in <a href="https://developer.twitter.com/apps/">Twitter Application Management</a>.</p> <div class="olist loweralpha"> <ol class="loweralpha" type="a"> <li> <p>Enter App name and click <strong>Next</strong>.</p> </li> <li> <p>Note the value of <strong>API Key</strong> and <strong>API Key Secret</strong> and click <strong>App settings</strong>.</p> </li> <li> <p>In the <strong>User authentication settings</strong> section click on the <strong>Set up</strong> button.</p> </li> <li> <p>Select <strong>Web App</strong> as the <strong>Type of App</strong>.</p> </li> <li> <p>Paste the value of the <strong>Redirect URL</strong> into the <strong>Callback URI / Redirect URL</strong> field.</p> </li> <li> <p>The value for <strong>Website URL</strong> can be any valid URL except <code>localhost</code>.</p> </li> <li> <p>Click <strong>Save</strong> and then <strong>Done</strong>.</p> </li> </ol> </div> </li> <li> <p>In Keycloak, paste the value of the <code>API Key</code> into the <strong>Client ID</strong> field.</p> </li> <li> <p>In Keycloak, paste the value of the <code>API Key Secret</code> into the <strong>Client Secret</strong> field.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> </ol> </div> </div> </div> <div class="sect2"> <h3 id="_identity_broker_oidc"><a class="anchor" href="#_identity_broker_oidc"></a>OpenID Connect v1.0 identity providers</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/identity-broker/oidc.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/identity-broker/oidc.adoc&amp;description=%0A%0AFile:%20server_admin/topics/identity-broker/oidc.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Keycloak brokers identity providers based on the OpenID Connect protocol. These identity providers (IDPs) must support the <a href="#con-oidc-auth-flows_server_administration_guide">Authorization Code Flow</a> defined in the specification to authenticate users and authorize access.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Identity Providers</strong> in the menu.</p> </li> <li> <p>From the <code>Add provider</code> list, select <code>OpenID Connect v1.0</code>.</p> <div class="paragraph"> <div class="title">Add identity provider</div> <p><span class="image"><img src="./images/oidc-add-identity-provider.png" alt="Add Identity Provider"></span></p> </div> </li> <li> <p>Enter your initial configuration options. See <a href="#_general-idp-config">General IDP Configuration</a> for more information about configuration options.</p> <table class="tableblock frame-all grid-all stretch"> <caption class="title">Table 2. OpenID connect config</caption> <colgroup> <col style="width: 50%;"> <col style="width: 50%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Configuration</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Authorization URL</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The authorization URL endpoint the OIDC protocol requires.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Token URL</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The token URL endpoint the OIDC protocol requires.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Logout URL</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The logout URL endpoint in the OIDC protocol. This value is optional.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Backchannel Logout</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">A background, out-of-band, REST request to the IDP to log out the user. Some IDPs perform logout through browser redirects only, as they may identify sessions using a browser cookie.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">User Info URL</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">An endpoint the OIDC protocol defines. This endpoint points to user profile information.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Client Authentication</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Defines the Client Authentication method Keycloak uses with the Authorization Code Flow. In the case of JWT signed with a private key, Keycloak uses the realm private key. In the other cases, define a client secret. See the <a href="https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication">Client Authentication specifications</a> for more information.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Client ID</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">A realm acting as an OIDC client to the external IDP. The realm must have an OIDC client ID if you use the Authorization Code Flow to interact with the external IDP.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Client Secret</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Client secret from an external <a href="#_vault-administration">vault</a>. This secret is necessary if you are using the Authorization Code Flow.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Client Assertion Signature Algorithm</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Signature algorithm to create JWT assertion as client authentication. In the case of JWT signed with private key or Client secret as jwt, it is required. If no algorithm is specified, the following algorithm is adapted. <code>RS256</code> is adapted in the case of JWT signed with private key. <code>HS256</code> is adapted in the case of Client secret as jwt.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Client Assertion Audience</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The audience to use for the client assertion. The default value is the IDP&#8217;s token endpoint URL.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Issuer</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Keycloak validates issuer claims, in responses from the IDP, against this value.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Default Scopes</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">A list of OIDC scopes Keycloak sends with the authentication request. The default value is <code>openid</code>. A space separates each scope.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Prompt</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The prompt parameter in the OIDC specification. Through this parameter, you can force re-authentication and other options. See the specification for more details.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Accepts prompt=none forward from client</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Specifies if the IDP accepts forwarded authentication requests containing the <code>prompt=none</code> query parameter. If a realm receives an auth request with <code>prompt=none</code>, the realm checks if the user is currently authenticated and returns a <code>login_required</code> error if the user has not logged in. When Keycloak determines a default IDP for the auth request (using the <code>kc_idp_hint</code> query parameter or having a default IDP for the realm), you can forward the auth request with <code>prompt=none</code> to the default IDP. The default IDP checks the authentication of the user there. Because not all IDPs support requests with <code>prompt=none</code>, Keycloak uses this switch to indicate that the default IDP supports the parameter before redirecting the authentication request.</p> <p class="tableblock">If the user is unauthenticated in the IDP, the client still receives a <code>login_required</code> error. If the user is authentic in the IDP, the client can still receive an <code>interaction_required</code> error if Keycloak must display authentication pages that require user interaction. This authentication includes required actions (for example, password change), consent screens, and screens set to display by the <code>first broker login</code> flow or <code>post broker login</code> flow.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Validate Signatures</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Specifies if Keycloak verifies signatures on the external ID Token signed by this IDP. If <strong>ON</strong>, Keycloak must know the public key of the external OIDC IDP. For performance purposes, Keycloak caches the public key of the external OIDC identity provider.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Use JWKS URL</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">This switch is applicable if <code>Validate Signatures</code> is <strong>ON</strong>. If <strong>Use JWKS URL</strong> is <strong>ON</strong>, Keycloak downloads the IDP&#8217;s public keys from the JWKS URL. New keys download when the identity provider generates a new keypair. If <strong>OFF</strong>, Keycloak uses the public key (or certificate) from its database, so when the IDP keypair changes, import the new key to the Keycloak database as well.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">JWKS URL</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The URL pointing to the location of the IDP JWK keys. For more information, see the <a href="https://datatracker.ietf.org/doc/html/rfc7517">JWK specification</a>. If you use an external Keycloak as an IDP, you can use a URL such as <a href="http://broker-keycloak:8180/realms/test/protocol/openid-connect/certs" class="bare">http://broker-keycloak:8180/realms/test/protocol/openid-connect/certs</a> if your brokered Keycloak is running on <a href="http://broker-keycloak:8180" class="bare">http://broker-keycloak:8180</a> and its realm is <code>test</code>.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Validating Public Key</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The public key in PEM format that Keycloak uses to verify external IDP signatures. This key applies if <code>Use JWKS URL</code> is <strong>OFF</strong>.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Validating Public Key Id</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">This setting applies if <strong>Use JWKS URL</strong> is <strong>OFF</strong>. This setting specifies the ID of the public key in PEM format. Because there is no standard way for computing key ID from the key, external identity providers can use different algorithms from what Keycloak uses. If this field&#8217;s value is not specified, Keycloak uses the validating public key for all requests, regardless of the key ID sent by the external IDP. When <strong>ON</strong>, this field&#8217;s value is the key ID used by Keycloak for validating signatures from providers and must match the key ID specified by the IDP.</p></td> </tr> </tbody> </table> </li> </ol> </div> <div class="paragraph"> <p>You can import all this configuration data by providing a URL or file that points to OpenID Provider Metadata. If you connect to a Keycloak external IDP, you can import the IDP settings from <code>&lt;root&gt;/realms/{realm-name}/.well-known/openid-configuration</code>. This link is a JSON document describing metadata about the IDP.</p> </div> <div class="paragraph"> <p>If you want to use <a href="https://datatracker.ietf.org/doc/html/rfc7516">Json Web Encryption (JWE)</a> ID Tokens or UserInfo responses in the provider, the IDP needs to know the public key to use with Keycloak. The provider uses the <a href="#realm_keys">realm keys</a> defined for the different encryption algorithms to decrypt the tokens. Keycloak provides a standard <a href="#con-server-oidc-uri-endpoints_server_administration_guide">JWKS endpoint</a> which the IDP can use for downloading the keys automatically.</p> </div> </div> <div class="sect2"> <h3 id="saml-v2-0-identity-providers"><a class="anchor" href="#saml-v2-0-identity-providers"></a>SAML v2.0 Identity Providers</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/identity-broker/saml.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/identity-broker/saml.adoc&amp;description=%0A%0AFile:%20server_admin/topics/identity-broker/saml.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Keycloak can broker identity providers based on the SAML v2.0 protocol.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Identity Providers</strong> in the menu.</p> </li> <li> <p>From the <code>Add provider</code> list, select <code>SAML v2.0</code>.</p> <div class="paragraph"> <div class="title">Add identity provider</div> <p><span class="image"><img src="./images/saml-add-identity-provider.png" alt="Add Identity Provider"></span></p> </div> </li> <li> <p>Enter your initial configuration options. See <a href="#_general-idp-config">General IDP Configuration</a> for more information about configuration options.</p> </li> </ol> </div> <table class="tableblock frame-all grid-all stretch"> <caption class="title">Table 3. SAML Config</caption> <colgroup> <col style="width: 50%;"> <col style="width: 50%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Configuration</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Service Provider Entity ID</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The SAML Entity ID that the remote Identity Provider uses to identify requests from this Service Provider. By default, this setting is set to the realms base URL <code>&lt;root&gt;/realms/{realm-name}</code>.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Identity Provider Entity ID</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The Entity ID used to validate the Issuer for received SAML assertions. If empty, no Issuer validation is performed.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Single Sign-On Service URL</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The SAML endpoint that starts the authentication process. If your SAML IDP publishes an IDP entity descriptor, the value of this field is specified there.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Artifact service URL</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The SAML artifact resolution endpoint. If your SAML IDP publishes an IDP entity descriptor, the value of this field is specified there.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Single Logout Service URL</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The SAML logout endpoint. If your SAML IDP publishes an IDP entity descriptor, the value of this field is specified there.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Backchannel Logout</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Toggle this switch to <strong>ON</strong> if your SAML IDP supports back channel logout.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">NameID Policy Format</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The URI reference corresponding to a name identifier format. By default, Keycloak sets it to <code>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</code>.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Principal Type</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Specifies which part of the SAML assertion will be used to identify and track external user identities. Can be either Subject NameID or SAML attribute (either by name or by friendly name). Subject NameID value can not be set together with 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient' NameID Policy Format value.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Principal Attribute</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">If a Principal type is non-blank, this field specifies the name ("Attribute [Name]") or the friendly name ("Attribute [Friendly Name]") of the identifying attribute.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Allow create</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Allow the external identity provider to create a new identifier to represent the principal.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">HTTP-POST Binding Response</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Controls the SAML binding in response to any SAML requests sent by an external IDP. When <strong>OFF</strong>, Keycloak uses Redirect Binding.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">ARTIFACT Binding Response</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Controls the SAML binding in response to any SAML requests sent by an external IDP. When <strong>OFF</strong>, Keycloak evaluates the HTTP-POST Binding Response configuration.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">HTTP-POST Binding for AuthnRequest</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Controls the SAML binding when requesting authentication from an external IDP. When <strong>OFF</strong>, Keycloak uses Redirect Binding.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Want AuthnRequests Signed</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">When <strong>ON</strong>, Keycloak uses the realm&#8217;s keypair to sign requests sent to the external SAML IDP.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Want Assertions Signed</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Indicates whether this service provider expects a signed Assertion.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Want Assertions Encrypted</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Indicates whether this service provider expects an encrypted Assertion.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Signature Algorithm</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">If <strong>Want AuthnRequests Signed</strong> is <strong>ON</strong>, the signature algorithm to use. Note that <code>SHA1</code> based algorithms are deprecated and may be removed in a future release. We recommend to use some more secure algorithm instead of <code>*_SHA1</code>. Also, with <code>*_SHA1</code> algorithms, verifying signatures do not work if the SAML identity provider (for example another instance of Keycloak) runs on Java 17 or higher.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Encryption Algorithm</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Encryption algorithm, which is used by SAML IDP for encryption of SAML documents, assertions, or IDs. The corresponding decryption key for decrypt SAML document parts will be chosen based on this configured algorithm and should be available in realm keys for the encryption (ENC) usage. If the algorithm is not configured, any supported algorithm is allowed and a decryption key will be chosen based on the algorithm specified in SAML document itself.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">SAML Signature Key Name</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Signed SAML documents sent using POST binding contain the identification of signing key in <code>KeyName</code> element, which, by default, contains the Keycloak key ID. External SAML IDPs can expect a different key name. This switch controls whether <code>KeyName</code> contains: * <code>KEY_ID</code> - Key ID. * <code>CERT_SUBJECT</code> - the subject from the certificate corresponding to the realm key. Microsoft Active Directory Federation Services expect <code>CERT_SUBJECT</code>. * <code>NONE</code> - Keycloak omits the key name hint from the SAML message.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Force Authentication</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The user must enter their credentials at the external IDP even when the user is already logged in.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Validate Signature</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">When <strong>ON</strong>, the realm expects SAML requests and responses from the external IDP to be digitally signed.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Metadata descriptor URL</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">External URL where Identity Provider publishes the <code>IDPSSODescriptor</code> metadata. This URL is used to download the Identity Provider certificates when the <code>Reload keys</code> or <code>Import keys</code> actions are clicked.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Use metadata descriptor URL</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">When <strong>ON</strong>, the certificates to validate signatures are automatically downloaded from the <code>Metadata descriptor URL</code> and cached in Keycloak. The SAML provider can validate signatures in two different ways. If a specific certificate is requested (usually in <code>POST</code> binding) and it is not in the cache, certificates are automatically refreshed from the URL. If all certificates are requested to validate the signature (<code>REDIRECT</code> binding) the refresh is only done after a max cache time (see <a href="https://www.keycloak.org/server/all-provider-config">public-key-storage</a> spi in the all provider config guide for more information about how the cache works). The cache can also be manually updated using the action <code>Reload Keys</code> in the identity provider page.</p> <p class="tableblock">When the option is <strong>OFF</strong>, the certificates in <code>Validating X509 Certificates</code> are used to validate signatures.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Validating X509 Certificates</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The public certificates Keycloak uses to validate the signatures of SAML requests and responses from the external IDP when <code>Use metadata descriptor URL</code> is <strong>OFF</strong>. Multiple certificates can be entered separated by comma (<code>,</code>). The certificates can be re-imported from the <code>Metadata descriptor URL</code> clicking the <code>Import Keys</code> action in the identity provider page. The action downloads the current certificates in the metadata endpoint and assigns them to the config in this same option. You need to click <code>Save</code> to definitely store the re-imported certificates.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Sign Service Provider Metadata</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">When <strong>ON</strong>, Keycloak uses the realm&#8217;s key pair to sign the <a href="#_identity_broker_saml_sp_descriptor">SAML Service Provider Metadata descriptor</a>.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Pass subject</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Controls if Keycloak forwards a <code>login_hint</code> query parameter to the IDP. Keycloak adds this field&#8217;s value to the login_hint parameter in the AuthnRequest&#8217;s Subject so destination providers can pre-fill their login form.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Attribute Consuming Service Index</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Identifies the attribute set to request to the remote IDP. Keycloak automatically adds the attributes mapped in the identity provider configuration to the autogenerated SP metadata document.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Attribute Consuming Service Name</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">A descriptive name for the set of attributes that are advertised in the autogenerated SP metadata document.</p></td> </tr> </tbody> </table> <div class="paragraph"> <p>You can import all configuration data by providing a URL or a file pointing to the SAML IDP entity descriptor of the external IDP. If you are connecting to a Keycloak external IDP, you can import the IDP settings from the URL <code>&lt;root&gt;/realms/{realm-name}/protocol/saml/descriptor</code>. This link is an XML document describing metadata about the IDP. You can also import all this configuration data by providing a URL or XML file pointing to the external SAML IDP&#8217;s entity descriptor to connect to.</p> </div> <div class="sect3"> <h4 id="_identity_broker_saml_requested_authncontext"><a class="anchor" href="#_identity_broker_saml_requested_authncontext"></a>Requesting specific AuthnContexts</h4> <div class="paragraph"> <p>Identity Providers facilitate clients specifying constraints on the authentication method verifying the user identity. For example, asking for MFA, Kerberos authentication, or security requirements. These constraints use particular AuthnContext criteria. A client can ask for one or more criteria and specify how the Identity Provider must match the requested AuthnContext, exactly, or by satisfying other equivalents.</p> </div> <div class="paragraph"> <p>You can list the criteria your Service Provider requires by adding ClassRefs or DeclRefs in the Requested AuthnContext Constraints section. Usually, you need to provide either ClassRefs or DeclRefs, so check with your Identity Provider documentation which values are supported. If no ClassRefs or DeclRefs are present, the Identity Provider does not enforce additional constraints.</p> </div> <table class="tableblock frame-all grid-all stretch"> <caption class="title">Table 4. Requested AuthnContext Constraints</caption> <colgroup> <col style="width: 50%;"> <col style="width: 50%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Configuration</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Comparison</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The method the Identity Provider uses to evaluate the context requirements. The available values are <code>Exact</code>, <code>Minimum</code>, <code>Maximum</code>, or <code>Better</code>. The default value is <code>Exact</code>.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">AuthnContext ClassRefs</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The AuthnContext ClassRefs describing the required criteria.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">AuthnContext DeclRefs</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The AuthnContext DeclRefs describing the required criteria.</p></td> </tr> </tbody> </table> </div> <div class="sect3"> <h4 id="_identity_broker_saml_sp_descriptor"><a class="anchor" href="#_identity_broker_saml_sp_descriptor"></a>SP Descriptor</h4> <div class="paragraph"> <p>When you access the provider&#8217;s SAML SP metadata, look for the <code>Endpoints</code> item in the identity provider configuration settings. It contains a <code>SAML 2.0 Service Provider Metadata</code> link which generates the SAML entity descriptor for the Service Provider. You can download the descriptor or copy its URL and then import it into the remote Identity Provider.</p> </div> <div class="paragraph"> <p>This metadata is also available publicly by going to the following URL:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>http[s]://{host:port}/realms/{realm-name}/broker/{broker-alias}/endpoint/descriptor</code></pre> </div> </div> <div class="paragraph"> <p>Ensure you save any configuration changes before accessing the descriptor.</p> </div> </div> <div class="sect3"> <h4 id="_identity_broker_saml_login_hint"><a class="anchor" href="#_identity_broker_saml_login_hint"></a>Send subject in SAML requests</h4> <div class="paragraph"> <p>By default, a social button pointing to a SAML Identity Provider redirects the user to the following login URL:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>http[s]://{host:port}/realms/${realm-name}/broker/{broker-alias}/login</code></pre> </div> </div> <div class="paragraph"> <p>Adding a query parameter named <code>login_hint</code> to this URL adds the parameter&#8217;s value to SAML request as a Subject attribute. If this query parameter is empty, Keycloak does not add a subject to the request.</p> </div> <div class="paragraph"> <p>Enable the "Pass subject" option to send the subject in SAML requests.</p> </div> </div> </div> <div class="sect2"> <h3 id="_client_suggested_idp"><a class="anchor" href="#_client_suggested_idp"></a>Client-suggested Identity Provider</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/identity-broker/suggested.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/identity-broker/suggested.adoc&amp;description=%0A%0AFile:%20server_admin/topics/identity-broker/suggested.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>OIDC applications can bypass the Keycloak login page by hinting at the identity provider they want to use. You can enable this by setting the <code>kc_idp_hint</code> query parameter in the Authorization Code Flow authorization endpoint.</p> </div> <div class="paragraph"> <p>With Keycloak OIDC client adapters, you can specify this query parameter when you access a secured resource in the application.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">GET /myapplication.com?kc_idp_hint=facebook HTTP/1.1 Host: localhost:8080</code></pre> </div> </div> <div class="paragraph"> <p>In this case, your realm must have an identity provider with a <code>facebook</code> alias. If this provider does not exist, the login form is displayed.</p> </div> <div class="paragraph"> <p>If you are using the JavaScript adapter, you can also achieve the same behavior as follows:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="javascript">const keycloak = <span class="keyword">new</span> Keycloak({ <span class="key">url</span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">http://keycloak-server</span><span class="delimiter">&quot;</span></span>, <span class="key">realm</span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">my-realm</span><span class="delimiter">&quot;</span></span>, <span class="key">clientId</span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">my-app</span><span class="delimiter">&quot;</span></span> ); await keycloak.createLoginUrl({ <span class="key">idpHint</span>: <span class="string"><span class="delimiter">'</span><span class="content">facebook</span><span class="delimiter">'</span></span> });</code></pre> </div> </div> <div class="paragraph"> <p>With the <code>kc_idp_hint</code> query parameter, the client can override the default identity provider if you configure one for the <code>Identity Provider Redirector</code> authenticator. The client can disable the automatic redirecting by setting the <code>kc_idp_hint</code> query parameter to an empty value.</p> </div> </div> <div class="sect2"> <h3 id="_mappers"><a class="anchor" href="#_mappers"></a>Mapping claims and assertions</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/identity-broker/mappers.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/identity-broker/mappers.adoc&amp;description=%0A%0AFile:%20server_admin/topics/identity-broker/mappers.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>You can import the SAML and OpenID Connect metadata, provided by the external IDP you are authenticating with, into the realm. After importing, you can extract user profile metadata and other information, so you can make it available to your applications.</p> </div> <div class="paragraph"> <p>Each user logging into your realm using an external identity provider has an entry in the local Keycloak database, based on the metadata from the SAML or OIDC assertions and claims.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Identity Providers</strong> in the menu.</p> </li> <li> <p>Select one of the identity providers in the list.</p> </li> <li> <p>Click the <strong>Mappers</strong> tab.</p> <div class="paragraph"> <div class="title">Identity provider mappers</div> <p><span class="image"><img src="./images/identity-provider-mappers.png" alt="identity provider mappers"></span></p> </div> </li> <li> <p>Click <strong>Add mapper</strong>.</p> <div class="paragraph"> <div class="title">Identity provider mapper</div> <p><span class="image"><img src="./images/identity-provider-mapper.png" alt="identity provider mapper"></span></p> </div> </li> <li> <p>Select a value for <strong>Sync Mode Override</strong>. The mapper updates user information when users log in repeatedly according to this setting.</p> <div class="olist loweralpha"> <ol class="loweralpha" type="a"> <li> <p>Select <strong>legacy</strong> to use the behavior of the previous Keycloak version.</p> </li> <li> <p>Select <strong>import</strong> to import data from when the user was first created in Keycloak during the first login to Keycloak with a particular identity provider.</p> </li> <li> <p>Select <strong>force</strong> to update user data at each user login.</p> </li> <li> <p>Select <strong>inherit</strong> to use the sync mode configured in the identity provider. All other options will override this sync mode.</p> </li> </ol> </div> </li> <li> <p>Select a mapper from the <strong>Mapper Type</strong> list. Hover over the <strong>Mapper Type</strong> for a description of the mapper and configuration to enter for the mapper.</p> </li> <li> <p>Click <strong>Save</strong>.</p> </li> </ol> </div> <div class="paragraph"> <p>For JSON-based claims, you can use dot notation for nesting and square brackets to access array fields by index. For example, <code>contact.address[0].country</code>.</p> </div> <div class="paragraph"> <p>To investigate the structure of user profile JSON data provided by social providers, you can enable the <code>DEBUG</code> level logger <code>org.keycloak.social.user_profile_dump</code> when starting the server.</p> </div> </div> <div class="sect2"> <h3 id="available-user-session-data"><a class="anchor" href="#available-user-session-data"></a>Available user session data</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/identity-broker/session-data.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/identity-broker/session-data.adoc&amp;description=%0A%0AFile:%20server_admin/topics/identity-broker/session-data.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>After a user login from an external IDP, Keycloak stores user session note data that you can access. This data can be propagated to the client requesting log in using the token or SAML assertion passed back to the client using an appropriate client mapper.</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">identity_provider</dt> <dd> <p>The IDP alias of the broker used to perform the login.</p> </dd> <dt class="hdlist1">identity_provider_identity</dt> <dd> <p>The IDP username of the currently authenticated user. Often, but not always, the same as the Keycloak username. For example, Keycloak can link a user john` to a Facebook user <code>john123@gmail.com</code>. In that case, the value of the user session note is <code>john123@gmail.com</code>.</p> </dd> </dl> </div> <div class="paragraph"> <p>You can use a <a href="#_protocol-mappers">Protocol Mapper</a> of type <code>User Session Note</code> to propagate this information to your clients.</p> </div> </div> <div class="sect2"> <h3 id="_identity_broker_first_login"><a class="anchor" href="#_identity_broker_first_login"></a>First login flow</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/identity-broker/first-login-flow.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/identity-broker/first-login-flow.adoc&amp;description=%0A%0AFile:%20server_admin/topics/identity-broker/first-login-flow.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>When users log in through identity brokering, Keycloak imports and links aspects of the user within the realm&#8217;s local database. When Keycloak successfully authenticates users through an external identity provider, two situations can exist:</p> </div> <div class="ulist"> <ul> <li> <p>Keycloak has already imported and linked a user account with the authenticated identity provider account. In this case, Keycloak authenticates as the existing user and redirects back to the application.</p> </li> <li> <p>No account exists for this user in Keycloak. Usually, you register and import a new account into the Keycloak database, but there may be an existing Keycloak account with the same email address. Automatically linking the existing local account to the external identity provider is a potential security hole. You cannot always trust the information you get from the external identity provider.</p> </li> </ul> </div> <div class="paragraph"> <p>Different organizations have different requirements when dealing with some of these situations. With Keycloak, you can use the <code>First Login Flow</code> option in the IDP settings to choose a <a href="#_authentication-flows">workflow</a> for a user logging in from an external IDP for the first time. By default, the <code>First Login Flow</code> option points to the <code>first broker login</code> flow, but you can use your flow or different flows for different identity providers.</p> </div> <div class="paragraph"> <p>The flow is in the Admin Console under the <strong>Authentication</strong> tab. When you choose the <code>First Broker Login</code> flow, you see the authenticators used by default. You can re-configure the existing flow. For example, you can disable some authenticators, mark some of them as <code>required</code>, or configure some authenticators.</p> </div> <div class="paragraph"> <p>You can also create a new authentication flow, write your own Authenticator implementations, and use it in your flow. See <a href="https://www.keycloak.org/docs/26.0.6/server_development/">Server Developer Guide</a> for more information.</p> </div> <div class="sect3"> <h4 id="default-first-login-flow-authenticators"><a class="anchor" href="#default-first-login-flow-authenticators"></a>Default first login flow authenticators</h4> <div class="dlist"> <dl> <dt class="hdlist1">Review Profile</dt> <dd> <div class="ulist"> <ul> <li> <p>This authenticator displays the profile information page, so the users can review their profile that Keycloak retrieves from an identity provider.</p> </li> <li> <p>You can set the <code>Update Profile On First Login</code> option in the <strong>Actions</strong> menu.</p> </li> <li> <p>When <strong>ON</strong>, users are presented with the profile page requesting additional information to federate the user&#8217;s identities.</p> </li> <li> <p>When <strong>missing</strong>, users are presented with the profile page if the identity provider does not provide mandatory information, such as email, first name, or last name.</p> </li> <li> <p>When <strong>OFF</strong>, the profile page does not display unless the user clicks in a later phase on the <code>Review profile info</code> link in the page displayed by the <code>Confirm Link Existing Account</code> authenticator.</p> </li> </ul> </div> </dd> <dt class="hdlist1">Create User If Unique</dt> <dd> <p>This authenticator checks if there is already an existing Keycloak account with the same email or username like the account from the identity provider. If it&#8217;s not, then the authenticator just creates a new local Keycloak account and links it with the identity provider and the whole flow is finished. Otherwise it goes to the next <code>Handle Existing Account</code> subflow. If you always want to ensure that there is no duplicated account, you can mark this authenticator as <code>REQUIRED</code>. In this case, the user will see the error page if there is an existing Keycloak account and the user will need to link the identity provider account through Account management.</p> <div class="ulist"> <ul> <li> <p>This authenticator verifies that there is already a Keycloak account with the same email or username as the identity provider&#8217;s account.</p> </li> <li> <p>If an account does not exist, the authenticator creates a local Keycloak account, links this account with the identity provider, and terminates the flow.</p> </li> <li> <p>If an account exists, the authenticator implements the next <code>Handle Existing Account</code> sub-flow.</p> </li> <li> <p>To ensure there is no duplicated account, you can mark this authenticator as <code>REQUIRED</code>. The user sees the error page if a Keycloak account exists, and users must link their identity provider account through Account management.</p> </li> </ul> </div> </dd> <dt class="hdlist1">Confirm Link Existing Account</dt> <dd> <div class="ulist"> <ul> <li> <p>On the information page, users see a Keycloak account with the same email. Users can review their profile again and use a different email or username. The flow restarts and goes back to the <code>Review Profile</code> authenticator.</p> </li> <li> <p>Alternatively, users can confirm that they want to link their identity provider account with their existing Keycloak account.</p> </li> <li> <p>Disable this authenticator if you do not want users to see this confirmation page and go straight to linking identity provider account by email verification or re-authentication.</p> </li> </ul> </div> </dd> <dt class="hdlist1">Verify Existing Account By Email</dt> <dd> <div class="ulist"> <ul> <li> <p>This authenticator is <code>ALTERNATIVE</code> by default. Keycloak uses this authenticator if the realm has an SMTP setup configured.</p> </li> <li> <p>The authenticator sends an email to users to confirm that they want to link the identity provider with their Keycloak account.</p> </li> <li> <p>Disable this authenticator if you do not want to confirm linking by email, but want users to reauthenticate with their password.</p> </li> </ul> </div> </dd> <dt class="hdlist1">Verify Existing Account By Re-authentication</dt> <dd> <div class="ulist"> <ul> <li> <p>Use this authenticator if the email authenticator is not available. For example, you have not configured SMTP for your realm. This authenticator displays a login screen for users to authenticate to link their Keycloak account with the Identity Provider.</p> </li> <li> <p>Users can also re-authenticate with another identity provider already linked to their Keycloak account.</p> </li> <li> <p>You can force users to use OTP. Otherwise, it is optional and used if you have set OTP for the user account.</p> </li> </ul> </div> </dd> </dl> </div> </div> <div class="sect3"> <h4 id="automatically-link-existing-first-login-flow"><a class="anchor" href="#automatically-link-existing-first-login-flow"></a>Automatically link existing first login flow</h4> <div class="admonitionblock warning"> <table> <tr> <td class="icon"> <i class="fa icon-warning" title="Warning"></i> </td> <td class="content"> <div class="paragraph"> <p>The AutoLink authenticator is dangerous in a generic environment where users can register themselves using arbitrary usernames or email addresses. Do not use this authenticator unless you are carefully curating user registration and assigning usernames and email addresses.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>To configure a first login flow that links users automatically without prompting, create a new flow with the following two authenticators:</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Create User If Unique</dt> <dd> <p>This authenticator ensures Keycloak handles unique users. Set the authenticator requirement to <strong>Alternative</strong>.</p> </dd> <dt class="hdlist1">Automatically Set Existing User</dt> <dd> <p>This authenticator sets an existing user to the authentication context without verification. Set the authenticator requirement to "Alternative".</p> </dd> </dl> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>This setup is the simplest setup available, but it is possible to use other authenticators. For example: * You can add the Review Profile authenticator to the beginning of the flow if you want end users to confirm their profile information. * You can add authentication mechanisms to this flow, forcing a user to verify their credentials. Adding authentication mechanisms requires a complex flow. For example, you can set the "Automatically Set Existing User" and "Password Form" as "Required" in an "Alternative" sub-flow.</p> </div> </td> </tr> </table> </div> </div> <div class="sect3"> <h4 id="_disabling_automatic_user_creation"><a class="anchor" href="#_disabling_automatic_user_creation"></a>Disabling automatic user creation</h4> <div class="paragraph"> <p>The Default first login flow looks up the Keycloak account matching the external identity and offers to link them. If no matching Keycloak account exists, the flow automatically creates one.</p> </div> <div class="paragraph"> <p>This default behavior may be unsuitable for some setups. One example is when you use a read-only LDAP user store, where all users are pre-created. In this case, you must switch off automatic user creation.</p> </div> <div class="paragraph"> <p>To disable user creation:</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Authentication</strong> in the menu.</p> </li> <li> <p>Select <strong>First Broker Login</strong> from the list.</p> </li> <li> <p>Set <strong>Create User If Unique</strong> to <strong>DISABLED</strong>.</p> </li> <li> <p>Set <strong>Confirm Link Existing Account</strong> to <strong>DISABLED</strong>.</p> </li> </ol> </div> <div class="paragraph"> <p>This configuration also implies that Keycloak itself won&#8217;t be able to determine which internal account would correspond to the external identity. Therefore, the <code>Verify Existing Account By Re-authentication</code> authenticator will ask the user to provide both username and password.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> Enabling or disabling user creation by identity provider is completely independent on the realm <a href="#con-user-registration_server_administration_guide">User Registration switch</a>. You can have enabled user-creation by identity provider and at the same time disabled user self-registration in the realm login settings or vice-versa. </td> </tr> </table> </div> </div> <div class="sect3"> <h4 id="_detect_existing_user_first_login_flow"><a class="anchor" href="#_detect_existing_user_first_login_flow"></a>Detect existing user first login flow</h4> <div class="paragraph"> <p>In order to configure a first login flow in which:</p> </div> <div class="ulist"> <ul> <li> <p>only users already registered in this realm can log in,</p> </li> <li> <p>users are automatically linked without being prompted,</p> </li> </ul> </div> <div class="paragraph"> <p>create a new flow with the following two authenticators:</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Detect Existing Broker User</dt> <dd> <p>This authenticator ensures that unique users are handled. Set the authenticator requirement to <code>REQUIRED</code>.</p> </dd> <dt class="hdlist1">Automatically Set Existing User</dt> <dd> <p>Automatically sets an existing user to the authentication context without any verification. Set the authenticator requirement to <code>REQUIRED</code>.</p> </dd> </dl> </div> <div class="paragraph"> <p>You have to set the <code>First Login Flow</code> of the identity provider configuration to that flow. You could set the also set <code>Sync Mode</code> to <code>force</code> if you want to update the user profile (Last Name, First Name&#8230;&#8203;) with the identity provider attributes.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> This flow can be used if you want to delegate the identity to other identity providers (such as GitHub, Facebook &#8230;&#8203;) but you want to manage which users that can log in. </td> </tr> </table> </div> <div class="paragraph"> <p>With this configuration, Keycloak is unable to determine which internal account corresponds to the external identity. The <strong>Verify Existing Account By Re-authentication</strong> authenticator asks the provider for the username and password.</p> </div> </div> <div class="sect3"> <h4 id="_override_existing_broker_link"><a class="anchor" href="#_override_existing_broker_link"></a>Override existing broker link</h4> <div class="paragraph"> <p>When an another account needs to be linked to the same Keycloak account within the same identity provider, you can configure the following authenticator.</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Confirm Override Existing Link</dt> <dd> <p>This authenticator will detect the existing broker link for the user and display a confirmation page to confirm overriding the existing broker link. Set the authenticator requirement to REQUIRED.</p> </dd> </dl> </div> <div class="paragraph"> <p>A typical use of this authenticator is a scenario such as the following:</p> </div> <div class="ulist"> <ul> <li> <p>For example, consider a Keycloak user <code>john</code> with the email <code>john@gmail.com</code>. That user is linked to the identity provider <code>google</code> with the <code>google</code> username <code>john@gmail.com</code> .</p> </li> <li> <p>Then for instance Keycloak user <code>john</code> creates new Google account with email <code>john-new@gmail.com</code></p> </li> <li> <p>Then during login to Keycloak, the user authenticated to the identity provider <code>google</code> with a new username such as <code>john-new@gmail.com</code>, which is not linked to any Keycloak account yet (as Keycloak account <code>john</code> is still linked with the <code>google</code> user <code>john@gmail.com</code>) and hence the first-broker-login flow is triggered.</p> </li> <li> <p>During first-broker-login, the Keycloak user <code>john</code> is authenticated somehow (either by default first-broker-login re-authentication or for instance by authenticator like <code>Detect existing broker user</code>)</p> </li> <li> <p>Now with this authenticator in the authentication flow, it is possible to override the IDP link to the <code>google</code> identity provider of Keycloak user <code>john</code> with the new <code>google</code> link to <code>google</code> user <code>john-new@gmail.com</code> after user <code>john</code> confirms this.</p> </li> </ul> </div> <div class="paragraph"> <p>When creating authentication flows with this authenticator, make sure to add this authenticator once other authenticators that are already established the Keycloak user by other means (either by re-authentication or after <code>Detect existing broker user</code> as mentioned above.</p> </div> </div> </div> <div class="sect2"> <h3 id="retrieving-external-idp-tokens"><a class="anchor" href="#retrieving-external-idp-tokens"></a>Retrieving external IDP tokens</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/identity-broker/tokens.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/identity-broker/tokens.adoc&amp;description=%0A%0AFile:%20server_admin/topics/identity-broker/tokens.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>With Keycloak, you can store tokens and responses from the authentication process with the external IDP using the <code>Store Token</code> configuration option on the IDP&#8217;s settings page.</p> </div> <div class="paragraph"> <p>Application code can retrieve these tokens and responses to import extra user information or to request the external IDP securely. For example, an application can use the Google token to use other Google services and REST APIs. To retrieve a token for a particular identity provider, send a request as follows:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>GET /realms/{realm}/broker/{provider_alias}/token HTTP/1.1 Host: localhost:8080 Authorization: Bearer &lt;KEYCLOAK ACCESS TOKEN&gt;</code></pre> </div> </div> <div class="paragraph"> <p>An application must authenticate with Keycloak and receive an access token. This access token must have the <code>broker</code> client-level role <code>read-token</code> set, so the user must have a role mapping for this role, and the client application must have that role within its scope. In this case, since you are accessing a protected service in Keycloak, send the access token issued by Keycloak during the user authentication. You can assign this role to newly imported users in the broker configuration page by setting the <strong>Stored Tokens Readable</strong> switch to <strong>ON</strong>.</p> </div> <div class="paragraph"> <p>These external tokens can be re-established by logging in again through the provider or using the client-initiated account linking API.</p> </div> </div> <div class="sect2"> <h3 id="identity-broker-logout"><a class="anchor" href="#identity-broker-logout"></a>Identity broker logout</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/identity-broker/logout.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/identity-broker/logout.adoc&amp;description=%0A%0AFile:%20server_admin/topics/identity-broker/logout.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>When logging out, Keycloak sends a request to the external identity provider that is used to log in initially and logs the user out of this identity provider.</p> </div> </div> </div> </div> <div class="sect1"> <h2 id="sso-protocols"><a class="anchor" href="#sso-protocols"></a>SSO protocols</h2> <div class="sectionbody"> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/sso-protocols.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/sso-protocols.adoc&amp;description=%0A%0AFile:%20server_admin/topics/sso-protocols.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>This section discusses authentication protocols, the Keycloak authentication server and how applications, secured by the Keycloak authentication server, interact with these protocols.</p> </div> <div class="sect2"> <h3 id="con-oidc_server_administration_guide"><a class="anchor" href="#con-oidc_server_administration_guide"></a>OpenID Connect</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/sso-protocols/con-oidc.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/sso-protocols/con-oidc.adoc&amp;description=%0A%0AFile:%20server_admin/topics/sso-protocols/con-oidc.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p><a href="https://openid.net/developers/how-connect-works/">OpenID Connect</a> (OIDC) is an authentication protocol that is an extension of <a href="https://datatracker.ietf.org/doc/html/rfc6749">OAuth 2.0</a>.</p> </div> <div class="paragraph"> <p>OAuth 2.0 is a framework for building authorization protocols and is incomplete. OIDC, however, is a full authentication and authorization protocol that uses the <a href="https://jwt.io">Json Web Token</a> (JWT) standards. The JWT standards define an identity token JSON format and methods to digitally sign and encrypt data in a compact and web-friendly way.</p> </div> <div class="paragraph"> <p>In general, OIDC implements two use cases. The first case is an application requesting that a Keycloak server authenticates a user. Upon successful login, the application receives an <em>identity token</em> and an <em>access token</em>. The <em>identity token</em> contains user information including user name, email, and profile information. The realm digitally signs the <em>access token</em> which contains access information (such as user role mappings) that applications use to determine the resources users can access in the application.</p> </div> <div class="paragraph"> <p>The second use case is a client accessing remote services.</p> </div> <div class="ulist"> <ul> <li> <p>The client requests an <em>access token</em> from Keycloak to invoke on remote services on behalf of the user.</p> </li> <li> <p>Keycloak authenticates the user and asks the user for consent to grant access to the requesting client.</p> </li> <li> <p>The client receives the <em>access token</em> which is digitally signed by the realm.</p> </li> <li> <p>The client makes REST requests on remote services using the <em>access token</em>.</p> </li> <li> <p>The remote REST service extracts the <em>access token</em>.</p> </li> <li> <p>The remote REST service verifies the tokens signature.</p> </li> <li> <p>The remote REST service decides, based on access information within the token, to process or reject the request.</p> </li> </ul> </div> <div class="sect3"> <h4 id="con-oidc-auth-flows_server_administration_guide"><a class="anchor" href="#con-oidc-auth-flows_server_administration_guide"></a>OIDC auth flows</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/sso-protocols/con-oidc-auth-flows.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/sso-protocols/con-oidc-auth-flows.adoc&amp;description=%0A%0AFile:%20server_admin/topics/sso-protocols/con-oidc-auth-flows.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>OIDC has several methods, or flows, that clients or applications can use to authenticate users and receive <em>identity</em> and <em>access</em> tokens. The method depends on the type of application or client requesting access.</p> </div> <div class="sect4"> <h5 id="_oidc-auth-flows-authorization"><a class="anchor" href="#_oidc-auth-flows-authorization"></a>Authorization Code Flow</h5> <div class="paragraph"> <p>The Authorization Code Flow is a browser-based protocol and suits authenticating and authorizing browser-based applications. It uses browser redirects to obtain <em>identity</em> and <em>access</em> tokens.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>A user connects to an application using a browser. The application detects the user is not logged into the application.</p> </li> <li> <p>The application redirects the browser to Keycloak for authentication.</p> </li> <li> <p>The application passes a callback URL as a query parameter in the browser redirect. Keycloak uses the parameter upon successful authentication.</p> </li> <li> <p>Keycloak authenticates the user and creates a one-time, short-lived, temporary code.</p> </li> <li> <p>Keycloak redirects to the application using the callback URL and adds the temporary code as a query parameter in the callback URL.</p> </li> <li> <p>The application extracts the temporary code and makes a background REST invocation to Keycloak to exchange the code for an <em>identity</em> and <em>access</em> and <em>refresh</em> token. To prevent replay attacks, the temporary code cannot be used more than once.</p> </li> </ol> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>A system is vulnerable to a stolen token for the lifetime of that token. For security and scalability reasons, access tokens are generally set to expire quickly so subsequent token requests fail. If a token expires, an application can obtain a new access token using the additional <em>refresh</em> token sent by the login protocol.</p> </div> </td> </tr> </table> </div> <div id="_confidential-clients" class="paragraph"> <p><em>Confidential</em> clients provide client secrets when they exchange the temporary codes for tokens. <em>Public</em> clients are not required to provide client secrets. <em>Public</em> clients are secure when HTTPS is strictly enforced and redirect URIs registered for the client are strictly controlled. HTML5/JavaScript clients have to be <em>public</em> clients because there is no way to securely transmit the client secret to HTML5/JavaScript clients. For more details, see the <a href="#assembly-managing-clients_server_administration_guide">Managing Clients</a> chapter.</p> </div> <div class="paragraph"> <p>Keycloak also supports the <a href="https://datatracker.ietf.org/doc/html/rfc7636">Proof Key for Code Exchange</a> specification.</p> </div> </div> <div class="sect4"> <h5 id="_oidc-auth-flows-implicit"><a class="anchor" href="#_oidc-auth-flows-implicit"></a>Implicit Flow</h5> <div class="paragraph"> <p>The Implicit Flow is a browser-based protocol. It is similar to the Authorization Code Flow but with fewer requests and no refresh tokens.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>The possibility exists of <em>access</em> tokens leaking in the browser history when tokens are transmitted via redirect URIs (see below).</p> </div> <div class="paragraph"> <p>Also, this flow does not provide clients with refresh tokens. Therefore, access tokens have to be long-lived or users have to re-authenticate when they expire.</p> </div> <div class="paragraph"> <p>We do not advise using this flow. This flow is supported because it is in the OIDC and OAuth 2.0 specification.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>The protocol works as follows:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>A user connects to an application using a browser. The application detects the user is not logged into the application.</p> </li> <li> <p>The application redirects the browser to Keycloak for authentication.</p> </li> <li> <p>The application passes a callback URL as a query parameter in the browser redirect. Keycloak uses the query parameter upon successful authentication.</p> </li> <li> <p>Keycloak authenticates the user and creates an <em>identity</em> and <em>access</em> token. Keycloak redirects to the application using the callback URL and additionally adds the <em>identity</em> and <em>access</em> tokens as a query parameter in the callback URL.</p> </li> <li> <p>The application extracts the <em>identity</em> and <em>access</em> tokens from the callback URL.</p> </li> </ol> </div> </div> <div class="sect4"> <h5 id="_oidc-auth-flows-direct"><a class="anchor" href="#_oidc-auth-flows-direct"></a>Resource owner password credentials grant (Direct Access Grants)</h5> <div class="paragraph"> <p><em>Direct Access Grants</em> are used by REST clients to obtain tokens on behalf of users. It is a HTTP POST request that contains:</p> </div> <div class="ulist"> <ul> <li> <p>The credentials of the user. The credentials are sent within form parameters.</p> </li> <li> <p>The id of the client.</p> </li> <li> <p>The clients secret (if it is a confidential client).</p> </li> </ul> </div> <div class="paragraph"> <p>The HTTP response contains the <em>identity</em>, <em>access</em>, and <em>refresh</em> tokens.</p> </div> </div> <div class="sect4"> <h5 id="_client_credentials_grant"><a class="anchor" href="#_client_credentials_grant"></a>Client credentials grant</h5> <div class="paragraph"> <p>The <em>Client Credentials Grant</em> creates a token based on the metadata and permissions of a service account associated with the client instead of obtaining a token that works on behalf of an external user. <em>Client Credentials Grants</em> are used by REST clients.</p> </div> <div class="paragraph"> <p>See the <a href="#_service_accounts">Service Accounts</a> chapter for more information.</p> </div> </div> <div class="sect4"> <h5 id="_refresh_token_grant"><a class="anchor" href="#_refresh_token_grant"></a>Refresh token grant</h5> <div class="paragraph"> <p>By default, Keycloak returns refresh tokens in the token responses from most of the flows. Some exceptions are implicit flow or client credentials grant described above.</p> </div> <div class="paragraph"> <p>Refresh token is tied to the user session of the SSO browser session and can be valid for the lifetime of the user session. However, that client should send a refresh-token request at least once per specified interval. Otherwise, the session can be considered "idle" and can expire. See the <a href="#_timeouts">timeouts section</a> for more information.</p> </div> <div class="paragraph"> <p>Keycloak supports <a href="#_offline-access">offline tokens</a>, which can be used typically when client needs to use refresh token even if corresponding browser SSO session is already expired.</p> </div> <div class="sect5"> <h6 id="_refresh_token_rotation"><a class="anchor" href="#_refresh_token_rotation"></a>Refresh token rotation</h6> <div class="paragraph"> <p>It is possible to specify that the refresh token is considered invalid once it is used. This means that client must always save the refresh token from the last refresh response because older refresh tokens, which were already used, would not be considered valid anymore by Keycloak. This is possible to set with the use of <em>Revoke Refresh token</em> option as specified in the <a href="#_timeouts">timeouts section</a>.</p> </div> <div class="paragraph"> <p>Keycloak also supports the situation that no refresh token rotation exists. In this case, a refresh token is returned during login, but subsequent responses from refresh-token requests will not return new refresh tokens. This practice is recommended for instance in the <strong>FAPI 2 draft specification</strong> in the <a href="https://www.keycloak.org/guides#securing-apps">securing apps</a> section. In Keycloak, it is possible to skip refresh token rotation with the use of <a href="#_client_policies">client policies</a>. You can add executor <code>suppress-refresh-token-rotation</code> to some client profile and configure client policy to specify for which clients would be the profile triggered, which means that for those clients the refresh token rotation is going to be skipped.</p> </div> </div> </div> <div class="sect4"> <h5 id="device-authorization-grant"><a class="anchor" href="#device-authorization-grant"></a>Device authorization grant</h5> <div class="paragraph"> <p>This is used by clients running on internet-connected devices that have limited input capabilities or lack a suitable browser. Here&#8217;s a brief summary of the protocol:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>The application requests Keycloak a device code and a user code. Keycloak creates a device code and a user code. Keycloak returns a response including the device code and the user code to the application.</p> </li> <li> <p>The application provides the user with the user code and the verification URI. The user accesses a verification URI to be authenticated by using another browser. You could define a short verification_uri that will be redirected to Keycloak verification URI (/realms/realm_name/device)outside Keycloak - fe in a proxy.</p> </li> <li> <p>The application repeatedly polls Keycloak to find out if the user completed the user authorization. If user authentication is complete, the application exchanges the device code for an <em>identity</em>, <em>access</em> and <em>refresh</em> token.</p> </li> </ol> </div> </div> <div class="sect4"> <h5 id="_client_initiated_backchannel_authentication_grant"><a class="anchor" href="#_client_initiated_backchannel_authentication_grant"></a>Client initiated backchannel authentication grant</h5> <div class="paragraph"> <p>This feature is used by clients who want to initiate the authentication flow by communicating with the OpenID Provider directly without redirect through the user&#8217;s browser like OAuth 2.0&#8217;s authorization code grant. Here&#8217;s a brief summary of the protocol:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>The client requests Keycloak an auth_req_id that identifies the authentication request made by the client. Keycloak creates the auth_req_id.</p> </li> <li> <p>After receiving this auth_req_id, this client repeatedly needs to poll Keycloak to obtain an Access Token, Refresh Token and ID Token from Keycloak in return for the auth_req_id until the user is authenticated.</p> </li> </ol> </div> <div class="paragraph"> <p>An administrator can configure Client Initiated Backchannel Authentication (CIBA) related operations as <code>CIBA Policy</code> per realm.</p> </div> <div class="paragraph"> <p>Also please refer to other places of Keycloak documentation like <strong>Backchannel Authentication Endpoint</strong> and <strong>Client Initiated Backchannel Authentication Grant</strong> in the <a href="https://www.keycloak.org/guides#securing-apps">securing apps</a> section.</p> </div> <div class="sect5"> <h6 id="ciba-policy"><a class="anchor" href="#ciba-policy"></a>CIBA Policy</h6> <div class="paragraph"> <p>An administrator carries out the following operations on the <code>Admin Console</code> :</p> </div> <div class="ulist"> <ul> <li> <p>Open the <code>Authentication &#8594; CIBA Policy</code> tab.</p> </li> <li> <p>Configure items and click <code>Save</code>.</p> </li> </ul> </div> <div class="paragraph"> <p>The configurable items and their description follow.</p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 50%;"> <col style="width: 50%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Configuration</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Backchannel Token Delivery Mode</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Specifying how the CD (Consumption Device) gets the authentication result and related tokens. There are three modes, "poll", "ping" and "push". Keycloak only supports "poll". The default setting is "poll". This configuration is required. For more details, see <a href="https://openid.net/specs/openid-client-initiated-backchannel-authentication-core-1_0.html#rfc.section.5">CIBA Specification</a>.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Expires In</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The expiration time of the "auth_req_id" in seconds since the authentication request was received. The default setting is 120. This configuration is required. For more details, see <a href="https://openid.net/specs/openid-client-initiated-backchannel-authentication-core-1_0.html#successful_authentication_request_acknowdlegment">CIBA Specification</a>.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Interval</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The interval in seconds the CD (Consumption Device) needs to wait for between polling requests to the token endpoint. The default setting is 5. This configuration is optional. For more details, see <a href="https://openid.net/specs/openid-client-initiated-backchannel-authentication-core-1_0.html#successful_authentication_request_acknowdlegment">CIBA Specification</a>.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Authentication Requested User Hint</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The way of identifying the end-user for whom authentication is being requested. The default setting is "login_hint". There are three modes, "login_hint", "login_hint_token" and "id_token_hint". Keycloak only supports "login_hint". This configuration is required. For more details, see <a href="https://openid.net/specs/openid-client-initiated-backchannel-authentication-core-1_0.html#rfc.section.7.1">CIBA Specification</a>.</p></td> </tr> </tbody> </table> </div> <div class="sect5"> <h6 id="provider-setting"><a class="anchor" href="#provider-setting"></a>Provider Setting</h6> <div class="paragraph"> <p>The CIBA grant uses the following two providers.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Authentication Channel Provider : provides the communication between Keycloak and the entity that actually authenticates the user via AD (Authentication Device).</p> </li> <li> <p>User Resolver Provider : get <code>UserModel</code> of Keycloak from the information provided by the client to identify the user.</p> </li> </ol> </div> <div class="paragraph"> <p>Keycloak has both default providers. However, the administrator needs to set up Authentication Channel Provider like this:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">kc.[sh|bat] start --spi-ciba-auth-channel-ciba-http-auth-channel-http-authentication-channel-uri=https://backend.internal.example.com</code></pre> </div> </div> <div class="paragraph"> <p>The configurable items and their description follow.</p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 50%;"> <col style="width: 50%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Configuration</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">http-authentication-channel-uri</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Specifying URI of the entity that actually authenticates the user via AD (Authentication Device).</p></td> </tr> </tbody> </table> </div> <div class="sect5"> <h6 id="authentication-channel-provider"><a class="anchor" href="#authentication-channel-provider"></a>Authentication Channel Provider</h6> <div class="paragraph"> <p>CIBA standard document does not specify how to authenticate the user by AD. Therefore, it might be implemented at the discretion of products. Keycloak delegates this authentication to an external authentication entity. To communicate with the authentication entity, Keycloak provides Authentication Channel Provider.</p> </div> <div class="paragraph"> <p>Its implementation of Keycloak assumes that the authentication entity is under the control of the administrator of Keycloak so that Keycloak trusts the authentication entity. It is not recommended to use the authentication entity that the administrator of Keycloak cannot control.</p> </div> <div class="paragraph"> <p>Authentication Channel Provider is provided as SPI provider so that users of Keycloak can implement their own provider in order to meet their environment. Keycloak provides its default provider called HTTP Authentication Channel Provider that uses HTTP to communicate with the authentication entity.</p> </div> <div class="paragraph"> <p>If a user of Keycloak user want to use the HTTP Authentication Channel Provider, they need to know its contract between Keycloak and the authentication entity consisting of the following two parts.</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Authentication Delegation Request/Response</dt> <dd> <p>Keycloak sends an authentication request to the authentication entity.</p> </dd> <dt class="hdlist1">Authentication Result Notification/ACK</dt> <dd> <p>The authentication entity notifies the result of the authentication to Keycloak.</p> </dd> </dl> </div> <div class="paragraph"> <p>Authentication Delegation Request/Response consists of the following messaging.</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Authentication Delegation Request</dt> <dd> <p>The request is sent from Keycloak to the authentication entity to ask it for user authentication by AD.</p> </dd> </dl> </div> <div class="listingblock"> <div class="content"> <pre>POST [delegation_reception]</pre> </div> </div> <div class="ulist"> <ul> <li> <p>Headers</p> </li> </ul> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 33.3333%;"> <col style="width: 33.3333%;"> <col style="width: 33.3334%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Name</th> <th class="tableblock halign-left valign-top">Value</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Content-Type</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">application/json</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The message body is json formatted.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Authorization</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Bearer [token]</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The [token] is used when the authentication entity notifies the result of the authentication to Keycloak.</p></td> </tr> </tbody> </table> <div class="ulist"> <ul> <li> <p>Parameters</p> </li> </ul> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 33.3333%;"> <col style="width: 33.3333%;"> <col style="width: 33.3334%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Type</th> <th class="tableblock halign-left valign-top">Name</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Path</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">delegation_reception</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The endpoint provided by the authentication entity to receive the delegation request</p></td> </tr> </tbody> </table> <div class="ulist"> <ul> <li> <p>Body</p> </li> </ul> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 50%;"> <col style="width: 50%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Name</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">login_hint</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">It tells the authentication entity who is authenticated by AD.<br> By default, it is the user&#8217;s "username".<br> This field is required and was defined by CIBA standard document.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">scope</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">It tells which scopes the authentication entity gets consent from the authenticated user.<br> This field is required and was defined by CIBA standard document.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">is_consent_required</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">It shows whether the authentication entity needs to get consent from the authenticated user about the scope.<br> This field is required.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">binding_message</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Its value is intended to be shown in both CD and AD&#8217;s UI to make the user recognize that the authentication by AD is triggered by CD.<br> This field is optional and was defined by CIBA standard document.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">acr_values</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">It tells the requesting Authentication Context Class Reference from CD.<br> This field is optional and was defined by CIBA standard document.</p></td> </tr> </tbody> </table> <div class="dlist"> <dl> <dt class="hdlist1">Authentication Delegation Response</dt> <dd> <p>The response is returned from the authentication entity to Keycloak to notify that the authentication entity received the authentication request from Keycloak.</p> <div class="ulist"> <ul> <li> <p>Responses</p> </li> </ul> </div> </dd> </dl> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 50%;"> <col style="width: 50%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">HTTP Status Code</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">201</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">It notifies Keycloak of receiving the authentication delegation request.</p></td> </tr> </tbody> </table> <div class="paragraph"> <p>Authentication Result Notification/ACK consists of the following messaging.</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Authentication Result Notification</dt> <dd> <p>The authentication entity sends the result of the authentication request to Keycloak.</p> </dd> </dl> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>POST /realms/[realm]/protocol/openid-connect/ext/ciba/auth/callback</code></pre> </div> </div> <div class="ulist"> <ul> <li> <p>Headers</p> </li> </ul> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 33.3333%;"> <col style="width: 33.3333%;"> <col style="width: 33.3334%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Name</th> <th class="tableblock halign-left valign-top">Value</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Content-Type</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">application/json</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The message body is json formatted.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Authorization</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Bearer [token]</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The [token] must be the one the authentication entity has received from Keycloak in Authentication Delegation Request.</p></td> </tr> </tbody> </table> <div class="ulist"> <ul> <li> <p>Parameters</p> </li> </ul> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 33.3333%;"> <col style="width: 33.3333%;"> <col style="width: 33.3334%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Type</th> <th class="tableblock halign-left valign-top">Name</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Path</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">realm</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The realm name</p></td> </tr> </tbody> </table> <div class="ulist"> <ul> <li> <p>Body</p> </li> </ul> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 50%;"> <col style="width: 50%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Name</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">status</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">It tells the result of user authentication by AD.<br> It must be one of the following status.<br> SUCCEED : The authentication by AD has been successfully completed.<br> UNAUTHORIZED : The authentication by AD has not been completed.<br> CANCELLED : The authentication by AD has been cancelled by the user.</p></td> </tr> </tbody> </table> <div class="dlist"> <dl> <dt class="hdlist1">Authentication Result ACK</dt> <dd> <p>The response is returned from Keycloak to the authentication entity to notify Keycloak received the result of user authentication by AD from the authentication entity.</p> <div class="ulist"> <ul> <li> <p>Responses</p> </li> </ul> </div> </dd> </dl> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 50%;"> <col style="width: 50%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">HTTP Status Code</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">200</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">It notifies the authentication entity of receiving the notification of the authentication result.</p></td> </tr> </tbody> </table> </div> <div class="sect5"> <h6 id="user-resolver-provider"><a class="anchor" href="#user-resolver-provider"></a>User Resolver Provider</h6> <div class="paragraph"> <p>Even if the same user, its representation may differ in each CD, Keycloak and the authentication entity.</p> </div> <div class="paragraph"> <p>For CD, Keycloak and the authentication entity to recognize the same user, this User Resolver Provider converts their own user representations among them.</p> </div> <div class="paragraph"> <p>User Resolver Provider is provided as SPI provider so that users of Keycloak can implement their own provider in order to meet their environment. Keycloak provides its default provider called Default User Resolver Provider that has the following characteristics.</p> </div> <div class="ulist"> <ul> <li> <p>Only support <code>login_hint</code> parameter and is used as default.</p> </li> <li> <p><code>username</code> of UserModel in Keycloak is used to represent the user on CD, Keycloak and the authentication entity.</p> </li> </ul> </div> </div> </div> </div> <div class="sect3"> <h4 id="_oidc-logout"><a class="anchor" href="#_oidc-logout"></a>OIDC Logout</h4> <div class="paragraph"> <p>OIDC has four specifications relevant to logout mechanisms:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p><a href="https://openid.net/specs/openid-connect-session-1_0.html">Session Management</a></p> </li> <li> <p><a href="https://openid.net/specs/openid-connect-rpinitiated-1_0.html">RP-Initiated Logout</a></p> </li> <li> <p><a href="https://openid.net/specs/openid-connect-frontchannel-1_0.html">Front-Channel Logout</a></p> </li> <li> <p><a href="https://openid.net/specs/openid-connect-backchannel-1_0.html">Back-Channel Logout</a></p> </li> </ol> </div> <div class="paragraph"> <p>Again since all of this is described in the OIDC specification we will only give a brief overview here.</p> </div> <div class="sect4"> <h5 id="session-management"><a class="anchor" href="#session-management"></a>Session Management</h5> <div class="paragraph"> <p>This is a browser-based logout. The application obtains session status information from Keycloak at a regular basis. When the session is terminated at Keycloak the application will notice and trigger its own logout.</p> </div> </div> <div class="sect4"> <h5 id="rp-initiated-logout"><a class="anchor" href="#rp-initiated-logout"></a>RP-Initiated Logout</h5> <div class="paragraph"> <p>This is also a browser-based logout where the logout starts by redirecting the user to a specific endpoint at Keycloak. This redirect usually happens when the user clicks the <code>Log Out</code> link on the page of some application, which previously used Keycloak to authenticate the user.</p> </div> <div class="paragraph"> <p>Once the user is redirected to the logout endpoint, Keycloak is going to send logout requests to clients to let them invalidate their local user sessions, and potentially redirect the user to some URL once the logout process is finished. The user might be optionally requested to confirm the logout in case the <code>id_token_hint</code> parameter was not used. After logout, the user is automatically redirected to the specified <code>post_logout_redirect_uri</code> as long as it is provided as a parameter. Note that you need to include either the <code>client_id</code> or <code>id_token_hint</code> parameter in case the <code>post_logout_redirect_uri</code> is included. Also the <code>post_logout_redirect_uri</code> parameter needs to match one of the <code>Valid Post Logout Redirect URIs</code> specified in the client configuration.</p> </div> <div class="paragraph"> <p>Depending on the client configuration, logout requests can be sent to clients through the front-channel or through the back-channel. For the frontend browser clients, which rely on the Session Management described in the previous section, Keycloak does not need to send any logout requests to them; these clients automatically detect that SSO session in the browser is logged out.</p> </div> </div> <div class="sect4"> <h5 id="front-channel-logout"><a class="anchor" href="#front-channel-logout"></a>Front-channel Logout</h5> <div class="paragraph"> <p>To configure clients to receive logout requests through the front-channel, look at the <a href="#_front-channel-logout">Front-Channel Logout</a> client setting. When using this method, consider the following:</p> </div> <div class="ulist"> <ul> <li> <p>Logout requests sent by Keycloak to clients rely on the browser and on embedded <code>iframes</code> that are rendered for the logout page.</p> </li> <li> <p>By being based on <code>iframes</code>, front-channel logout might be impacted by Content Security Policies (CSP) and logout requests might be blocked.</p> </li> <li> <p>If the user closes the browser prior to rendering the logout page or before logout requests are actually sent to clients, their sessions at the client might not be invalidated.</p> </li> </ul> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>Consider using Back-Channel Logout as it provides a more reliable and secure approach to log out users and terminate their sessions on the clients.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>If the client is not enabled with front-channel logout, then Keycloak is going to try first to send logout requests through the back-channel using the <a href="#_back-channel-logout-url">Back-Channel Logout URL</a>. If not defined, the server is going to fall back to using the <a href="#_admin-url">Admin URL</a>.</p> </div> </div> <div class="sect4"> <h5 id="backchannel-logout"><a class="anchor" href="#backchannel-logout"></a>Backchannel Logout</h5> <div class="paragraph"> <p>This is a non-browser-based logout that uses direct backchannel communication between Keycloak and clients. Keycloak sends a HTTP POST request containing a logout token to all clients logged into Keycloak. These requests are sent to a registered backchannel logout URLs at Keycloak and are supposed to trigger a logout at client side.</p> </div> </div> </div> <div class="sect3"> <h4 id="con-server-oidc-uri-endpoints_server_administration_guide"><a class="anchor" href="#con-server-oidc-uri-endpoints_server_administration_guide"></a>Keycloak server OIDC URI endpoints</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/sso-protocols/con-server-oidc-uri-endpoints.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/sso-protocols/con-server-oidc-uri-endpoints.adoc&amp;description=%0A%0AFile:%20server_admin/topics/sso-protocols/con-server-oidc-uri-endpoints.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>The following is a list of OIDC endpoints that Keycloak publishes. These endpoints can be used when a non-Keycloak client adapter uses OIDC to communicate with the authentication server. They are all relative URLs. The root of the URL consists of the HTTP(S) protocol, hostname, and optionally the path: For example</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>https://localhost:8080</code></pre> </div> </div> <div class="dlist"> <dl> <dt class="hdlist1">/realms/{realm-name}/protocol/openid-connect/auth</dt> <dd> <p>Used for obtaining a temporary code in the Authorization Code Flow or obtaining tokens using the Implicit Flow, Direct Grants, or Client Grants.</p> </dd> <dt class="hdlist1">/realms/{realm-name}/protocol/openid-connect/token</dt> <dd> <p>Used by the Authorization Code Flow to convert a temporary code into a token.</p> </dd> <dt class="hdlist1">/realms/{realm-name}/protocol/openid-connect/logout</dt> <dd> <p>Used for performing logouts.</p> </dd> <dt class="hdlist1">/realms/{realm-name}/protocol/openid-connect/userinfo</dt> <dd> <p>Used for the User Info service described in the OIDC specification.</p> </dd> <dt class="hdlist1">/realms/{realm-name}/protocol/openid-connect/revoke</dt> <dd> <p>Used for OAuth 2.0 Token Revocation described in <a href="https://datatracker.ietf.org/doc/html/rfc7009">RFC7009</a>.</p> </dd> <dt class="hdlist1">/realms/{realm-name}/protocol/openid-connect/certs</dt> <dd> <p>Used for the JSON Web Key Set (JWKS) containing the public keys used to verify any JSON Web Token (jwks_uri)</p> </dd> <dt class="hdlist1">/realms/{realm-name}/protocol/openid-connect/auth/device</dt> <dd> <p>Used for Device Authorization Grant to obtain a device code and a user code.</p> </dd> <dt class="hdlist1">/realms/{realm-name}/protocol/openid-connect/ext/ciba/auth</dt> <dd> <p>This is the URL endpoint for Client Initiated Backchannel Authentication Grant to obtain an auth_req_id that identifies the authentication request made by the client.</p> </dd> <dt class="hdlist1">/realms/{realm-name}/protocol/openid-connect/logout/backchannel-logout</dt> <dd> <p>This is the URL endpoint for performing backchannel logouts described in the OIDC specification.</p> </dd> </dl> </div> <div class="paragraph"> <p>In all of these, replace {realm-name} with the name of the realm.</p> </div> </div> </div> <div class="sect2"> <h3 id="_saml"><a class="anchor" href="#_saml"></a>SAML</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/sso-protocols/con-saml.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/sso-protocols/con-saml.adoc&amp;description=%0A%0AFile:%20server_admin/topics/sso-protocols/con-saml.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p><a href="https://saml.xml.org/saml-specifications">SAML 2.0</a> is a similar specification to OIDC but more mature. It is descended from SOAP and web service messaging specifications so is generally more verbose than OIDC. SAML 2.0 is an authentication protocol that exchanges XML documents between authentication servers and applications. XML signatures and encryption are used to verify requests and responses.</p> </div> <div class="paragraph"> <p>In general, SAML implements two use cases.</p> </div> <div class="paragraph"> <p>The first use case is an application that requests the Keycloak server authenticates a user. Upon successful login, the application will receive an XML document. This document contains an SAML assertion that specifies user attributes. The realm digitally signs the document which contains access information (such as user role mappings) that applications use to determine the resources users are allowed to access in the application.</p> </div> <div class="paragraph"> <p>The second use case is a client accessing remote services. The client requests a SAML assertion from Keycloak to invoke on remote services on behalf of the user.</p> </div> <div class="sect3"> <h4 id="con-saml-bindings_server_administration_guide"><a class="anchor" href="#con-saml-bindings_server_administration_guide"></a>SAML bindings</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/sso-protocols/con-saml-bindings.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/sso-protocols/con-saml-bindings.adoc&amp;description=%0A%0AFile:%20server_admin/topics/sso-protocols/con-saml-bindings.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>Keycloak supports three binding types.</p> </div> <div class="sect4"> <h5 id="redirect-binding"><a class="anchor" href="#redirect-binding"></a>Redirect binding</h5> <div class="paragraph"> <p><em>Redirect</em> binding uses a series of browser redirect URIs to exchange information.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>A user connects to an application using a browser. The application detects the user is not authenticated.</p> </li> <li> <p>The application generates an XML authentication request document and encodes it as a query parameter in a URI. The URI is used to redirect to the Keycloak server. Depending on your settings, the application can also digitally sign the XML document and include the signature as a query parameter in the redirect URI to Keycloak. This signature is used to validate the client that sends the request.</p> </li> <li> <p>The browser redirects to Keycloak.</p> </li> <li> <p>The server extracts the XML auth request document and verifies the digital signature, if required.</p> </li> <li> <p>The user enters their authentication credentials.</p> </li> <li> <p>After authentication, the server generates an XML authentication response document. The document contains a SAML assertion that holds metadata about the user, including name, address, email, and any role mappings the user has. The document is usually digitally signed using XML signatures, and may also be encrypted.</p> </li> <li> <p>The XML authentication response document is encoded as a query parameter in a redirect URI. The URI brings the browser back to the application. The digital signature is also included as a query parameter.</p> </li> <li> <p>The application receives the redirect URI and extracts the XML document.</p> </li> <li> <p>The application verifies the realm&#8217;s signature to ensure it is receiving a valid authentication response. The information inside the SAML assertion is used to make access decisions or display user data.</p> </li> </ol> </div> </div> <div class="sect4"> <h5 id="post-binding"><a class="anchor" href="#post-binding"></a>POST binding</h5> <div class="paragraph"> <p><em>POST</em> binding is similar to <em>Redirect</em> binding but <em>POST</em> binding exchanges XML documents using POST requests instead of using GET requests. <em>POST</em> Binding uses JavaScript to make the browser send a POST request to the Keycloak server or application when exchanging documents. HTTP responds with an HTML document which contains an HTML form containing embedded JavaScript. When the page loads, the JavaScript automatically invokes the form.</p> </div> <div class="paragraph"> <p><em>POST</em> binding is recommended due to two restrictions:</p> </div> <div class="ulist"> <ul> <li> <p><strong>Security</strong>&#8201;&#8212;&#8201;With <em>Redirect</em> binding, the SAML response is part of the URL. It is less secure as it is possible to capture the response in logs.</p> </li> <li> <p><strong>Size</strong>&#8201;&#8212;&#8201;Sending the document in the HTTP payload provides more scope for large amounts of data than in a limited URL.</p> </li> </ul> </div> </div> <div class="sect4"> <h5 id="ecp"><a class="anchor" href="#ecp"></a>ECP</h5> <div class="paragraph"> <p>Enhanced Client or Proxy (ECP) is a SAML v.2.0 profile which allows the exchange of SAML attributes outside the context of a web browser. It is often used by REST or SOAP-based clients.</p> </div> </div> </div> <div class="sect3"> <h4 id="keycloak-server-saml-uri-endpoints"><a class="anchor" href="#keycloak-server-saml-uri-endpoints"></a>Keycloak Server SAML URI Endpoints</h4> <div class="paragraph"> <p>Keycloak has one endpoint for all SAML requests.</p> </div> <div class="paragraph"> <p><code>http(s)://authserver.host/realms/{realm-name}/protocol/saml</code></p> </div> <div class="paragraph"> <p>All bindings use this endpoint.</p> </div> </div> </div> <div class="sect2"> <h3 id="ref-saml-vs-oidc_server_administration_guide"><a class="anchor" href="#ref-saml-vs-oidc_server_administration_guide"></a>OpenID Connect compared to SAML</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/sso-protocols/ref-saml-vs-oidc.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/sso-protocols/ref-saml-vs-oidc.adoc&amp;description=%0A%0AFile:%20server_admin/topics/sso-protocols/ref-saml-vs-oidc.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>The following lists a number of factors to consider when choosing a protocol.</p> </div> <div class="paragraph"> <p>For most purposes, Keycloak recommends using OIDC.</p> </div> <div class="paragraph"> <p><strong>OIDC</strong></p> </div> <div class="ulist"> <ul> <li> <p>OIDC is specifically designed to work with the web.</p> </li> <li> <p>OIDC is suited for HTML5/JavaScript applications because it is easier to implement on the client side than SAML.</p> </li> <li> <p>OIDC tokens are in the JSON format which makes them easier for Javascript to consume.</p> </li> <li> <p>OIDC has features to make security implementation easier. For example, see the <a href="https://openid.net/specs/openid-connect-session-1_0.html#ChangeNotification">iframe trick</a> that the specification uses to determine a users login status.</p> </li> </ul> </div> <div class="paragraph"> <p><strong>SAML</strong></p> </div> <div class="ulist"> <ul> <li> <p>SAML is designed as a layer to work on top of the web.</p> </li> <li> <p>SAML can be more verbose than OIDC.</p> </li> <li> <p>Users pick SAML over OIDC because there is a perception that it is mature.</p> </li> <li> <p>Users pick SAML over OIDC existing applications that are secured with it.</p> </li> </ul> </div> </div> <div class="sect2"> <h3 id="_docker"><a class="anchor" href="#_docker"></a>Docker registry v2 authentication</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/sso-protocols/con-sso-docker.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/sso-protocols/con-sso-docker.adoc&amp;description=%0A%0AFile:%20server_admin/topics/sso-protocols/con-sso-docker.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>Docker authentication is disabled by default. To enable docker authentication, see the <a href="https://www.keycloak.org/server/features">Enabling and disabling features</a> guide.</p> </div> </td> </tr> </table> </div> <div class="paragraph _abstract"> <p><a href="https://distribution.github.io/distribution/spec/auth/">Docker Registry V2 Authentication</a> is a protocol, similar to OIDC, that authenticates users against Docker registries. Keycloak&#8217;s implementation of this protocol lets Docker clients use a Keycloak authentication server authenticate against a registry. This protocol uses standard token and signature mechanisms but it does deviate from a true OIDC implementation. It deviates by using a very specific JSON format for requests and responses as well as mapping repository names and permissions to the OAuth scope mechanism.</p> </div> <div class="sect3"> <h4 id="docker-authentication-flow"><a class="anchor" href="#docker-authentication-flow"></a>Docker authentication flow</h4> <div class="paragraph"> <p>The authentication flow is described in the <a href="https://distribution.github.io/distribution/spec/auth/token/">Docker API documentation</a>. The following is a summary from the perspective of the Keycloak authentication server:</p> </div> <div class="ulist"> <ul> <li> <p>Perform a <code>docker login</code>.</p> </li> <li> <p>The Docker client requests a resource from the Docker registry. If the resource is protected and no authentication token is in the request, the Docker registry server responds with a 401 HTTP message with some information on the permissions that are required and the location of the authorization server.</p> </li> <li> <p>The Docker client constructs an authentication request based on the 401 HTTP message from the Docker registry. The client uses the locally cached credentials (from the <code>docker login</code> command) as part of the <a href="https://datatracker.ietf.org/doc/html/rfc2617">HTTP Basic Authentication</a> request to the Keycloak authentication server.</p> </li> <li> <p>The Keycloak authentication server attempts to authenticate the user and return a JSON body containing an OAuth-style Bearer token.</p> </li> <li> <p>The Docker client receives a bearer token from the JSON response and uses it in the authorization header to request the protected resource.</p> </li> <li> <p>The Docker registry receives the new request for the protected resource with the token from the Keycloak server. The registry validates the token and grants access to the requested resource (if appropriate).</p> </li> </ul> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> Keycloak does not create a browser SSO session after successful authentication with the Docker protocol. The browser SSO session does not use the Docker protocol as it cannot refresh tokens or obtain the status of a token or session from the Keycloak server; therefore a browser SSO session is not necessary. For more details, see the <a href="#_transient-session">transient session</a> section. </td> </tr> </table> </div> </div> <div class="sect3"> <h4 id="keycloak-docker-registry-v2-authentication-server-uri-endpoints"><a class="anchor" href="#keycloak-docker-registry-v2-authentication-server-uri-endpoints"></a>Keycloak Docker Registry v2 Authentication Server URI Endpoints</h4> <div class="paragraph"> <p>Keycloak has one endpoint for all Docker auth v2 requests.</p> </div> <div class="paragraph"> <p><code>http(s)://authserver.host/realms/{realm-name}/protocol/docker-v2/auth</code></p> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="_admin_permissions"><a class="anchor" href="#_admin_permissions"></a>Controlling access to the Admin Console</h2> <div class="sectionbody"> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/admin-console-permissions.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/admin-console-permissions.adoc&amp;description=%0A%0AFile:%20server_admin/topics/admin-console-permissions.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Each realm created on the Keycloak has a dedicated Admin Console from which that realm can be managed. The <code>master</code> realm is a special realm that allows admins to manage more than one realm on the system. You can also define fine-grained access to users in different realms to manage the server. This chapter goes over all the scenarios for this.</p> </div> <div class="sect2"> <h3 id="master-realm-access-control"><a class="anchor" href="#master-realm-access-control"></a>Master realm access control</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/admin-console-permissions/master-realm.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/admin-console-permissions/master-realm.adoc&amp;description=%0A%0AFile:%20server_admin/topics/admin-console-permissions/master-realm.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>The <code>master</code> realm in Keycloak is a special realm and treated differently than other realms. Users in the Keycloak <code>master</code> realm can be granted permission to manage zero or more realms that are deployed on the Keycloak server. When a realm is created, Keycloak automatically creates various roles that grant fine-grain permissions to access that new realm. Access to The Admin Console and Admin REST endpoints can be controlled by mapping these roles to users in the <code>master</code> realm. It&#8217;s possible to create multiple superusers, as well as users that can only manage specific realms.</p> </div> <div class="sect3"> <h4 id="global-roles"><a class="anchor" href="#global-roles"></a>Global roles</h4> <div class="paragraph"> <p>There are two realm-level roles in the <code>master</code> realm. These are:</p> </div> <div class="ulist"> <ul> <li> <p>admin</p> </li> <li> <p>create-realm</p> </li> </ul> </div> <div class="paragraph"> <p>Users with the <code>admin</code> role are superusers and have full access to manage any realm on the server. Users with the <code>create-realm</code> role are allowed to create new realms. They will be granted full access to any new realm they create.</p> </div> </div> <div class="sect3"> <h4 id="realm-specific-roles"><a class="anchor" href="#realm-specific-roles"></a>Realm specific roles</h4> <div class="paragraph"> <p>Admin users within the <code>master</code> realm can be granted management privileges to one or more other realms in the system. Each realm in Keycloak is represented by a client in the <code>master</code> realm. The name of the client is <code>&lt;realm name&gt;-realm</code>. These clients each have client-level roles defined which define varying level of access to manage an individual realm.</p> </div> <div class="paragraph"> <p>The roles available are:</p> </div> <div class="ulist"> <ul> <li> <p>view-realm</p> </li> <li> <p>view-users</p> </li> <li> <p>view-clients</p> </li> <li> <p>view-events</p> </li> <li> <p>manage-realm</p> </li> <li> <p>manage-users</p> </li> <li> <p>create-client</p> </li> <li> <p>manage-clients</p> </li> <li> <p>manage-events</p> </li> <li> <p>view-identity-providers</p> </li> <li> <p>manage-identity-providers</p> </li> <li> <p>impersonation</p> </li> </ul> </div> <div class="paragraph"> <p>Assign the roles you want to your users and they will only be able to use that specific part of the administration console.</p> </div> <div class="admonitionblock important"> <table> <tr> <td class="icon"> <i class="fa icon-important" title="Important"></i> </td> <td class="content"> Admins with the <code>manage-users</code> role will only be able to assign admin roles to users that they themselves have. So, if an admin has the <code>manage-users</code> role but doesn&#8217;t have the <code>manage-realm</code> role, they will not be able to assign this role. </td> </tr> </table> </div> </div> </div> <div class="sect2"> <h3 id="_per_realm_admin_permissions"><a class="anchor" href="#_per_realm_admin_permissions"></a>Dedicated realm admin consoles</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/admin-console-permissions/per-realm.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/admin-console-permissions/per-realm.adoc&amp;description=%0A%0AFile:%20server_admin/topics/admin-console-permissions/per-realm.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Each realm has a dedicated Admin Console that can be accessed by going to the url <code>/admin/{realm-name}/console</code>. Users within that realm can be granted realm management permissions by assigning specific user role mappings.</p> </div> <div class="paragraph"> <p>Each realm has a built-in client called <code>realm-management</code>. You can view this client by going to the <code>Clients</code> left menu item of your realm. This client defines client-level roles that specify permissions that can be granted to manage the realm.</p> </div> <div class="ulist"> <ul> <li> <p>view-realm</p> </li> <li> <p>view-users</p> </li> <li> <p>view-clients</p> </li> <li> <p>view-events</p> </li> <li> <p>manage-realm</p> </li> <li> <p>manage-users</p> </li> <li> <p>create-client</p> </li> <li> <p>manage-clients</p> </li> <li> <p>manage-events</p> </li> <li> <p>view-identity-providers</p> </li> <li> <p>manage-identity-providers</p> </li> <li> <p>impersonation</p> </li> </ul> </div> <div class="paragraph"> <p>Assign the roles you want to your users and they will only be able to use that specific part of the administration console.</p> </div> </div> <div class="sect2"> <h3 id="_fine_grain_permissions"><a class="anchor" href="#_fine_grain_permissions"></a>Fine grain admin permissions</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/admin-console-permissions/fine-grain.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/admin-console-permissions/fine-grain.adoc&amp;description=%0A%0AFile:%20server_admin/topics/admin-console-permissions/fine-grain.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>Fine Grain Admin Permissions is <strong>Preview</strong> and is not fully supported. This feature is disabled by default.</p> </div> <div class="paragraph"> <p>To enable start the server with <code>--features=preview</code> or <code>--features=admin-fine-grained-authz</code></p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>Sometimes roles like <code>manage-realm</code> or <code>manage-users</code> are too coarse grain and you want to create restricted admin accounts that have more fine grain permissions. Keycloak allows you to define and assign restricted access policies for managing a realm. Things like:</p> </div> <div class="ulist"> <ul> <li> <p>Managing one specific client</p> </li> <li> <p>Managing users that belong to a specific group</p> </li> <li> <p>Managing membership of a group</p> </li> <li> <p>Limited user management.</p> </li> <li> <p>Fine grain impersonation control</p> </li> <li> <p>Being able to assign a specific restricted set of roles to users.</p> </li> <li> <p>Being able to assign a specific restricted set of roles to a composite role.</p> </li> <li> <p>Being able to assign a specific restricted set of roles to a client&#8217;s scope.</p> </li> <li> <p>New general policies for viewing and managing users, groups, roles, and clients.</p> </li> </ul> </div> <div class="paragraph"> <p>There are some important things to note about fine grain admin permissions:</p> </div> <div class="ulist"> <ul> <li> <p>Fine grain admin permissions were implemented on top of <a href="https://www.keycloak.org/docs/26.0.6/authorization_services/">Authorization Services</a>. It is highly recommended that you read up on those features before diving into fine grain permissions.</p> </li> <li> <p>Fine grain permissions are only available within <a href="#_per_realm_admin_permissions">dedicated admin consoles</a> and admins defined within those realms. You cannot define cross-realm fine grain permissions.</p> </li> <li> <p>Fine grain permissions are used to grant additional permissions. You cannot override the default behavior of the built-in admin roles.</p> </li> </ul> </div> <div class="sect3"> <h4 id="managing-one-specific-client"><a class="anchor" href="#managing-one-specific-client"></a>Managing one specific client</h4> <div class="paragraph"> <p>Let&#8217;s look first at allowing an admin to manage one client and one client only. In our example, we have a realm called <code>test</code> and a client called <code>sales-application</code>. In the realm <code>test</code> we will give a user in that realm permission to only manage that application.</p> </div> <div class="admonitionblock important"> <table> <tr> <td class="icon"> <i class="fa icon-important" title="Important"></i> </td> <td class="content"> You cannot do cross realm fine grain permissions. Admins in the <code>master</code> realm are limited to the predefined admin roles defined in previous chapters. </td> </tr> </table> </div> <div class="sect4"> <h5 id="permission-setup"><a class="anchor" href="#permission-setup"></a>Permission setup</h5> <div class="paragraph"> <p>The first thing we must do is login to the Admin Console so we can set up permissions for that client. We navigate to the management section of the client, we want to define fine-grain permissions for.</p> </div> <div class="paragraph"> <div class="title">Client management</div> <p><span class="image"><img src="./images/fine-grain-client.png" alt="Fine grain client"></span></p> </div> <div class="paragraph"> <p>You should see a tab menu item called <code>Permissions</code>. Click on that tab.</p> </div> <div class="paragraph"> <div class="title">Client permissions tab</div> <p><span class="image"><img src="./images/fine-grain-client-permissions-tab-off.png" alt="Fine grain client permissions tab"></span></p> </div> <div class="paragraph"> <p>By default, each client is not enabled to do fine grain permissions. So turn the <code>Permissions Enabled</code> switch to on to initialize permissions.</p> </div> <div class="admonitionblock important"> <table> <tr> <td class="icon"> <i class="fa icon-important" title="Important"></i> </td> <td class="content"> If you turn the <code>Permissions Enabled</code> switch to off, it will delete any and all permissions you have defined for this client. </td> </tr> </table> </div> <div class="paragraph"> <div class="title">Client permissions tab</div> <p><span class="image"><img src="./images/fine-grain-client-permissions-tab-on.png" alt="Fine grain permission tab"></span></p> </div> <div class="paragraph"> <p>When you switch <code>Permissions Enabled</code> to on, it initializes various permission objects behind the scenes using <a href="https://www.keycloak.org/docs/26.0.6/authorization_services/">Authorization Services</a>. For this example, we&#8217;re interested in the <code>manage</code> permission for the client. Clicking on that will redirect you to the permission that handles the <code>manage</code> permission for the client. All authorization objects are contained in the <code>realm-management</code> client&#8217;s <code>Authorization</code> tab.</p> </div> <div class="paragraph"> <div class="title">Client manage permission</div> <p><span class="image"><img src="./images/fine-grain-client-manage-permissions.png" alt="Fine grain client manage permission"></span></p> </div> <div class="paragraph"> <p>When first initialized the <code>manage</code> permission does not have any policies associated with it. You will need to create one by going to the policy tab. To get there fast, click on the <code>Client details</code> link shown in the above image. Then click on the policies tab.</p> </div> <div class="paragraph"> <p>On this page, look for the <code>Create client policy</code> button, which you can use to define many policies. You can define a policy that is associated with a role or a group or even define rules in JavaScript. For this simple example, we are going to create a <code>User Policy</code>.</p> </div> <div class="paragraph"> <div class="title">User policy</div> <p><span class="image"><img src="./images/fine-grain-client-user-policy.png" alt="Fine grain client user policy"></span></p> </div> <div class="paragraph"> <p>This policy will match a hard-coded user in the user database. In this case, it is the <code>sales-admin</code> user. We must then go back to the <code>sales-application</code> client&#8217;s <code>manage</code> permission page and assign the policy to the permission object.</p> </div> <div class="paragraph"> <div class="title">Assign user policy</div> <p><span class="image"><img src="./images/fine-grain-client-assign-user-policy.png" alt="Fine grain client assign user policy"></span></p> </div> <div class="paragraph"> <p>The <code>sales-admin</code> user now has permission to manage the <code>sales-application</code> client.</p> </div> <div class="paragraph"> <p>There is one more thing we have to do. Go to <code>Users</code>, select the <code>sales-admin</code> user, then go to the <code>Role Mappings</code> tab and assign the <code>query-clients</code> role to the user.</p> </div> <div class="paragraph"> <div class="title">Assign query-clients</div> <p><span class="image"><img src="./images/fine-grain-assign-query-clients.png" alt="Fine grain assign query clients"></span></p> </div> <div class="paragraph"> <p>Why do you have to do this? This role tells the Admin Console what menu items to render when the <code>sales-admin</code> visits the Admin Console. The <code>query-clients</code> role tells the Admin Console that it should render client menus for the <code>sales-admin</code> user.</p> </div> <div class="paragraph"> <p>IMPORTANT If you do not set the <code>query-clients</code> role, restricted admins like <code>sales-admin</code> will not see any menu options when they log into the Admin Console</p> </div> </div> <div class="sect4"> <h5 id="testing-it-out"><a class="anchor" href="#testing-it-out"></a>Testing it out</h5> <div class="paragraph"> <p>Next, we log out of the master realm and re-login to the <a href="#_per_realm_admin_permissions">dedicated admin console</a> for the <code>test</code> realm using the <code>sales-admin</code> as a username. This is located under <code>/admin/test/console</code>.</p> </div> <div class="paragraph"> <div class="title">Sales admin login</div> <p><span class="image"><img src="./images/fine-grain-sales-admin-login.png" alt="Fine grain sales admin login"></span></p> </div> <div class="paragraph"> <p>This admin is now able to manage this one client.</p> </div> </div> </div> <div class="sect3"> <h4 id="restrict-user-role-mapping"><a class="anchor" href="#restrict-user-role-mapping"></a>Restrict user role mapping</h4> <div class="paragraph"> <p>Another thing you might want to do is to restrict the set of roles an admin is allowed to assign to a user. Continuing our last example, let&#8217;s expand the permission set of the 'sales-admin' user so that he can also control which users are allowed to access this application. Through fine grain permissions, we can enable it so that the <code>sales-admin</code> can only assign roles that grant specific access to the <code>sales-application</code>. We can also restrict it so that the admin can only map roles and not perform any other types of user administration.</p> </div> <div class="paragraph"> <p>The <code>sales-application</code> has defined three different client roles.</p> </div> <div class="paragraph"> <div class="title">Sales application roles</div> <p><span class="image"><img src="./images/fine-grain-sales-application-roles.png" alt="Fine grain sales application roles"></span></p> </div> <div class="paragraph"> <p>We want the <code>sales-admin</code> user to be able to map these roles to any user in the system. The first step to do this is to allow the role to be mapped by the admin. If we click on the <code>viewLeads</code> role, you&#8217;ll see that there is a <code>Permissions</code> tab for this role.</p> </div> <div class="paragraph"> <div class="title">View leads role permission tab</div> <p><span class="image"><img src="./images/fine-grain-view-leads-role-tab.png" alt="Fine grain view leads role"></span></p> </div> <div class="paragraph"> <p>If we click on that tab and turn the <code>Permissions Enabled</code> on, you&#8217;ll see that there are a number of actions we can apply policies to.</p> </div> <div class="paragraph"> <div class="title">View leads permissions</div> <p><span class="image"><img src="./images/fine-grain-view-leads-permissions.png" alt="Fine grain view leads permissions"></span></p> </div> <div class="paragraph"> <p>The one we are interested in is <code>map-role</code>. Click on this permission and add the same User Policy that was created in the earlier example.</p> </div> <div class="paragraph"> <div class="title">Map-roles permission</div> <p><span class="image"><img src="./images/fine-grain-map-roles-permission.png" alt="Fine grain map roles permission"></span></p> </div> <div class="paragraph"> <p>What we&#8217;ve done is say that the <code>sales-admin</code> can map the <code>viewLeads</code> role. What we have not done is specify which users the admin is allowed to map this role too. To do that we must go to the <code>Users</code> section of the admin console for this realm. Clicking on the <code>Users</code> left menu item brings us to the users interface of the realm. You should see a <code>Permissions</code> tab. Click on that and enable it.</p> </div> <div class="paragraph"> <div class="title">Users permissions</div> <p><span class="image"><img src="./images/fine-grain-users-permissions.png" alt="Fine grain user permissions"></span></p> </div> <div class="paragraph"> <p>The permission we are interested in is <code>map-roles</code>. This is a restrictive policy in that it only allows admins the ability to map roles to a user. If we click on the <code>map-roles</code> permission and again add the User Policy we created for this, our <code>sales-admin</code> will be able to map roles to any user.</p> </div> <div class="paragraph"> <p>The last thing we have to do is add the <code>view-users</code> role to the <code>sales-admin</code>. This will allow the admin to view users in the realm he wants to add the <code>sales-application</code> roles to.</p> </div> <div class="paragraph"> <div class="title">Add view-users</div> <p><span class="image"><img src="./images/fine-grain-add-view-users.png" alt="Fine grain add view users"></span></p> </div> <div class="sect4"> <h5 id="testing-it-out-2"><a class="anchor" href="#testing-it-out-2"></a>Testing it out</h5> <div class="paragraph"> <p>Next, we log out of the master realm and re-login to the <a href="#_per_realm_admin_permissions">dedicated admin console</a> for the <code>test</code> realm using the <code>sales-admin</code> as a username. This is located under <code>/admin/test/console</code>.</p> </div> <div class="paragraph"> <p>You will see that now the <code>sales-admin</code> can view users in the system. If you select one of the users you&#8217;ll see that each user detail page is read only, except for the <code>Role Mappings</code> tab. Going to this tab you&#8217;ll find that there are no <code>Available</code> roles for the admin to map to the user except when we browse the <code>sales-application</code> roles.</p> </div> <div class="paragraph"> <div class="title">Assign viewLeads</div> <p><span class="image"><img src="./images/fine-grain-add-view-leads.png" alt="Fine grain add view leads"></span></p> </div> <div class="paragraph"> <p>We&#8217;ve only specified that the <code>sales-admin</code> can map the <code>viewLeads</code> role.</p> </div> </div> <div class="sect4"> <h5 id="per-client-map-roles-shortcut"><a class="anchor" href="#per-client-map-roles-shortcut"></a>Per client map-roles shortcut</h5> <div class="paragraph"> <p>It would be tedious if we had to do this for every client role that the <code>sales-application</code> published. to make things easier, there&#8217;s a way to specify that an admin can map any role defined by a client. If we log back into the admin console to our master realm admin and go back to the <code>sales-application</code> permissions page, you&#8217;ll see the <code>map-roles</code> permission.</p> </div> <div class="paragraph"> <div class="title">Client map-roles permission</div> <p><span class="image"><img src="./images/fine-grain-client-permissions-tab-on.png" alt="Fine grain client permissions"></span></p> </div> <div class="paragraph"> <p>If you grant access to this particular permission to an admin, that admin will be able map any role defined by the client.</p> </div> </div> </div> <div class="sect3"> <h4 id="full-list-of-permissions"><a class="anchor" href="#full-list-of-permissions"></a>Full list of permissions</h4> <div class="paragraph"> <p>You can do a lot more with fine grain permissions beyond managing a specific client or the specific roles of a client. This chapter defines the whole list of permission types that can be described for a realm.</p> </div> <div class="sect4"> <h5 id="role"><a class="anchor" href="#role"></a>Role</h5> <div class="paragraph"> <p>When going to the <code>Permissions</code> tab for a specific role, you will see these permission types listed.</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">map-role</dt> <dd> <p>Policies that decide if an admin can map this role to a user. These policies only specify that the role can be mapped to a user, not that the admin is allowed to perform user role mapping tasks. The admin will also have to have manage or role mapping permissions. See <a href="#_users-permissions">Users Permissions</a> for more information.</p> </dd> <dt class="hdlist1">map-role-composite</dt> <dd> <p>Policies that decide if an admin can map this role as a composite to another role. An admin can define roles for a client if he has to manage permissions for that client but he will not be able to add composites to those roles unless he has the <code>map-role-composite</code> privileges for the role he wants to add as a composite.</p> </dd> <dt class="hdlist1">map-role-client-scope</dt> <dd> <p>Policies that decide if an admin can apply this role to the scope of a client. Even if the admin can manage the client, he will not have permission to create tokens for that client that contain this role unless this privilege is granted.</p> </dd> </dl> </div> </div> <div class="sect4"> <h5 id="client"><a class="anchor" href="#client"></a>Client</h5> <div class="paragraph"> <p>When going to the <code>Permissions</code> tab for a specific client, you will see these permission types listed.</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">view</dt> <dd> <p>Policies that decide if an admin can view the client&#8217;s configuration.</p> </dd> <dt class="hdlist1">manage</dt> <dd> <p>Policies that decide if an admin can view and manage the client&#8217;s configuration. There are some issues with this in that privileges could be leaked unintentionally. For example, the admin could define a protocol mapper that hardcoded a role even if the admin does not have privileges to map the role to the client&#8217;s scope. This is currently the limitation of protocol mappers as they don&#8217;t have a way to assign individual permissions to them like roles do.</p> </dd> <dt class="hdlist1">configure</dt> <dd> <p>Reduced set of privileges to manage the client. It is like the <code>manage</code> scope except the admin is not allowed to define protocol mappers, change the client template, or the client&#8217;s scope.</p> </dd> <dt class="hdlist1">map-roles</dt> <dd> <p>Policies that decide if an admin can map any role defined by the client to a user. This is a shortcut, easy-of-use feature to avoid having to define policies for each and every role defined by the client.</p> </dd> <dt class="hdlist1">map-roles-composite</dt> <dd> <p>Policies that decide if an admin can map any role defined by the client as a composite to another role. This is a shortcut, easy-of-use feature to avoid having to define policies for each and every role defined by the client.</p> </dd> <dt class="hdlist1">map-roles-client-scope</dt> <dd> <p>Policies that decide if an admin can map any role defined by the client to the scope of another client. This is a shortcut, easy-of-use feature to avoid having to define policies for each and every role defined by the client.</p> </dd> </dl> </div> </div> <div class="sect4"> <h5 id="_users-permissions"><a class="anchor" href="#_users-permissions"></a>Users</h5> <div class="paragraph"> <p>When going to the <code>Permissions</code> tab for all users, you will see these permission types listed.</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">view</dt> <dd> <p>Policies that decide if an admin can view all users in the realm.</p> </dd> <dt class="hdlist1">manage</dt> <dd> <p>Policies that decide if an admin can manage all users in the realm. This permission grants the admin the privilege to perform user role mappings, but it does not specify which roles the admin is allowed to map. You&#8217;ll need to define the privilege for each role you want the admin to be able to map.</p> </dd> <dt class="hdlist1">map-roles</dt> <dd> <p>This is a subset of the privileges granted by the <code>manage</code> scope. In this case the admin is only allowed to map roles. The admin is not allowed to perform any other user management operation. Also, like <code>manage</code>, the roles that the admin is allowed to apply must be specified per role or per set of roles if dealing with client roles.</p> </dd> <dt class="hdlist1">manage-group-membership</dt> <dd> <p>Similar to <code>map-roles</code> except that it pertains to group membership: which groups a user can be added or removed from. These policies just grant the admin permission to manage group membership, not which groups the admin is allowed to manage membership for. You&#8217;ll have to specify policies for each group&#8217;s <code>manage-members</code> permission.</p> </dd> <dt class="hdlist1">impersonate</dt> <dd> <p>Policies that decide if the admin is allowed to impersonate other users. These policies are applied to the administrator&#8217;s attributes and role mappings.</p> </dd> <dt class="hdlist1">user-impersonated</dt> <dd> <p>Policies that decide which users can be impersonated. These policies will be applied to the user being impersonated. For example, you might want to define a policy that will forbid anybody from impersonating a user that has admin privileges.</p> </dd> </dl> </div> </div> <div class="sect4"> <h5 id="group"><a class="anchor" href="#group"></a>Group</h5> <div class="paragraph"> <p>When going to the <code>Permissions</code> tab for a specific group, you will see these permission types listed.</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">view</dt> <dd> <p>Policies that decide if the admin can view information about the group.</p> </dd> <dt class="hdlist1">manage</dt> <dd> <p>Policies that decide if the admin can manage the configuration of the group.</p> </dd> <dt class="hdlist1">view-members</dt> <dd> <p>Policies that decide if the admin can view the user details of members of the group.</p> </dd> <dt class="hdlist1">manage-members</dt> <dd> <p>Policies that decide if the admin can manage the users that belong to this group.</p> </dd> <dt class="hdlist1">manage-membership</dt> <dd> <p>Policies that decide if an admin can change the membership of the group. Add or remove members from the group.</p> </dd> </dl> </div> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="_managing_organizations"><a class="anchor" href="#_managing_organizations"></a>Managing organizations</h2> <div class="sectionbody"> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/assembly-managing-organizations.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/assembly-managing-organizations.adoc&amp;description=%0A%0AFile:%20server_admin/topics/assembly-managing-organizations.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>When integrating with a third party like a customer or business partner, you might want to manage their identities separately from others and build a unified and secure experience throughout your business ecosystem when they interact with a realm.</p> </div> <div class="paragraph"> <p>In a realm, an <strong>organization</strong> represents these third parties so that a realm or an organization administrator can manage the entire lifecycle of its members and how they authenticate and authorize to a realm, on a per-organization basis.</p> </div> <div class="paragraph"> <p>The organization is the entry point to start using the IAM capabilities of Keycloak to also address Business-to-Business (B2B) use cases. It enables multi-tenancy within a realm so that users can have access to protected resources from a realm but with a more restricted and controlled context, that context being the organization to which they belong.</p> </div> <div class="paragraph"> <p>Keycloak Organizations is a feature that enables support for organizations in Keycloak. For now, it provides some of the core capabilities needed to manage organizations such as:</p> </div> <div class="ulist"> <ul> <li> <p>Manage members</p> </li> <li> <p>Onboard organization members using invitation links</p> </li> <li> <p>Onboard organization members by federating their identities through identity brokering</p> </li> <li> <p>Identity-first login and organization-specific steps when authenticating in the scope of an organization</p> </li> <li> <p>Propagate organization-specific claims to applications through tokens for authorization purposes</p> </li> </ul> </div> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/organizations/intro.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/organizations/intro.adoc&amp;description=%0A%0AFile:%20server_admin/topics/organizations/intro.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="sect2"> <h3 id="_enabling_organization_"><a class="anchor" href="#_enabling_organization_"></a>Enabling organizations in Keycloak</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/organizations/managing-organization.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/organizations/managing-organization.adoc&amp;description=%0A%0AFile:%20server_admin/topics/organizations/managing-organization.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>To use organizations, you have to enable the feature for the current realm.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Realm Settings</strong> in the menu.</p> </li> <li> <p>Toggle <strong>Organizations</strong> to <strong>On</strong>.</p> </li> <li> <p>Click <strong>Save</strong></p> </li> </ol> </div> <div class="paragraph"> <div class="title">Enabling Organizations</div> <p><span class="image"><img src="./images/organizations-enabling-orgs.png" alt="Enabling Organizations"></span></p> </div> <div class="paragraph"> <p>Once the feature is enabled, you are able to manage organizations through the <strong>Organizations</strong> section available from the menu.</p> </div> </div> <div class="sect2"> <h3 id="managing-an-organization"><a class="anchor" href="#managing-an-organization"></a>Managing an organization</h3> <div class="paragraph _abstract"> <p>From the <strong>Organizations</strong> section, you can manage all the organizations in your realm.</p> </div> <div class="paragraph"> <div class="title">Managing organizations</div> <p><span class="image"><img src="./images/organizations-management-screen.png" alt="Managing organizations"></span></p> </div> <div class="sect3"> <h4 id="creating-an-organization"><a class="anchor" href="#creating-an-organization"></a>Creating an organization</h4> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Create Organization</strong>.</p> </li> </ol> </div> <div class="paragraph"> <div class="title">Creating organization</div> <p><span class="image"><img src="./images/organizations-create-org.png" alt="Creating organization"></span></p> </div> <div class="paragraph"> <p>An organization has the following settings:</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Name</dt> <dd> <p>A user-friendly name for the organization. The name is unique within a realm.</p> </dd> <dt class="hdlist1">Alias</dt> <dd> <p>An alias for this organization, used to reference the organization internally. The alias is unique within a realm and must be URL-friendly, so characters not usually allowed in URLs will not be allowed in the alias. If not set, Keycloak will attempt to use the name as the alias. If the name is not URL-friendly, you will get an error and will be asked to specify an alias. Once defined, the alias cannot be changed afterwards.</p> </dd> <dt class="hdlist1">Redirect URL</dt> <dd> <p>After completing registration or accepting an invitation to the organization sent via email, the user is automatically redirected to the specified redirect url. If left empty, the user will be redirected to the account console by default.</p> </dd> <dt class="hdlist1">Domains</dt> <dd> <p>A set of one or more domains that belongs to this organization. A domain cannot be shared by different organizations within a realm.</p> </dd> <dt class="hdlist1">Description</dt> <dd> <p>A free-text field to describe the organization.</p> </dd> </dl> </div> <div class="paragraph"> <p>Once you create an organization, you can manage the additional settings that are described in the following sections:</p> </div> <div class="ulist"> <ul> <li> <p><a href="#_managing_attributes_">Manage attributes</a></p> </li> <li> <p><a href="#_managing_members_">Manage members</a></p> </li> <li> <p><a href="#_managing_identity_provider_">Manage identity providers</a></p> </li> </ul> </div> </div> <div class="sect3"> <h4 id="understanding-organization-domains"><a class="anchor" href="#understanding-organization-domains"></a>Understanding organization domains</h4> <div class="paragraph"> <p>When managing an organization, the domain associated with an organization plays an important role in how organization members authenticate to a realm and how their profiles are validated.</p> </div> <div class="paragraph"> <p>One of the key roles of a domain is to help to identify the organizations where a user is a member. By looking at their email address, Keycloak will match a corresponding organization using the same domain and eventually change the authentication flow based on the organization requirements.</p> </div> <div class="paragraph"> <p>The domain also allows organizations to enforce that users are not allowed to use a domain in their emails other than those associated with an organization. This restriction is especially useful when users, and their identities, are federated from identity providers associated with an organization and you want to force a specific email domain for their email addresses.</p> </div> </div> <div class="sect3"> <h4 id="disabling-an-organization"><a class="anchor" href="#disabling-an-organization"></a>Disabling an organization</h4> <div class="paragraph"> <p>To disable an organization, toggle <strong>Enabled</strong> to <strong>Off</strong>.</p> </div> <div class="paragraph"> <div class="title">Disabling organization</div> <p><span class="image"><img src="./images/organizations-disable-org.png" alt="Disabling organization"></span></p> </div> <div class="paragraph"> <p>When an organization is disabled, you can still manage it through the management interfaces, but the organization members cannot authenticate to the realm, including authenticating through the identity providers associated with the organization as they are also automatically disabled.</p> </div> <div class="paragraph"> <p>However, the unmanaged members of an organization are still able to authenticate to the realm as they are also realm users, but tokens will not hold metadata about their relationship with an organization that is disabled.</p> </div> <div class="paragraph"> <p>For more details about managed and unmanaged users, see <a href="#_managed_unmanaged_members_">Managed and unmanaged members</a> section.</p> </div> </div> <div class="sect3"> <h4 id="deleting-an-organization"><a class="anchor" href="#deleting-an-organization"></a>Deleting an organization</h4> <div class="paragraph"> <p>To delete an organization, click the <strong>Delete</strong> action for the corresponding organization in the listing page or when editing an organization.</p> </div> <div class="paragraph"> <div class="title">Deleting organization</div> <p><span class="image"><img src="./images/organizations-delete-org.png" alt="Deleting organization"></span></p> </div> <div class="paragraph"> <p>When removing an organization, all data associated with it will be deleted, including any managed member.</p> </div> <div class="paragraph"> <p>Unmanaged users and identity providers remain in the realm, but they are no longer linked to the organization.</p> </div> <div class="paragraph"> <p>For more details about managed and unmanaged users, see <a href="#_managed_unmanaged_members_">Managed and unmanaged members</a>.</p> </div> </div> </div> <div class="sect2"> <h3 id="_managing_attributes_"><a class="anchor" href="#_managing_attributes_"></a>Managing attributes</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/organizations/managing-attributes.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/organizations/managing-attributes.adoc&amp;description=%0A%0AFile:%20server_admin/topics/organizations/managing-attributes.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>An administrator can store additional metadata about an organization using attributes. An organization attribute is a key/value pair that can hold multiple string values.</p> </div> <div class="paragraph"> <p>For that, click the <strong>Attributes</strong> tab and set any attribute you want by providing a key and a value.</p> </div> <div class="paragraph"> <p>To provide multiple values for the same attribute, and key, just add another attribute with the same key but with a different value.</p> </div> <div class="paragraph"> <div class="title">Managing organization attributes</div> <p><span class="image"><img src="./images/organizations-manage-attributes.png" alt="Managing organization attributes"></span></p> </div> </div> <div class="sect2"> <h3 id="_managing_members_"><a class="anchor" href="#_managing_members_"></a>Managing members</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/organizations/managing-members.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/organizations/managing-members.adoc&amp;description=%0A%0AFile:%20server_admin/topics/organizations/managing-members.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>An organization member is basically a realm user but with a link to a single organization. They are logically separated from other users in a realm so that you know exactly which users belong to an organization.</p> </div> <div class="paragraph"> <p>There are different ways to add, or onboard, a member to an organization:</p> </div> <div class="ulist"> <ul> <li> <p>Adding an existing realm user as a member</p> </li> <li> <p>Through an identity provider associated with an organization</p> </li> <li> <p>Sending an invitation to create a new account</p> </li> <li> <p>Sending an invitation to an existing user to join an organization</p> </li> </ul> </div> <div class="paragraph"> <p>Once a member of an organization, that user&#8217;s account can be managed just like any regular account in a realm by accessing the <strong>Users</strong> section in the menu.</p> </div> <div class="paragraph"> <p>However, you can narrow the users to only those associated with an organization by accessing the <strong>Members</strong> tab when managing an organization. In this tab, you have a list of all the organization members and actions to add new members and to edit and remove existing ones.</p> </div> <div class="paragraph"> <div class="title">Managing organization members</div> <p><span class="image"><img src="./images/organizations-manage-members.png" alt="Managing organization members"></span></p> </div> <div class="sect3"> <h4 id="_managed_unmanaged_members_"><a class="anchor" href="#_managed_unmanaged_members_"></a>Managed and unmanaged members</h4> <div class="paragraph"> <p>When managing members, consider how their relationship with an organization affects the lifecycle of their accounts. Members can join an organization through different flows and each flow indicates the strength of the link between their accounts and the organization.</p> </div> <div class="paragraph"> <p>There are two types of members:</p> </div> <div class="ulist"> <ul> <li> <p><strong>Managed</strong></p> </li> <li> <p><strong>Unmanaged</strong></p> </li> </ul> </div> <div class="paragraph"> <p>Managed members are those managed by the organization, and they cannot exist outside of their organization. For instance, consider an account created through an identity provider associated with an organization. That account does not belong to a realm as it was federated from the organization. In this case, the single-source of truth for the identity is the organization and its lifecycle is controlled by the organization. If you remove the organization or the member, the account is also removed from the realm.</p> </div> <div class="paragraph"> <p>On the other hand, unmanaged members are those that can exist without the organization. For instance, when adding an existing realm user to an organization, the account belongs to the realm first and foremost and eventually linked to an organization. In this case, removing an organization or a member will not remove the account from the realm; the realm is the single-source of truth for the identity.</p> </div> </div> <div class="sect3"> <h4 id="adding-an-existing-realm-user-as-a-member"><a class="anchor" href="#adding-an-existing-realm-user-as-a-member"></a>Adding an existing realm user as a member</h4> <div class="paragraph"> <p>An existing realm user can join an organization by selecting that user from a list and adding the user to the organization.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Add member</strong>.</p> </li> <li> <p>Click <strong>Add realm user</strong>.</p> </li> <li> <p>Select one or more users and click <strong>Add</strong> to add them to the organization.</p> </li> </ol> </div> <div class="paragraph"> <div class="title">Adding a realm user</div> <p><span class="image"><img src="./images/organizations-add-realm-user.png" alt="Adding a realm user"></span></p> </div> <div class="paragraph"> <p>Once a user is a member of the organization, that user is able to authenticate to the realm just like a regular user and using any credential supported by the realm.</p> </div> </div> <div class="sect3"> <h4 id="inviting-users"><a class="anchor" href="#inviting-users"></a>Inviting users</h4> <div class="paragraph"> <p>An administrator can email users to join an organization.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Add member</strong>.</p> </li> <li> <p>Click <strong>Invite member</strong>.</p> </li> <li> <p>Provide an email address</p> </li> <li> <p>Click <strong>Send</strong></p> </li> </ol> </div> <div class="paragraph"> <div class="title">Inviting members</div> <p><span class="image"><img src="./images/organizations-invite-member.png" alt="Inviting members"></span></p> </div> <div class="paragraph"> <p>Optionally, you can also provide a value for the <strong>First name</strong> and <strong>Last name</strong> fields for a more personalized email message using a greeting message with the first and last names of the person receiving the email.</p> </div> <div class="paragraph"> <p>An invitation is basically an email sent with a link that the person should click to perform the necessary steps to join an organization. These steps depend on whether the person already has an account in the realm or if a new account should be created before joining the organization.</p> </div> <div class="paragraph"> <p>If the email maps to an existing user in a realm, the steps the user will follow are basically about confirming the intention to join the organization.</p> </div> <div class="paragraph"> <p>On the other hand, if no user is associated with the given email address, the steps will involve creating a new account through the realm&#8217;s self-registration flow. In this case, the user is forced to provide the same email address used to send the invitation.</p> </div> </div> <div class="sect3"> <h4 id="_onboard_member_identity_provider_"><a class="anchor" href="#_onboard_member_identity_provider_"></a>Onboarding members using an Identity Provider</h4> <div class="paragraph"> <p>An organization might have its own identity provider as the single source of truth for their identities. In this case, users federated from the identity provider are automatically added as a member of the organization.</p> </div> <div class="paragraph"> <p>When users join an organization through an identity provider associated with an organization, they are automatically marked as managed members. In this case, they will go through the broker login flows configured in the realm and join the organization automatically once they successfully authenticate.</p> </div> <div class="paragraph"> <p>Onboarding new members through an identity provider can be done by either automatically redirecting the user to an organization&#8217;s identity provider or by selecting the identity provider when at the login page.</p> </div> <div class="paragraph"> <p>In both cases, once the user provides the email, Keycloak will try to match an organization based on the email domain. In case the email domain matches the organization, and an identity provider is associated with the same domain and the <strong>Redirect when email domain matches</strong> setting is enabled, the user is automatically redirected to the identity provider. Once the user authenticates at the identity provider and completes the first broker login flow, the user is automatically added as an organization member.</p> </div> <div class="paragraph"> <p>On the other hand, if <strong>Redirect when email domain matches</strong> is not enabled, but the identity provider is configured not to <strong>Hide on login page</strong>, the user can select the identity provider and then be redirected to the identity provider to continue the onboarding process.</p> </div> <div class="paragraph"> <p>For more details, see <a href="#_managing_identity_provider_">Managing Identity Providers</a>.</p> </div> </div> <div class="sect3"> <h4 id="removing-a-member"><a class="anchor" href="#removing-a-member"></a>Removing a member</h4> <div class="paragraph"> <p>You can remove a member from an organization.</p> </div> <div class="paragraph"> <p>From the action menu next to the member you want to remove, click <strong>Remove</strong>.</p> </div> <div class="paragraph"> <p>When removing a member from an organization, remember that the user may or may not be removed from a realm depending on if that user is managed or unmanaged member, respectively.</p> </div> <div class="paragraph"> <p>For more details, see <a href="#_managed_unmanaged_members_">Managed and unmanaged members</a>.</p> </div> </div> </div> <div class="sect2"> <h3 id="_managing_identity_provider_"><a class="anchor" href="#_managing_identity_provider_"></a>Managing identity providers</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/organizations/managing-identity-providers.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/organizations/managing-identity-providers.adoc&amp;description=%0A%0AFile:%20server_admin/topics/organizations/managing-identity-providers.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>An organization might have its own identity provider as the single source of truth for their identities. In this case, you want to configure the organization to authenticate users using the organization&#8217;s identity provider, federate their identities, and finally add them as a member of the organization.</p> </div> <div class="paragraph"> <p>An organization can have one or more identity providers associated with it so that they can authenticate their users from different sources and enforce different constraints on each of them.</p> </div> <div class="paragraph"> <p>Before you can link an identity provider to an organization, you create an organization at the realm level from the <strong>Identity Providers</strong> section in the menu. You can link any of the built-in social and identity providers available in the realm to an organization.</p> </div> <div class="sect3"> <h4 id="linking-an-identity-provider-to-an-organization"><a class="anchor" href="#linking-an-identity-provider-to-an-organization"></a>Linking an identity provider to an organization</h4> <div class="paragraph"> <p>An identity provider can be linked to an organization from the <strong>Identity providers</strong> tab. If identity providers already exist, you see a list of them and options to search, edit, or unlink from the organization.</p> </div> <div class="paragraph"> <div class="title">Organization identity providers</div> <p><span class="image"><img src="./images/organizations-identity-providers.png" alt="Organization identity providers"></span></p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Link identity provider</strong></p> </li> <li> <p>Select an <strong>Identity provider</strong></p> </li> <li> <p>Set the appropriate settings</p> </li> <li> <p>Click <strong>Save</strong></p> </li> </ol> </div> <div class="paragraph"> <div class="title">Linking identity provider</div> <p><span class="image"><img src="./images/organizations-link-identity-provider.png" alt="Linking identity provider"></span></p> </div> <div class="paragraph"> <p>An identity provider has the following settings:</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Identity provider</dt> <dd> <p>The identity provider you want to link to the organization. An identity provider can only be linked to a single organization.</p> </dd> <dt class="hdlist1">Domain</dt> <dd> <p>The domain from the organization that you want to link with the identity provider.</p> </dd> <dt class="hdlist1">Hide on login page</dt> <dd> <p>If this identity provider should be hidden in login pages when the user is authenticating in the scope of the organization.</p> </dd> <dt class="hdlist1">Redirect when email domain matches</dt> <dd> <p>If members should be automatically redirected to the identity provider when their email domain matches the domain set to the identity provider.</p> </dd> </dl> </div> <div class="paragraph"> <p>Once linked to an organization, the identity provider can be managed just like any other in a realm by accessing the <strong>Identity Providers</strong> section in the menu. However, the options herein described are only available when managing the identity provider in the scope of an organization. The only exception is the <strong>Hide on login page</strong> option that is present here for convenience.</p> </div> </div> <div class="sect3"> <h4 id="editing-a-linked-identity-provider"><a class="anchor" href="#editing-a-linked-identity-provider"></a>Editing a linked identity provider</h4> <div class="paragraph"> <p>You can edit any of the organization-related settings of a linked identity provider at any time. .Procedure</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>In the menu, click <strong>Organizations</strong> and go to the <strong>Identity providers</strong> tab.</p> </li> <li> <p>Locate the <strong>identity provider</strong> in the list.</p> <div class="paragraph"> <p>You can use the search option for this step.</p> </div> </li> <li> <p>Click the action button (three dots) at the end of the line.</p> </li> <li> <p>Click <strong>Edit</strong>.</p> </li> <li> <p>Make the necessary changes.</p> </li> <li> <p>Click <strong>Save</strong>.</p> </li> </ol> </div> <div class="paragraph"> <div class="title">Editing linked identity provider</div> <p><span class="image"><img src="./images/organizations-edit-identity-provider.png" alt="Editing linked identity provider"></span></p> </div> </div> <div class="sect3"> <h4 id="unlinking-an-identity-provider-from-an-organization"><a class="anchor" href="#unlinking-an-identity-provider-from-an-organization"></a>Unlinking an identity provider from an organization</h4> <div class="paragraph"> <p>When an identity provider is unlinked from an organization, it remains available as a realm-level provider that is no longer ssociated with an organization. To delete the unlinked provider, use the <strong>Identity Providers</strong> section in the menu.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>In the menu, click <strong>Organizations</strong> and go to the <strong>Identity providers</strong> tab.</p> </li> <li> <p>Locate the <strong>identity provider</strong> in the list.</p> <div class="paragraph"> <p>You can use the search capabilities for this step.</p> </div> </li> <li> <p>Click the action button (three dots) at the end of the line.</p> </li> <li> <p>Click <strong>Unlink provider</strong>.</p> </li> </ol> </div> <div class="paragraph"> <div class="title">Unlinking identity provider</div> <p><span class="image"><img src="./images/organizations-unlink-identity-provider.png" alt="Unlinking identity provider"></span></p> </div> </div> </div> <div class="sect2"> <h3 id="authenticating-members_server_administration_guide"><a class="anchor" href="#authenticating-members_server_administration_guide"></a>Authenticating members</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/organizations/authenticating-members.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/organizations/authenticating-members.adoc&amp;description=%0A%0AFile:%20server_admin/topics/organizations/authenticating-members.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>When you enable organizations for a realm, user authentication is changed. If the user is recognized to be authenticating in the context of an organization, the authentication flow changes on a per-organization basis.</p> </div> <div class="paragraph"> <p>When a realm is created, the authentication flows are automatically updated to enable specific steps to authenticate and onboard organization members. The authentication flows updated are:</p> </div> <div class="ulist"> <ul> <li> <p><strong>browser</strong></p> </li> <li> <p><strong>first broker login</strong></p> </li> </ul> </div> <div class="paragraph"> <p>The main change to the <strong>browser</strong> flow is that it defaults to an identity-first login so that users are identified before prompting for their credentials. Concerning the first broker login flow, the main change is automatically adding the users as organization members once they authenticate through the identity provider associated with an organization and successfully complete the flow.</p> </div> <div class="paragraph"> <p>The choice to use an identity-first login or not depends on the existence of an organization in a realm. If no organizations exist, the user follows the usual steps to authenticate using the username and password, or any other step configured in the browser flow. Otherwise, the user is asked first for a username or email to continue authenticating to a realm.</p> </div> <div class="paragraph"> <p>The identity-first login main goal is to identify the user:</p> </div> <div class="ulist"> <ul> <li> <p>Is the user an existing or a new user?</p> </li> <li> <p>Is the user a member of any organization within a realm?</p> </li> <li> <p>If an organization member, is the user linked to any identity provider associated with the organization?</p> </li> </ul> </div> <div class="paragraph"> <p>Depending on the outcome when identifying the user, the authentication flow changes to either proceed with authentication by asking for the user&#8217;s credentials or eventually redirect the user automatically to authenticate within the organization security boundaries through an identity provider.</p> </div> <div class="sect3"> <h4 id="understanding-the-identity-first-login"><a class="anchor" href="#understanding-the-identity-first-login"></a>Understanding the identity-first login</h4> <div class="paragraph"> <p>In addition to identifying the user once the username is provided, the identity-first login is also responsible for:</p> </div> <div class="ulist"> <ul> <li> <p>Matching an email domain to an organization.</p> </li> <li> <p>Deciding if the authentication flow should continue or not if an account already exists for the username provided</p> </li> <li> <p>Deciding how the user should be authenticated depending on how the domains and the identity providers are configured to an organization</p> </li> <li> <p>Seamlessly authenticating users through an identity provider associated with an organization if the email domain matches the domain set to the identity provider</p> </li> </ul> </div> <div class="paragraph"> <p>The identity-first login provides the same capabilities that are provided by the usual login page with the username and password fields. Users can still self-register by clicking the register link or choose any identity or social broker that is not linked to an organization in that realm.</p> </div> <div class="paragraph"> <div class="title">Identity-first login page</div> <p><span class="image"><img src="./images/organizations-identity-first-login.png" alt="Identity-first login page"></span></p> </div> <div class="paragraph"> <p>In the case of a user that does not exist, if that user tries to authenticate using an email domain that matches an organization domain, the identity-first login page appears again with a message that the username provided is not valid. At this point, no need exists to ask the user for credentials.</p> </div> <div class="paragraph"> <div class="title">Identity-first when user does not exist</div> <p><span class="image"><img src="./images/organizations-identity-first-error.png" alt="Identity-first login error"></span></p> </div> <div class="paragraph"> <p>Several options exist to register the user allowing that user to authenticate to the realm and join an organization.</p> </div> <div class="paragraph"> <p>If the realm has the self-registration setting enabled, the user can click the <strong>Register</strong> link at the identity-first login page and create an account at the realm. After that, the administrator can send an invitation link to the user or manually add the user as a member of an organization. For more details, see <a href="#_managing_members_">Managing members</a>.</p> </div> <div class="paragraph"> <p>If the organization has an identity provider without a domain and the <strong>Hide on login page</strong> setting is <strong>OFF</strong>, users can also click the identity provider link at the identity-first login page to automatically create an account and join an organization once they authenticate through the identity provider. For more details, see <a href="#_managing_identity_provider_">Managing identity providers</a>.</p> </div> <div class="paragraph"> <p>In a similar situation to the previous section, the organization may have an identity provider set with one of the organization domains. In this situation, the user is redirected to the identity provider if that user&#8217;s email matches a specific domain from the organization. Once the flow completes, an account is created and the user joins the organization.</p> </div> </div> <div class="sect3"> <h4 id="configuring-existing-authentication-flows"><a class="anchor" href="#configuring-existing-authentication-flows"></a>Configuring existing authentication flows</h4> <div class="paragraph"> <p>As previously mentioned for new realms, authentication flows are automatically updated with the necessary steps to support organizations and authenticate their members. For existing realms, in addition to enabling organizations to the realm, you also need to manually update your existing (custom) authenticating flows.</p> </div> <div class="paragraph"> <p>Change the <strong>browser</strong> flow by following these steps:</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Duplicate the current flow bound to the <strong>Browser flow</strong> binding type to avoid breaking the flow you are currently using</p> </li> <li> <p>Click <strong>Add sub-flow</strong> and give it a name such as <strong>My Organization</strong></p> </li> <li> <p>Move the newly added <strong>My Organization</strong> sub-flow to execute right after the <strong>Identity Provider Redirector</strong> execution step. The main point here is that the sub-flow should happen before any other sub-flow or execution step that authenticates the user using whatever credentials you support in your realm. Once added, change the <strong>Requirement</strong> to <strong>Alternative</strong>.</p> </li> <li> <p>Click <strong>Add sub-flow</strong> in the <strong>My Organization</strong> sub-flow and give it a name such as <strong>My Organization - Conditional</strong>. Once added, change the <strong>Requirement</strong> to <strong>Conditional</strong>.</p> </li> <li> <p>Click <strong>Add condition</strong> in the <strong>My Organization - Conditional</strong> sub-flow and select <strong>Condition - user configured</strong>. Once added, change the <strong>Requirement</strong> to <strong>Required</strong>.</p> </li> <li> <p>Click <strong>Add step</strong> in the <strong>My Organization - Conditional</strong> sub-flow and select the *Organization Identity-First Login</p> <div class="ulist"> <ul> <li> <p>execution step. Once added, change the <strong>Requirement</strong> to <strong>Alternative</strong>.</p> </li> </ul> </div> </li> <li> <p>Bind the authentication flow to the <strong>Browser</strong> binding type.</p> </li> </ol> </div> <div class="paragraph"> <div class="title">Organizations browser flow</div> <p><span class="image"><img src="./images/organizations-browser-flow.png" alt="Organizations browser flow"></span></p> </div> <div class="paragraph"> <p>Once you enable the <a href="#_enabling_organization_">Organizations</a> setting to the realm and create at least a single organization, you should be able to see the identity-first login page and start using organizations in your realm.</p> </div> <div class="paragraph"> <p>Change the <strong>first broker login</strong> flow by following these steps:</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Duplicate the current flow bound to the <strong>First broker login flow</strong> bind type to avoid breaking the flow you are currently using</p> </li> <li> <p>Click <strong>Add sub-flow</strong> and give it a name such as <code>Organization Member - Conditional</code>. Once added, change the <strong>Requirement</strong> to <strong>Conditional</strong>.</p> </li> <li> <p>Click <strong>Add condition</strong> in the <strong>Organization Member - Conditional</strong> sub-flow and select <strong>Condition - user configured</strong>. Once added, change the <strong>Requirement</strong> to <strong>Required</strong>.</p> </li> <li> <p>Click <strong>Add step</strong> in the <strong>Organization Member - Conditional</strong> sub-flow and select the <strong>Organization Member Onboard</strong> execution step. Once added, change the <strong>Requirement</strong> to <strong>Required</strong>.</p> </li> <li> <p>Bind the authentication flow to the <strong>First broker login</strong> binding type.</p> </li> </ol> </div> <div class="paragraph"> <div class="title">Organizations first broker flow</div> <p><span class="image"><img src="./images/organizations-first-broker-flow.png" alt="Organizations first broker flow"></span></p> </div> <div class="paragraph"> <p>You should now be able to authenticate using any identity provider associated with an organization and have the user joining the organization as a member as soon as they complete the first browser login flow.</p> </div> </div> </div> <div class="sect2"> <h3 id="mapping-organization-claims_server_administration_guide"><a class="anchor" href="#mapping-organization-claims_server_administration_guide"></a>Mapping organization claims</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/organizations/mapping-organization-claims.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/organizations/mapping-organization-claims.adoc&amp;description=%0A%0AFile:%20server_admin/topics/organizations/mapping-organization-claims.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>To map organization-specific claims into tokens, a client needs to request the <strong>organization</strong> scope when sending authorization requests to the server. When authenticating in the context of an organization, clients can request the <code>organization</code> scope to map information about the organizations where the user is a member.</p> </div> <div class="paragraph"> <p>As a result, the token will contain a claim as follows:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="json"><span class="key"><span class="delimiter">&quot;</span><span class="content">organization</span><span class="delimiter">&quot;</span></span>: { <span class="key"><span class="delimiter">&quot;</span><span class="content">testcorp</span><span class="delimiter">&quot;</span></span>: { <span class="key"><span class="delimiter">&quot;</span><span class="content">id</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">42c3e46f-2477-44d7-a85b-d3b43f6b31fa</span><span class="delimiter">&quot;</span></span>, <span class="key"><span class="delimiter">&quot;</span><span class="content">attr1</span><span class="delimiter">&quot;</span></span>: [ <span class="string"><span class="delimiter">&quot;</span><span class="content">value1</span><span class="delimiter">&quot;</span></span> ] } }</code></pre> </div> </div> <div class="paragraph"> <p>The organization claim can be used by clients (for example, from ID Tokens) and resource servers (for example, from access tokens) to authorize access to protected resources based on the organization where the user is a member.</p> </div> <div class="paragraph"> <p>The <code>organization</code> scope is a built-in optional client scope at the realm. Therefore, this scope is added to any client created in the realm by default. It also defines the <code>Organization Membership</code> mapper that controls how the organization membership information is mapped to the tokens.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> By default, the organization id and attributes are not included in the organization claim. To include them, edit the mapper and enable the <strong>Add organization id</strong> and <strong>Add organization attributes</strong> options, respectively. </td> </tr> </table> </div> <div class="paragraph"> <div class="title">Including attributes in the organization claim</div> <p><span class="image"><img src="./images/organizations-add-org-attrs-in-claim.png" alt="Including attributes in the organization claim"></span></p> </div> <div class="paragraph"> <p>The <code>organization</code> scope is requested using different formats:</p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 50%;"> <col style="width: 50%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Format</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>organization</code></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Maps to a single organization if the user is a member of a single organization. Otherwise, if a member of multiple organizations, the user will be prompted to select an organization when authenticating to the realm.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>organization:&lt;alias&gt;</code></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Maps to a single organization with the given alias.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>organization:*</code></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Maps to all organizations the user is a member of.</p></td> </tr> </tbody> </table> </div> </div> </div> <div class="sect1"> <h2 id="assembly-managing-clients_server_administration_guide"><a class="anchor" href="#assembly-managing-clients_server_administration_guide"></a>Managing OpenID Connect and SAML Clients</h2> <div class="sectionbody"> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/assembly-managing-clients.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/assembly-managing-clients.adoc&amp;description=%0A%0AFile:%20server_admin/topics/assembly-managing-clients.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>Clients are entities that can request authentication of a user. Clients come in two forms. The first type of client is an application that wants to participate in single-sign-on. These clients just want Keycloak to provide security for them. The other type of client is one that is requesting an access token so that it can invoke other services on behalf of the authenticated user. This section discusses various aspects around configuring clients and various ways to do it.</p> </div> <div class="sect2"> <h3 id="_oidc_clients"><a class="anchor" href="#_oidc_clients"></a>Managing OpenID Connect clients</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/clients/assembly-client-oidc.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/clients/assembly-client-oidc.adoc&amp;description=%0A%0AFile:%20server_admin/topics/clients/assembly-client-oidc.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p><a href="#con-oidc_server_administration_guide">OpenID Connect</a> is the recommended protocol to secure applications. It was designed from the ground up to be web friendly and it works best with HTML5/JavaScript applications.</p> </div> <div class="sect3"> <h4 id="proc-creating-oidc-client_server_administration_guide"><a class="anchor" href="#proc-creating-oidc-client_server_administration_guide"></a>Creating an OpenID Connect client</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/clients/oidc/proc-creating-oidc-client.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/clients/oidc/proc-creating-oidc-client.adoc&amp;description=%0A%0AFile:%20server_admin/topics/clients/oidc/proc-creating-oidc-client.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>To protect an application that uses the OpenID connect protocol, you create a client.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Clients</strong> in the menu.</p> </li> <li> <p>Click <strong>Create client</strong>.</p> <div class="paragraph"> <div class="title">Create client</div> <p><span class="image"><img src="./images/add-client-oidc.png" alt="Create Client"></span></p> </div> </li> <li> <p>Leave <strong>Client type</strong> set to <strong>OpenID Connect</strong>.</p> </li> <li> <p>Enter a <strong>Client ID.</strong></p> <div class="paragraph"> <p>This ID is an alphanumeric string that is used in OIDC requests and in the Keycloak database to identify the client.</p> </div> </li> <li> <p>Supply a <strong>Name</strong> for the client.</p> <div class="paragraph"> <p>If you plan to localize this name, set up a replacement string value. For example, a string value such as ${myapp}. See the <a href="https://www.keycloak.org/docs/26.0.6/server_development/">Server Developer Guide</a> for more information.</p> </div> </li> <li> <p>Click <strong>Save</strong>.</p> </li> </ol> </div> <div class="paragraph"> <p>This action creates the client and bring you to the <strong>Settings</strong> tab, where you can perform <a href="#con-basic-settings_server_administration_guide">Basic configuration</a>.</p> </div> </div> <div class="sect3"> <h4 id="con-basic-settings_server_administration_guide"><a class="anchor" href="#con-basic-settings_server_administration_guide"></a>Basic configuration</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/clients/oidc/con-basic-settings.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/clients/oidc/con-basic-settings.adoc&amp;description=%0A%0AFile:%20server_admin/topics/clients/oidc/con-basic-settings.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>The <strong>Settings</strong> tab includes many options to configure this client.</p> </div> <div class="paragraph"> <div class="title">Settings tab</div> <p><span class="image"><img src="./images/client-settings-oidc.png" alt="Settings tab"></span></p> </div> <div class="sect4"> <h5 id="general-settings"><a class="anchor" href="#general-settings"></a>General Settings</h5> <div class="dlist"> <dl> <dt class="hdlist1"><strong>Client ID</strong></dt> <dd> <p>The alphanumeric ID string that is used in OIDC requests and in the Keycloak database to identify the client.</p> </dd> <dt class="hdlist1"><strong>Name</strong></dt> <dd> <p>The name for the client in Keycloak UI screen. To localize the name, set up a replacement string value. For example, a string value such as ${myapp}. See the <a href="https://www.keycloak.org/docs/26.0.6/server_development/">Server Developer Guide</a> for more information.</p> </dd> <dt class="hdlist1"><strong>Description</strong></dt> <dd> <p>The description of the client. This setting can also be localized.</p> </dd> <dt class="hdlist1"><strong>Always Display in Console</strong></dt> <dd> <p>Always list this client in the Account Console even if this user does not have an active session.</p> </dd> </dl> </div> </div> <div class="sect4"> <h5 id="access-settings"><a class="anchor" href="#access-settings"></a>Access Settings</h5> <div class="dlist"> <dl> <dt class="hdlist1"><strong>Root URL</strong></dt> <dd> <p>If Keycloak uses any configured relative URLs, this value is prepended to them.</p> </dd> <dt class="hdlist1"><strong>Home URL</strong></dt> <dd> <p>Provides the default URL for when the auth server needs to redirect or link back to the client.</p> </dd> <dt class="hdlist1"><strong>Valid Redirect URIs</strong></dt> <dd> <p>Required field. Enter a URL pattern and click <strong>+</strong> to add and <strong>-</strong> to remove existing URLs and click <strong>Save</strong>. Exact (case sensitive) string matching is used to compare valid redirect URIs.</p> <div class="paragraph"> <p>You can use wildcards at the end of the URL pattern. For example <code>http://host.com/path/*</code>. To avoid security issues, if the passed redirect URI contains the <strong>userinfo</strong> part or its <strong>path</strong> manages access to parent directory (<code>/../</code>) no wildcard comparison is performed but the standard and secure exact string matching.</p> </div> <div class="paragraph"> <p>The full wildcard <code>*</code> valid redirect URI can also be configured to allow any <strong>http</strong> or <strong>https</strong> redirect URI. Please do not use it in production environments.</p> </div> <div class="paragraph"> <p>Exclusive redirect URI patterns are typically more secure. See <a href="#unspecific-redirect-uris_server_administration_guide">Unspecific Redirect URIs</a> for more information.</p> </div> </dd> <dt class="hdlist1">Web Origins</dt> <dd> <p>Enter a URL pattern and click + to add and - to remove existing URLs. Click Save.</p> <div class="paragraph"> <p>This option handles <a href="https://fetch.spec.whatwg.org/">Cross-Origin Resource Sharing (CORS)</a>. If browser JavaScript attempts an AJAX HTTP request to a server whose domain is different from the one that the JavaScript code came from, the request must use CORS. The server must handle CORS requests, otherwise the browser will not display or allow the request to be processed. This protocol protects against XSS, CSRF, and other JavaScript-based attacks.</p> </div> <div class="paragraph"> <p>Domain URLs listed here are embedded within the access token sent to the client application. The client application uses this information to decide whether to allow a CORS request to be invoked on it. Only Keycloak client adapters support this feature. See <a href="https://www.keycloak.org/guides#securing-apps">Securing applications Guides</a> for more information.</p> </div> </dd> </dl> </div> <div id="_admin-url" class="dlist"> <dl> <dt class="hdlist1">Admin URL</dt> <dd> <p>Callback endpoint for a client. The server uses this URL to make callbacks like pushing revocation policies, performing backchannel logout, and other administrative operations. For Keycloak servlet adapters, this URL can be the root URL of the servlet application. For more information, see <a href="https://www.keycloak.org/guides#securing-apps">Securing applications Guides</a>.</p> </dd> </dl> </div> </div> <div class="sect4"> <h5 id="capability-config"><a class="anchor" href="#capability-config"></a>Capability Config</h5> <div id="_access-type" class="dlist"> <dl> <dt class="hdlist1"><strong>Client authentication</strong></dt> <dd> <p>The type of OIDC client.</p> <div class="ulist"> <ul> <li> <p><em>ON</em></p> <div class="paragraph"> <p>For server-side clients that perform browser logins and require client secrets when making an Access Token Request. This setting should be used for server-side applications.</p> </div> </li> <li> <p><em>OFF</em></p> <div class="paragraph"> <p>For client-side clients that perform browser logins. As it is not possible to ensure that secrets can be kept safe with client-side clients, it is important to restrict access by configuring correct redirect URIs.</p> </div> </li> </ul> </div> </dd> <dt class="hdlist1"><strong>Authorization</strong></dt> <dd> <p>Enables or disables fine-grained authorization support for this client.</p> </dd> <dt class="hdlist1"><strong>Standard Flow</strong></dt> <dd> <p>If enabled, this client can use the OIDC <a href="#_oidc-auth-flows-authorization">Authorization Code Flow</a>.</p> </dd> <dt class="hdlist1"><strong>Direct Access Grants</strong></dt> <dd> <p>If enabled, this client can use the OIDC <a href="#_oidc-auth-flows-direct">Direct Access Grants</a>.</p> </dd> <dt class="hdlist1"><strong>Implicit Flow</strong></dt> <dd> <p>If enabled, this client can use the OIDC <a href="#_oidc-auth-flows-implicit">Implicit Flow</a>.</p> </dd> <dt class="hdlist1"><strong>Service account roles</strong></dt> <dd> <p>If enabled, this client can authenticate to Keycloak and retrieve access token dedicated to this client. In terms of OAuth2 specification, this enables support of <code>Client Credentials Grant</code> for this client.</p> </dd> <dt class="hdlist1"><strong>Auth 2.0 Device Authorization Grant</strong></dt> <dd> <p>If enabled, this client can use the OIDC <a href="#con-oidc-auth-flows_server_administration_guide">Device Authorization Grant</a>.</p> </dd> <dt class="hdlist1"><strong>OIDC CIBA Grant</strong></dt> <dd> <p>If enabled, this client can use the OIDC <a href="#con-oidc-auth-flows_server_administration_guide">Client Initiated Backchannel Authentication Grant</a>.</p> </dd> </dl> </div> </div> <div class="sect4"> <h5 id="login-settings"><a class="anchor" href="#login-settings"></a>Login settings</h5> <div class="dlist"> <dl> <dt class="hdlist1"><strong>Login theme</strong></dt> <dd> <p>A theme to use for login, OTP, grant registration, and forgotten password pages.</p> </dd> <dt class="hdlist1"><strong>Consent required</strong></dt> <dd> <p>If enabled, users have to consent to client access.</p> <div class="paragraph"> <p>For client-side clients that perform browser logins. As it is not possible to ensure that secrets can be kept safe with client-side clients, it is important to restrict access by configuring correct redirect URIs.</p> </div> </dd> <dt class="hdlist1"><strong>Display client on screen</strong></dt> <dd> <p>This switch applies if <strong>Consent Required</strong> is <strong>Off</strong>.</p> <div class="ulist"> <ul> <li> <p><em>Off</em></p> <div class="paragraph"> <p>The consent screen will contain only the consents corresponding to configured client scopes.</p> </div> </li> <li> <p><em>On</em></p> <div class="paragraph"> <p>There will be also one item on the consent screen about this client itself.</p> </div> </li> </ul> </div> </dd> <dt class="hdlist1"><strong>Client consent screen text</strong></dt> <dd> <p>Applies if <strong>Consent required</strong> and <strong>Display client on screen</strong> are enabled. Contains the text that will be on the consent screen about permissions for this client.</p> </dd> </dl> </div> </div> <div class="sect4"> <h5 id="logout-settings"><a class="anchor" href="#logout-settings"></a>Logout settings</h5> <div id="_front-channel-logout" class="dlist"> <dl> <dt class="hdlist1"><strong>Front channel logout</strong></dt> <dd> <p>If <strong>Front Channel Logout</strong> is enabled, the application should be able to log out users through the front channel as per <a href="https://openid.net/specs/openid-connect-frontchannel-1_0.html">OpenID Connect Front-Channel Logout</a> specification. If enabled, you should also provide the <code>Front-Channel Logout URL</code>.</p> </dd> <dt class="hdlist1"><strong>Front-channel logout URL</strong></dt> <dd> <p>URL that will be used by Keycloak to send logout requests to clients through the front-channel.</p> </dd> </dl> </div> <div id="_back-channel-logout-url" class="dlist"> <dl> <dt class="hdlist1"><strong>Backchannel logout URL</strong></dt> <dd> <p>URL that will cause the client to log itself out when a logout request is sent to this realm (via end_session_endpoint). If omitted, no logout requests are sent to the client.</p> </dd> <dt class="hdlist1"><strong>Backchannel logout session required</strong></dt> <dd> <p>Specifies whether a session ID Claim is included in the Logout Token when the <strong>Backchannel Logout URL</strong> is used.</p> </dd> <dt class="hdlist1"><strong>Backchannel logout revoke offline sessions</strong></dt> <dd> <p>Specifies whether a revoke_offline_access event is included in the Logout Token when the Backchannel Logout URL is used. Keycloak will revoke offline sessions when receiving a Logout Token with this event.</p> </dd> </dl> </div> </div> </div> <div class="sect3"> <h4 id="con-advanced-settings_server_administration_guide"><a class="anchor" href="#con-advanced-settings_server_administration_guide"></a>Advanced configuration</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/clients/oidc/con-advanced-settings.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/clients/oidc/con-advanced-settings.adoc&amp;description=%0A%0AFile:%20server_admin/topics/clients/oidc/con-advanced-settings.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>After completing the fields on the <strong>Settings</strong> tab, you can use the other tabs to perform advanced configuration. For example, you can use the <strong>Permissions</strong> and <strong>Roles</strong> tabs to configure fine-grained authentication for administrators. See <a href="#_fine_grain_permissions">Fine grain admin permissions</a>. Also, see the remaining sections in this chapter for other capabilities.</p> </div> <div class="sect4"> <h5 id="advanced-tab"><a class="anchor" href="#advanced-tab"></a>Advanced tab</h5> <div class="paragraph"> <p>When you click the <strong>Advanced</strong> tab, additional fields are displayed. For details on a specific field, click the question mark icon for that field. However, certain fields are described in detail in this section.</p> </div> </div> <div class="sect4"> <h5 id="fine-grain-openid-connect-configuration"><a class="anchor" href="#fine-grain-openid-connect-configuration"></a>Fine grain OpenID Connect configuration</h5> <div class="paragraph"> <p><strong>Logo URL</strong></p> </div> <div class="paragraph"> <p>URL that references a logo for the Client application.</p> </div> <div class="paragraph"> <p><strong>Policy URL</strong></p> </div> <div class="paragraph"> <p>URL that the Relying Party Client provides to the End-User to read about how the profile data will be used.</p> </div> <div class="paragraph"> <p><strong>Terms of Service URL</strong></p> </div> <div class="paragraph"> <p>URL that the Relying Party Client provides to the End-User to read about the Relying Party&#8217;s terms of service.</p> </div> <div id="_jwe-id-token-encryption" class="paragraph"> <p><strong>Signed and Encrypted ID Token Support</strong></p> </div> <div class="paragraph"> <p>Keycloak can encrypt ID tokens according to the <a href="https://datatracker.ietf.org/doc/html/rfc7516">Json Web Encryption (JWE)</a> specification. The administrator determines if ID tokens are encrypted for each client.</p> </div> <div class="paragraph"> <p>The key used for encrypting the ID token is the Content Encryption Key (CEK). Keycloak and a client must negotiate which CEK is used and how it is delivered. The method used to determine the CEK is the Key Management Mode. The Key Management Mode that Keycloak supports is Key Encryption.</p> </div> <div class="paragraph"> <p>In Key Encryption:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>The client generates an asymmetric cryptographic key pair.</p> </li> <li> <p>The public key is used to encrypt the CEK.</p> </li> <li> <p>Keycloak generates a CEK per ID token</p> </li> <li> <p>Keycloak encrypts the ID token using this generated CEK</p> </li> <li> <p>Keycloak encrypts the CEK using the client&#8217;s public key.</p> </li> <li> <p>The client decrypts this encrypted CEK using their private key</p> </li> <li> <p>The client decrypts the ID token using the decrypted CEK.</p> </li> </ol> </div> <div class="paragraph"> <p>No party, other than the client, can decrypt the ID token.</p> </div> <div class="paragraph"> <p>The client must pass its public key for encrypting CEK to Keycloak. Keycloak supports downloading public keys from a URL provided by the client. The client must provide public keys according to the <a href="https://datatracker.ietf.org/doc/html/rfc7517">Json Web Keys (JWK)</a> specification.</p> </div> <div class="paragraph"> <p>The procedure is:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Open the client&#8217;s <strong>Keys</strong> tab.</p> </li> <li> <p>Toggle <strong>JWKS URL</strong> to ON.</p> </li> <li> <p>Input the client&#8217;s public key URL in the <strong>JWKS URL</strong> textbox.</p> </li> </ol> </div> <div class="paragraph"> <p>Key Encryption&#8217;s algorithms are defined in the <a href="https://datatracker.ietf.org/doc/html/rfc7518#section-4.1">Json Web Algorithm (JWA)</a> specification. Keycloak supports:</p> </div> <div class="ulist"> <ul> <li> <p>RSAES-PKCS1-v1_5(RSA1_5)</p> </li> <li> <p>RSAES OAEP using default parameters (RSA-OAEP)</p> </li> <li> <p>RSAES OAEP 256 using SHA-256 and MFG1 (RSA-OAEP-256)</p> </li> </ul> </div> <div class="paragraph"> <p>The procedure to select the algorithm is:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Open the client&#8217;s <strong>Advanced</strong> tab.</p> </li> <li> <p>Open <strong>Fine Grain OpenID Connect Configuration</strong>.</p> </li> <li> <p>Select the algorithm from <strong>ID Token Encryption Content Encryption Algorithm</strong> pulldown menu.</p> </li> </ol> </div> </div> <div class="sect4"> <h5 id="openid-connect-compatibility-modes"><a class="anchor" href="#openid-connect-compatibility-modes"></a>OpenID Connect Compatibility Modes</h5> <div class="paragraph"> <p>This section exists for backward compatibility. Click the question mark icons for details on each field.</p> </div> <div id="_mtls-client-certificate-bound-tokens" class="paragraph"> <p><strong>OAuth 2.0 Mutual TLS Certificate Bound Access Tokens Enabled</strong></p> </div> <div class="paragraph"> <p>Mutual TLS binds an access token and a refresh token together with a client certificate, which is exchanged during a TLS handshake. This binding prevents an attacker from using stolen tokens.</p> </div> <div class="paragraph"> <p>This type of token is a holder-of-key token. Unlike bearer tokens, the recipient of a holder-of-key token can verify if the sender of the token is legitimate.</p> </div> <div class="paragraph"> <p>If this setting is on, the workflow is:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>A token request is sent to the token endpoint in an authorization code flow or hybrid flow.</p> </li> <li> <p>Keycloak requests a client certificate.</p> </li> <li> <p>Keycloak receives the client certificate.</p> </li> <li> <p>Keycloak successfully verifies the client certificate.</p> </li> </ol> </div> <div class="paragraph"> <p>If verification fails, Keycloak rejects the token.</p> </div> <div class="paragraph"> <p>In the following cases, Keycloak will verify the client sending the access token or the refresh token:</p> </div> <div class="ulist"> <ul> <li> <p>A token refresh request is sent to the token endpoint with a holder-of-key refresh token.</p> </li> <li> <p>A UserInfo request is sent to UserInfo endpoint with a holder-of-key access token.</p> </li> <li> <p>A logout request is sent to non-OIDC compliant Keycloak proprietary Logout endpoint with a holder-of-key refresh token.</p> </li> </ul> </div> <div class="paragraph"> <p>See <a href="https://datatracker.ietf.org/doc/html/draft-ietf-oauth-mtls-08#section-3">Mutual TLS Client Certificate Bound Access Tokens</a> in the OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound Access Tokens for more details.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>Keycloak client adapters do not support holder-of-key token verification. Keycloak adapters treat access and refresh tokens as bearer tokens.</p> </div> </td> </tr> </table> </div> <div id="_dpop-bound-tokens" class="paragraph"> <p><strong>OAuth 2.0 Demonstrating Proof-of-Possession at the Application Layer (DPoP)</strong></p> </div> <div class="paragraph"> <p>DPoP binds an access token and a refresh token together with the public part of a client&#8217;s key pair. This binding prevents an attacker from using stolen tokens.</p> </div> <div class="paragraph"> <p>This type of token is a holder-of-key token. Unlike bearer tokens, the recipient of a holder-of-key token can verify if the sender of the token is legitimate.</p> </div> <div class="paragraph"> <p>If the client switch <code>OAuth 2.0 DPoP Bound Access Tokens Enabled</code> is on, the workflow is:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>A token request is sent to the token endpoint in an authorization code flow or hybrid flow.</p> </li> <li> <p>Keycloak requests a DPoP proof.</p> </li> <li> <p>Keycloak receives the DPoP proof.</p> </li> <li> <p>Keycloak successfully verifies the DPoP proof.</p> </li> </ol> </div> <div class="paragraph"> <p>If verification fails, Keycloak rejects the token.</p> </div> <div class="paragraph"> <p>If the switch <code>OAuth 2.0 DPoP Bound Access Tokens Enabled</code> is off, the client can still send <code>DPoP</code> proof in the token request. In that case, Keycloak will verify DPoP proof and will add the thumbprint to the token. But if the switch is off, DPoP binding is not enforced by the Keycloak server for this client. It is recommended to have this switch on if you want to make sure that particular client always uses DPoP binding.</p> </div> <div class="paragraph"> <p>In the following cases, Keycloak will verify the client sending the access token or the refresh token:</p> </div> <div class="ulist"> <ul> <li> <p>A token refresh request is sent to the token endpoint with a holder-of-key refresh token. This verification is done only for public clients as described in the DPoP specification. For confidential clients, the verification is not done as client authentication with proper client credentials is in place to ensure that request comes from the legitimate client. For public clients, both access tokens and refresh tokens are DPoP bound. For confidential clients, only access tokens are DPoP bound.</p> </li> <li> <p>A UserInfo request is sent to UserInfo endpoint with a holder-of-key access token.</p> </li> <li> <p>A logout request is sent to a non-OIDC compliant Keycloak proprietary logout endpoint Logout endpoint with a holder-of-key refresh token. This verification is done only for public clients as described above.</p> </li> </ul> </div> <div class="paragraph"> <p>See <a href="https://datatracker.ietf.org/doc/html/rfc9449">OAuth 2.0 Demonstrating Proof of Possession (DPoP)</a> for more details.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>Keycloak client adapters do not support DPoP holder-of-key token verification. Keycloak adapters treat access and refresh tokens as bearer tokens.</p> </div> </td> </tr> </table> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>DPoP is <strong>Preview</strong> and is not fully supported. This feature is disabled by default.</p> </div> <div class="paragraph"> <p>To enable start the server with <code>--features=preview</code> or <code>--features=dpop</code></p> </div> </td> </tr> </table> </div> <div id="_client_advanced_settings_oidc" class="paragraph"> <p><strong>Advanced Settings for OIDC</strong></p> </div> <div class="paragraph"> <p>The Advanced Settings for OpenID Connect allows you to configure overrides at the client level for <a href="#_timeouts">session and token timeouts</a>.</p> </div> <div class="paragraph"> <p><span class="image"><img src="./images/client-advanced-settings-oidc.png" alt="Advanced Settings"></span></p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 50%;"> <col style="width: 50%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Configuration</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Access Token Lifespan</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The value overrides the realm option with same name.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Client Session Idle</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The value overrides the realm option with same name. The value should be shorter than the global <strong>SSO Session Idle</strong>.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Client Session Max</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The value overrides the realm option with same name. The value should be shorter than the global <strong>SSO Session Max</strong>.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Client Offline Session Idle</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">This setting allows you to configure a shorter offline session idle timeout for the client. The timeout is amount of time the session remains idle before Keycloak revokes its offline token. If not set, realm <a href="#_offline-session-idle">Offline Session Idle</a> is used.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Client Offline Session Max</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">This setting allows you to configure a shorter offline session max lifespan for the client. The lifespan is the maximum time before Keycloak revokes the corresponding offline token. This option needs <a href="#_offline-session-max-limited">Offline Session Max Limited</a> enabled globally in the realm, and defaults to <a href="#_offline-session-max">Offline Session Max</a>.</p></td> </tr> </tbody> </table> <div id="_proof-key-for-code-exchange" class="paragraph"> <p><strong>Proof Key for Code Exchange Code Challenge Method</strong></p> </div> <div class="paragraph"> <p>If an attacker steals an authorization code of a legitimate client, Proof Key for Code Exchange (PKCE) prevents the attacker from receiving the tokens that apply to the code.</p> </div> <div class="paragraph"> <p>An administrator can select one of these options:</p> </div> <div class="dlist"> <dl> <dt class="hdlist1"><strong>(blank)</strong></dt> <dd> <p>Keycloak does not apply PKCE unless the client sends appropriate PKCE parameters to Keycloaks authorization endpoint.</p> </dd> <dt class="hdlist1"><strong>S256</strong></dt> <dd> <p>Keycloak applies to the client PKCE whose code challenge method is S256.</p> </dd> <dt class="hdlist1"><strong>plain</strong></dt> <dd> <p>Keycloak applies to the client PKCE whose code challenge method is plain.</p> </dd> </dl> </div> <div class="paragraph"> <p>See <a href="https://datatracker.ietf.org/doc/html/rfc7636">RFC 7636 Proof Key for Code Exchange by OAuth Public Clients</a> for more details.</p> </div> <div id="_mapping-acr-to-loa-client" class="paragraph"> <p><strong>ACR to Level of Authentication (LoA) Mapping</strong></p> </div> <div class="paragraph"> <p>In the advanced settings of a client, you can define which <code>Authentication Context Class Reference (ACR)</code> value is mapped to which <code>Level of Authentication (LoA)</code>. This mapping can be specified also at the realm as mentioned in the <a href="#_mapping-acr-to-loa-realm">ACR to LoA Mapping</a>. A best practice is to configure this mapping at the realm level, which allows to share the same settings across multiple clients.</p> </div> <div class="paragraph"> <p>The <code>Default ACR Values</code> can be used to specify the default values when the login request is sent from this client to Keycloak without <code>acr_values</code> parameter and without a <code>claims</code> parameter that has an <code>acr</code> claim attached. See <a href="https://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata">official OIDC dynamic client registration specification</a>.</p> </div> <div class="admonitionblock warning"> <table> <tr> <td class="icon"> <i class="fa icon-warning" title="Warning"></i> </td> <td class="content"> Note that default ACR values are used as the default level, however it cannot be reliably used to enforce login with the particular level. For example, assume that you configure the <code>Default ACR Values</code> to level 2. Then by default, users will be required to authenticate with level 2. However when the user explicitly attaches the parameter into login request such as <code>acr_values=1</code>, then the level 1 will be used. As a result, if the client really requires level 2, the client is encouraged to check the presence of the <code>acr</code> claim inside ID Token and double-check that it contains the requested level 2. </td> </tr> </table> </div> <div class="paragraph"> <p><span class="image"><img src="./images/client-oidc-map-acr-to-loa.png" alt="ACR to LoA mapping"></span></p> </div> <div class="paragraph"> <p>For further details see <a href="#_step-up-flow">Step-up Authentication</a> and <a href="https://openid.net/specs/openid-connect-core-1_0.html#acrSemantics">the official OIDC specification</a>.</p> </div> </div> </div> <div class="sect3"> <h4 id="_client-credentials"><a class="anchor" href="#_client-credentials"></a>Confidential client credentials</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/clients/oidc/con-confidential-client-credentials.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/clients/oidc/con-confidential-client-credentials.adoc&amp;description=%0A%0AFile:%20server_admin/topics/clients/oidc/con-confidential-client-credentials.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>If the <a href="#_access-type">Client authentication</a> of the client is set to <strong>ON</strong>, the credentials of the client must be configured under the <strong>Credentials</strong> tab.</p> </div> <div class="paragraph"> <div class="title">Credentials tab</div> <p><span class="image"><img src="./images/client-credentials.png" alt="Credentials Tab"></span></p> </div> <div class="paragraph"> <p>The <strong>Client Authenticator</strong> drop-down list specifies the type of credential to use for your client.</p> </div> <div class="paragraph"> <p><strong>Client ID and Secret</strong></p> </div> <div class="paragraph"> <p>This choice is the default setting. The secret is automatically generated. Click <strong>Regenerate</strong> to recreate the secret if necessary.</p> </div> <div class="paragraph"> <div class="title">Signed JWT</div> <p><span class="image"><img src="./images/client-credentials-jwt.png" alt="Signed JWT"></span></p> </div> <div class="paragraph"> <p><strong>Signed JWT</strong> is "Signed Json Web Token".</p> </div> <div class="paragraph"> <p>When choosing this credential type you will have to also generate a private key and certificate for the client in the tab <code>Keys</code>. The private key will be used to sign the JWT, while the certificate is used by the server to verify the signature.</p> </div> <div class="paragraph"> <div class="title">Keys tab</div> <p><span class="image"><img src="./images/client-oidc-keys.png" alt="Keys tab"></span></p> </div> <div class="paragraph"> <p>Click on the <code>Generate new keys</code> button to start this process.</p> </div> <div class="paragraph"> <div class="title">Generate keys</div> <p><span class="image"><img src="./images/generate-client-keys.png" alt="generate client keys"></span></p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Select the archive format you want to use.</p> </li> <li> <p>Enter a <strong>key password</strong>.</p> </li> <li> <p>Enter a <strong>store password</strong>.</p> </li> <li> <p>Click <strong>Generate</strong>.</p> </li> </ol> </div> <div class="paragraph"> <p>When you generate the keys, Keycloak will store the certificate and you download the private key and certificate for your client.</p> </div> <div class="paragraph"> <p>You can also generate keys using an external tool and then import the client&#8217;s certificate by clicking <strong>Import Certificate</strong>.</p> </div> <div class="paragraph"> <div class="title">Import certificate</div> <p><span class="image"><img src="./images/import-client-cert.png" alt="Import Certificate"></span></p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Select the archive format of the certificate.</p> </li> <li> <p>Enter the store password.</p> </li> <li> <p>Select the certificate file by clicking <strong>Import File</strong>.</p> </li> <li> <p>Click <strong>Import</strong>.</p> </li> </ol> </div> <div class="paragraph"> <p>Importing a certificate is unnecessary if you click <strong>Use JWKS URL</strong>. In this case, you can provide the URL where the public key is published in <a href="https://datatracker.ietf.org/doc/html/rfc7517">JWK</a> format. With this option, if the key is ever changed, Keycloak reimports the key.</p> </div> <div class="paragraph"> <p>If you are using a client secured by Keycloak adapter, you can configure the JWKS URL in this format, assuming that <a href="https://myhost.com/myapp" class="bare">https://myhost.com/myapp</a> is the root URL of your client application:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">https://myhost.com/myapp/k_jwks</code></pre> </div> </div> <div class="paragraph"> <p>See <a href="https://www.keycloak.org/docs/26.0.6/server_development/">Server Developer Guide</a> for more details.</p> </div> <div class="paragraph"> <p><strong>Signed JWT with Client Secret</strong></p> </div> <div class="paragraph"> <p>If you select this option, you can use a JWT signed by client secret instead of the private key.</p> </div> <div class="paragraph"> <p>The client secret will be used to sign the JWT by the client.</p> </div> <div class="paragraph"> <p><strong>X509 Certificate</strong></p> </div> <div class="paragraph"> <p>Keycloak will validate if the client uses proper X509 certificate during the TLS Handshake.</p> </div> <div class="paragraph"> <div class="title">X509 certificate</div> <p><span class="image"><img src="./images/x509-client-auth.png" alt="x509 client auth"></span></p> </div> <div class="paragraph"> <p>The validator also checks the Subject DN field of the certificate with a configured regexp validation expression. For some use cases, it is sufficient to accept all certificates. In that case, you can use <code>(.*?)(?:$)</code> expression.</p> </div> <div class="paragraph"> <p>Two ways exist for Keycloak to obtain the Client ID from the request:</p> </div> <div class="ulist"> <ul> <li> <p>The <code>client_id</code> parameter in the query (described in Section 2.2 of the <a href="https://datatracker.ietf.org/doc/html/rfc6749">OAuth 2.0 Specification</a>).</p> </li> <li> <p>Supply <code>client_id</code> as a form parameter.</p> </li> </ul> </div> </div> <div class="sect3"> <h4 id="_secret_rotation"><a class="anchor" href="#_secret_rotation"></a>Client Secret Rotation</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/clients/oidc/con-secret-rotation.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/clients/oidc/con-secret-rotation.adoc&amp;description=%0A%0AFile:%20server_admin/topics/clients/oidc/con-secret-rotation.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="admonitionblock important _abstract"> <table> <tr> <td class="icon"> <i class="fa icon-important" title="Important"></i> </td> <td class="content"> <div class="paragraph"> <p>Please note that Client Secret Rotation support is in development. Use this feature experimentally.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>For a client with <a href="#_client-credentials">Confidential</a> <a href="#_access-type">Client authentication</a> Keycloak supports the functionality of rotating client secrets through <a href="#_client_policies">Client Policies</a>.</p> </div> <div class="paragraph"> <p>The client secrets rotation policy provides greater security in order to alleviate problems such as secret leakage. Once enabled, Keycloak supports up to two concurrently active secrets for each client. The policy manages rotations according to the following settings:</p> </div> <div class="ulist"> <ul> <li> <p><strong>Secret expiration:</strong> [seconds] - When the secret is rotated, this is the expiration of time of the new secret. The amount, <em>in seconds</em>, added to the secret creation date. Calculated at policy execution time.</p> </li> <li> <p><strong>Rotated secret expiration:</strong> [seconds] - When the secret is rotated, this value is the remaining expiration time for the old secret. This value should be always smaller than Secret expiration. When the value is 0, the old secret will be immediately removed during client rotation. The amount, <em>in seconds</em>, added to the secret rotation date. Calculated at policy execution time.</p> </li> <li> <p><strong>Remaining expiration time for rotation during update:</strong> [seconds] - Time period when an update to a dynamic client should perform client secret rotation. Calculated at policy execution time.</p> </li> </ul> </div> <div class="paragraph"> <p>When a client secret rotation occurs, a new main secret is generated and the old client main secret becomes the secondary secret with a new expiration date.</p> </div> <div class="sect4"> <h5 id="rules-for-client-secret-rotation"><a class="anchor" href="#rules-for-client-secret-rotation"></a>Rules for client secret rotation</h5> <div class="paragraph"> <p>Rotations do not occur automatically or through a background process. In order to perform the rotation, an update action is required on the client, either through the Keycloak Admin Console through the function of <strong>Regenerate Secret</strong>, in the client&#8217;s credentials tab or Admin REST API. When invoking a client update action, secret rotation occurs according to the rules:</p> </div> <div class="ulist"> <ul> <li> <p>When the value of <strong>Secret expiration</strong> is less than the current date.</p> </li> <li> <p>During dynamic client registration client-update request, the client secret will be automatically rotated if the value of <strong>Remaining expiration time for rotation during update</strong> match the period between the current date and the <strong>Secret expiration</strong>.</p> </li> </ul> </div> <div class="paragraph"> <p>Additionally it is possible through Admin REST API to force a client secret rotation at any time.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>During the creation of new clients, if the client secret rotation policy is active, the behavior will be applied automatically.</p> </div> </td> </tr> </table> </div> <div class="admonitionblock warning"> <table> <tr> <td class="icon"> <i class="fa icon-warning" title="Warning"></i> </td> <td class="content"> To apply the secret rotation behavior to an existing client, update that client after you define the policy so that the behavior is applied. </td> </tr> </table> </div> </div> </div> <div class="sect3"> <h4 id="_proc-secret-rotation"><a class="anchor" href="#_proc-secret-rotation"></a>Creating an OIDC Client Secret Rotation Policy</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/clients/oidc/proc-secret-rotation.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/clients/oidc/proc-secret-rotation.adoc&amp;description=%0A%0AFile:%20server_admin/topics/clients/oidc/proc-secret-rotation.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>The following is an example of defining a secret rotation policy:</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Realm Settings</strong> in the menu.</p> </li> <li> <p>Click <strong>Client Policies</strong> tab.</p> </li> <li> <p>On the <strong>Profiles</strong> page, click <strong>Create client profile</strong>.</p> <div class="paragraph"> <div class="title">Create a profile</div> <p><span class="image"><img src="./images/create-oidc-client-profile.png" alt="Create Client Profile"></span></p> </div> </li> <li> <p>Enter any name for <strong>Name</strong>.</p> </li> <li> <p>Enter a description that helps you identify the purpose of the profile for <strong>Description</strong>.</p> </li> <li> <p>Click <strong>Save</strong>.</p> <div class="paragraph"> <p>This action creates the profile and enables you to configure executors.</p> </div> </li> <li> <p>Click <strong>Add executor</strong> to configure an executor for this profile.</p> <div class="paragraph"> <div class="title">Create a profile executor</div> <p><span class="image"><img src="./images/create-oidc-client-secret-rotation-executor.png" alt="Client Profile Executor"></span></p> </div> </li> <li> <p>Select <em>secret-rotation</em> for <strong>Executor Type</strong>.</p> </li> <li> <p>Enter the maximum duration time of each secret, in seconds, for <strong>Secret Expiration</strong>.</p> </li> <li> <p>Enter the maximum duration time of each rotated secret, in seconds, for <strong>Rotated Secret Expiration</strong>.</p> <div class="admonitionblock warning"> <table> <tr> <td class="icon"> <i class="fa icon-warning" title="Warning"></i> </td> <td class="content"> Remember that the <strong>Rotated Secret Expiration</strong> value must always be less than <strong>Secret Expiration</strong>. </td> </tr> </table> </div> </li> <li> <p>Enter the amount of time, in seconds, after which any update action will update the client for <strong>Remain Expiration Time</strong>.</p> </li> <li> <p>Click <strong>Add</strong>.</p> <div class="exampleblock"> <div class="content"> <div class="paragraph"> <p>In the example above:</p> </div> <div class="ulist"> <ul> <li> <p>Each secret is valid for one week.</p> </li> <li> <p>The rotated secret expires after two days.</p> </li> <li> <p>The window for updating dynamic clients starts one day before the secret expires.</p> </li> </ul> </div> </div> </div> </li> <li> <p>Return to the <strong>Client Policies</strong> tab.</p> </li> <li> <p>Click <strong>Policies</strong>.</p> </li> <li> <p>Click <strong>Create client policy</strong>.</p> <div class="paragraph"> <div class="title">Create the Client Secret Rotation Policy</div> <p><span class="image"><img src="./images/create-oidc-client-secret-rotation-policy.png" alt="Client Rotation Policy"></span></p> </div> </li> <li> <p>Enter any name for <strong>Name</strong>.</p> </li> <li> <p>Enter a description that helps you identify the purpose of the policy for <strong>Description</strong>.</p> </li> <li> <p>Click <strong>Save</strong>.</p> <div class="paragraph"> <p>This action creates the policy and enables you to associate policies with profiles. It also allows you to configure the conditions for policy execution.</p> </div> </li> <li> <p>Under Conditions, click <strong>Add condition</strong>.</p> <div class="paragraph"> <div class="title">Create the Client Secret Rotation Policy Condition</div> <p><span class="image"><img src="./images/create-oidc-client-secret-rotation-condition.png" alt="Client Rotation Policy Condition"></span></p> </div> </li> <li> <p>To apply the behavior to all confidential clients select <em>client-access-type</em> in the <strong>Condition Type</strong> field</p> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>To apply to a specific group of clients, another approach would be to select the <em>client-roles</em> type in the <strong>Condition Type</strong> field. In this way, you could create specific roles and assign a custom rotation configuration to each role.</p> </div> </td> </tr> </table> </div> </li> <li> <p>Add <em>confidential</em> to the field <strong>Client Access Type</strong>.</p> </li> <li> <p>Click <strong>Add</strong>.</p> </li> <li> <p>Back in the policy setting, under <em>Client Profiles</em>, click <strong>Add client profile</strong> and then select <strong>Weekly Client Secret Rotation Profile</strong> from the list and then click <strong>Add</strong>.</p> <div class="paragraph"> <div class="title">Client Secret Rotation Policy</div> <p><span class="image"><img src="./images/oidc-client-secret-rotation-policy.png" alt="Client Rotation Policy"></span></p> </div> </li> </ol> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>To apply the secret rotation behavior to an existing client, follow the following steps:</p> </div> <div class="olist arabic"> <div class="title">Using the Admin Console</div> <ol class="arabic"> <li> <p>Click <strong>Clients</strong> in the menu.</p> </li> <li> <p>Click a client.</p> </li> <li> <p>Click the <strong>Credentials</strong> tab.</p> </li> <li> <p>Click <strong>Re-generate</strong> of the client secret.</p> </li> </ol> </div> </td> </tr> </table> </div> <hr> <div class="ulist"> <div class="title">Using client REST services it can be executed in two ways:</div> <ul> <li> <p>Through an update operation on a client</p> </li> <li> <p>Through the regenerate client secret endpoint</p> </li> </ul> </div> </div> <div class="sect3"> <h4 id="_service_accounts"><a class="anchor" href="#_service_accounts"></a>Using a service account</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/clients/oidc/proc-using-a-service-account.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/clients/oidc/proc-using-a-service-account.adoc&amp;description=%0A%0AFile:%20server_admin/topics/clients/oidc/proc-using-a-service-account.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>Each OIDC client has a built-in <em>service account</em>. Use this <em>service account</em> to obtain an access token.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Clients</strong> in the menu.</p> </li> <li> <p>Select your client.</p> </li> <li> <p>Click the <strong>Settings</strong> tab.</p> </li> <li> <p>Toggle <a href="#_access-type">Client authentication</a> to <strong>On</strong>.</p> </li> <li> <p>Select <strong>Service accounts roles</strong>.</p> </li> <li> <p>Click <strong>Save</strong>.</p> </li> <li> <p>Configure your <a href="#_client-credentials">client credentials</a>.</p> </li> <li> <p>Click the <strong>Scope</strong> tab.</p> </li> <li> <p>Verify that you have roles or toggle <strong>Full Scope Allowed</strong> to <strong>ON</strong>.</p> </li> <li> <p>Click the <strong>Service Account Roles</strong> tab</p> </li> <li> <p>Configure the roles available to this service account for your client.</p> </li> </ol> </div> <div class="paragraph"> <p>Roles from access tokens are the intersection of:</p> </div> <div class="ulist"> <ul> <li> <p>Role scope mappings of a client combined with the role scope mappings inherited from linked client scopes.</p> </li> <li> <p>Service account roles.</p> </li> </ul> </div> <div class="paragraph"> <p>The REST URL to invoke is <code>/realms/{realm-name}/protocol/openid-connect/token</code>. This URL must be invoked as a POST request and requires that you post the client credentials with the request.</p> </div> <div class="paragraph"> <p>By default, client credentials are represented by the clientId and clientSecret of the client in the <strong>Authorization: Basic</strong> header but you can also authenticate the client with a signed JWT assertion or any other custom mechanism for client authentication.</p> </div> <div class="paragraph"> <p>You also need to set the <strong>grant_type</strong> parameter to "client_credentials" as per the OAuth2 specification.</p> </div> <div class="paragraph"> <p>For example, the POST invocation to retrieve a service account can look like this:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code> POST /realms/demo/protocol/openid-connect/token Authorization: Basic cHJvZHVjdC1zYS1jbGllbnQ6cGFzc3dvcmQ= Content-Type: application/x-www-form-urlencoded grant_type=client_credentials</code></pre> </div> </div> <div class="paragraph"> <p>The response would be similar to this <a href="https://datatracker.ietf.org/doc/html/rfc6749#section-4.4.3">Access Token Response</a> from the OAuth 2.0 specification.</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Cache-Control: no-store Pragma: no-cache { "access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"bearer", "expires_in":60 }</code></pre> </div> </div> <div class="paragraph"> <p>Only the access token is returned by default. No refresh token is returned and no user session is created on the Keycloak side upon successful authentication by default. Due to the lack of a refresh token, re-authentication is required when the access token expires. However, this situation does not mean any additional overhead for the Keycloak server because sessions are not created by default.</p> </div> <div class="paragraph"> <p>In this situation, logout is unnecessary. However, issued access tokens can be revoked by sending requests to the OAuth2 Revocation Endpoint as described in the <a href="#con-oidc_server_administration_guide">OpenID Connect Endpoints</a> section.</p> </div> <div class="paragraph _additional-resources"> <div class="title">Additional resources</div> <p>For more details, see <a href="#_client_credentials_grant">Client Credentials Grant</a>.</p> </div> </div> <div class="sect3"> <h4 id="audience-support"><a class="anchor" href="#audience-support"></a>Audience support</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/clients/oidc/con-audience.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/clients/oidc/con-audience.adoc&amp;description=%0A%0AFile:%20server_admin/topics/clients/oidc/con-audience.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>Typically, the environment where Keycloak is deployed consists of a set of <em>confidential</em> or <em>public</em> client applications that use Keycloak for authentication.</p> </div> <div class="paragraph"> <p><em>Services</em> (<em>Resource Servers</em> in the <a href="https://datatracker.ietf.org/doc/html/draft-ietf-oauth-mtls-08#section-4.2">OAuth 2 specification</a>) are also available that serve requests from client applications and provide resources to these applications. These services require an <em>Access token</em> (Bearer token) to be sent to them to authenticate a request. This token is obtained by the frontend application upon login to Keycloak.</p> </div> <div class="paragraph"> <p>In the environment where trust among services is low, you may encounter this scenario:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>A frontend client application requires authentication against Keycloak.</p> </li> <li> <p>Keycloak authenticates a user.</p> </li> <li> <p>Keycloak issues a token to the application.</p> </li> <li> <p>The application uses the token to invoke an untrusted service.</p> </li> <li> <p>The untrusted service returns the response to the application. However, it keeps the applications token.</p> </li> <li> <p>The untrusted service then invokes a trusted service using the applications token. This results in broken security as the untrusted service misuses the token to access other services on behalf of the client application.</p> </li> </ol> </div> <div class="paragraph"> <p>This scenario is unlikely in environments with a high level of trust between services but not in environments where trust is low. In some environments, this workflow may be correct as the untrusted service may have to retrieve data from a trusted service to return data to the original client application.</p> </div> <div class="paragraph"> <p>An unlimited audience is useful when a high level of trust exists between services. Otherwise, the audience should be limited. You can limit the audience and, at the same time, allow untrusted services to retrieve data from trusted services. In this case, ensure that the untrusted service and the trusted service are added as audiences to the token.</p> </div> <div class="paragraph"> <p>To prevent any misuse of the access token, limit the audience on the token and configure your services to verify the audience on the token. The flow will change as follows:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>A frontend application authenticates against Keycloak.</p> </li> <li> <p>Keycloak authenticates a user.</p> </li> <li> <p>Keycloak issues a token to the application. The application knows that it will need to invoke an untrusted service so it places <strong>scope=&lt;untrusted service&gt;</strong> in the authentication request sent to Keycloak (see <a href="#_client_scopes">Client Scopes section</a> for more details about the <em>scope</em> parameter).</p> <div class="paragraph"> <p>The token issued to the application contains a reference to the untrusted service in its audience (<strong>"audience": [ "&lt;untrusted service&gt;" ]</strong>) which declares that the client uses this access token to invoke the untrusted service.</p> </div> </li> <li> <p>The untrusted service invokes a trusted service with the token. Invocation is not successful because the trusted service checks the audience on the token and find that its audience is only for the untrusted service. This behavior is expected and security is not broken.</p> </li> </ol> </div> <div class="paragraph"> <p>If the client wants to invoke the trusted service later, it must obtain another token by reissuing the SSO login with <strong>scope=&lt;trusted service&gt;</strong>. The returned token will then contain the trusted service as an audience:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="json"><span class="key"><span class="delimiter">&quot;</span><span class="content">audience</span><span class="delimiter">&quot;</span></span>: [ <span class="string"><span class="delimiter">&quot;</span><span class="content">&lt;trusted service&gt;</span><span class="delimiter">&quot;</span></span> ]</code></pre> </div> </div> <div class="paragraph"> <p>Use this value to invoke the <strong>&lt;trusted service&gt;</strong>.</p> </div> <div class="sect4"> <h5 id="setup-5"><a class="anchor" href="#setup-5"></a>Setup</h5> <div class="paragraph"> <p>When setting up audience checking:</p> </div> <div class="ulist"> <ul> <li> <p>Ensure that services are configured to check audience on the access token sent to them. This may be done in a way specific to your client OIDC adapter, which you are using to secure your OIDC client application.</p> </li> <li> <p>Ensure that access tokens issued by Keycloak contain all necessary audiences. Audiences can be added using the client roles as described in the <a href="#_audience_resolve">next section</a> or hardcoded. See <a href="#_audience_hardcoded">Hardcoded audience</a>.</p> </li> </ul> </div> </div> <div class="sect4"> <h5 id="_audience_resolve"><a class="anchor" href="#_audience_resolve"></a>Automatically add audience</h5> <div class="paragraph"> <p>An <em>Audience Resolve</em> protocol mapper is defined in the default client scope <em>roles</em>. The mapper checks for clients that have at least one client role available for the current token. The client ID of each client is then added as an audience, which is useful if your service clients rely on client roles. Service client could be usually a client without any flows enabled, which may not have any tokens issued directly to itself. It represents an OAuth 2 <em>Resource Server</em>.</p> </div> <div class="paragraph"> <p>For example, for a service client and a confidential client, you can use the access token issued for the confidential client to invoke the service client REST service. The service client will be automatically added as an audience to the access token issued for the confidential client if the following are true:</p> </div> <div class="ulist"> <ul> <li> <p>The service client has any client roles defined on itself.</p> </li> <li> <p>Target user has at least one of those client roles assigned.</p> </li> <li> <p>Confidential client has the role scope mappings for the assigned role.</p> </li> </ul> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>If you want to ensure that the audience is not added automatically, do not configure role scope mappings directly on the confidential client. Instead, you can create a dedicated client scope that contains the role scope mappings for the client roles of your dedicated client scope.</p> </div> <div class="paragraph"> <p>Assuming that the client scope is added as an optional client scope to the confidential client, the client roles and the audience will be added to the token if explicitly requested by the <strong>scope=&lt;trusted service&gt;</strong> parameter.</p> </div> </td> </tr> </table> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>The frontend client itself is not automatically added to the access token audience, therefore allowing easy differentiation between the access token and the ID token, since the access token will not contain the client for which the token is issued as an audience.</p> </div> <div class="paragraph"> <p>If you need the client itself as an audience, see the <a href="#_audience_hardcoded">hardcoded audience</a> option. However, using the same client as both frontend and REST service is not recommended.</p> </div> </td> </tr> </table> </div> </div> <div class="sect4"> <h5 id="_audience_hardcoded"><a class="anchor" href="#_audience_hardcoded"></a>Hardcoded audience</h5> <div class="paragraph"> <p>When your service relies on realm roles or does not rely on the roles in the token at all, it can be useful to use a hardcoded audience. A hardcoded audience is a protocol mapper, that will add the client ID of the specified service client as an audience to the token. You can use any custom value, for example a URL, if you want to use a different audience than the client ID.</p> </div> <div class="paragraph"> <p>You can add the protocol mapper directly to the frontend client. If the protocol mapper is added directly, the audience will always be added as well.</p> </div> <div class="paragraph"> <p>For more control over the protocol mapper, you can create the protocol mapper on the dedicated client scope, which will be called for example <strong>good-service</strong>.</p> </div> <div class="paragraph"> <div class="title">Audience protocol mapper</div> <p><span class="image"><img src="./images/audience_mapper.png" alt="audience mapper"></span></p> </div> <div class="ulist"> <ul> <li> <p>From the <a href="#_client_installation">Client details tab</a> of the <strong>good-service</strong> client, you can generate the adapter configuration and confirm that <em>verify-token-audience</em> is set to <strong>true</strong>. This action forces the adapter to verify the audience if you use this configuration.</p> </li> <li> <p>You need to ensure that the confidential client is able to request <strong>good-service</strong> as an audience in its tokens.</p> <div class="paragraph"> <p>On the confidential client:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Click the <em>Client Scopes</em> tab.</p> </li> <li> <p>Assign <strong>good-service</strong> as an optional (or default) client scope.</p> <div class="paragraph"> <p>See <a href="#_client_scopes_linking">Client Scopes Linking section</a> for more details.</p> </div> </li> </ol> </div> </li> <li> <p>You can optionally <a href="#_client_scopes_evaluate">Evaluate Client Scopes</a> and generate an example access token. <strong>good-service</strong> will be added to the audience of the generated access token if <strong>good-service</strong> is included in the <em>scope</em> parameter, when you assigned it as an optional client scope.</p> </li> <li> <p>In your confidential client application, ensure that the <em>scope</em> parameter is used. The value <strong>good-service</strong> must be included when you want to issue the token for accessing <strong>good-service</strong>.</p> <div class="paragraph"> <p>See:</p> </div> <div class="ulist"> <ul> <li> <p><strong>Keycloak JavaScript adapter</strong> in the <a href="https://www.keycloak.org/guides#securing-apps">securing apps</a> section if your application uses the javascript adapter.</p> </li> </ul> </div> </li> </ul> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> Both the <em>Audience</em> and <em>Audience Resolve</em> protocol mappers add the audiences to the access token only, by default. The ID Token typically contains only a single audience, the client ID for which the token was issued, a requirement of the OpenID Connect specification. However, the access token does not necessarily have the client ID, which was the token issued for, unless the audience mappers added it. </td> </tr> </table> </div> </div> </div> </div> <div class="sect2"> <h3 id="_client-saml-configuration"><a class="anchor" href="#_client-saml-configuration"></a>Creating a SAML client</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/clients/saml/proc-creating-saml-client.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/clients/saml/proc-creating-saml-client.adoc&amp;description=%0A%0AFile:%20server_admin/topics/clients/saml/proc-creating-saml-client.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>Keycloak supports <a href="#_saml">SAML 2.0</a> for registered applications. POST and Redirect bindings are supported. You can choose to require client signature validation. You can have the server sign and/or encrypt responses as well.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Clients</strong> in the menu.</p> </li> <li> <p>Click <strong>Create client</strong> to go to the <strong>Create client</strong> page.</p> </li> <li> <p>Set <strong>Client type</strong> to <strong>SAML</strong>.</p> <div class="paragraph"> <div class="title">Create client</div> <p><span class="image"><img src="./images/add-client-saml.png" alt="add client saml"></span></p> </div> </li> <li> <p>Enter the <strong>Client ID</strong> of the client. This is often a URL and is the expected <strong>issuer</strong> value in SAML requests sent by the application.</p> </li> <li> <p>Click <strong>Save</strong>. This action creates the client and brings you to the <strong>Settings</strong> tab.</p> </li> </ol> </div> <div class="paragraph"> <p>The following sections describe each setting on this tab.</p> </div> <div class="sect3"> <h4 id="settings-tab"><a class="anchor" href="#settings-tab"></a>Settings tab</h4> <div class="paragraph"> <p>The <strong>Settings</strong> tab includes many options to configure this client.</p> </div> <div class="paragraph"> <div class="title">Client settings</div> <p><span class="image"><img src="./images/client-settings-saml.png" alt="client settings saml"></span></p> </div> <div class="sect4"> <h5 id="general-settings-2"><a class="anchor" href="#general-settings-2"></a>General settings</h5> <div class="dlist"> <dl> <dt class="hdlist1"><strong>Client ID</strong></dt> <dd> <p>The alphanumeric ID string that is used in OIDC requests and in the Keycloak database to identify the client. This value must match the issuer value sent with AuthNRequests. Keycloak pulls the issuer from the Authn SAML request and match it to a client by this value.</p> </dd> <dt class="hdlist1"><strong>Name</strong></dt> <dd> <p>The name for the client in a Keycloak UI screen. To localize the name, set up a replacement string value. For example, a string value such as ${myapp}. See the <a href="https://www.keycloak.org/docs/26.0.6/server_development/">Server Developer Guide</a> for more information.</p> </dd> <dt class="hdlist1"><strong>Description</strong></dt> <dd> <p>The description of the client. This setting can also be localized.</p> </dd> </dl> </div> <div class="dlist"> <dl> <dt class="hdlist1"><strong>Always Display in Console</strong></dt> <dd> <p>Always list this client in the Account Console even if this user does not have an active session.</p> </dd> </dl> </div> </div> <div class="sect4"> <h5 id="access-settings-2"><a class="anchor" href="#access-settings-2"></a>Access Settings</h5> <div class="dlist"> <dl> <dt class="hdlist1"><strong>Root URL</strong></dt> <dd> <p>When Keycloak uses a configured relative URL, this value is prepended to the URL.</p> </dd> <dt class="hdlist1"><strong>Home URL</strong></dt> <dd> <p>If Keycloak needs to link to a client, this URL is used.</p> </dd> <dt class="hdlist1"><strong>Valid Redirect URIs</strong></dt> <dd> <p>Enter a URL pattern and click the + sign to add. Click the - sign to remove. Click <strong>Save</strong> to save these changes. Wildcards values are allowed only at the end of a URL. For example, <a href="http://host.com/*$$" class="bare">http://host.com/*$$</a>. This field is used when the exact SAML endpoints are not registered and Keycloak pulls the Assertion Consumer URL from a request.</p> </dd> <dt class="hdlist1"><strong>IDP-Initiated SSO URL name</strong></dt> <dd> <p>URL fragment name to reference client when you want to do IDP Initiated SSO. Leaving this empty will disable IDP Initiated SSO. The URL you will reference from your browser will be: <em>server-root</em>/realms/{realm}/protocol/saml/clients/{client-url-name}</p> </dd> <dt class="hdlist1"><strong>IDP Initiated SSO Relay State</strong></dt> <dd> <p>Relay state you want to send with SAML request when you want to do IDP Initiated SSO.</p> </dd> <dt class="hdlist1"><strong>Master SAML Processing URL</strong></dt> <dd> <p>This URL is used for all SAML requests and the response is directed to the SP. It is used as the Assertion Consumer Service URL and the Single Logout Service URL.</p> <div class="paragraph"> <p>If login requests contain the Assertion Consumer Service URL then those login requests will take precedence. This URL must be validated by a registered Valid Redirect URI pattern.</p> </div> </dd> </dl> </div> </div> <div class="sect4"> <h5 id="saml-capabilities"><a class="anchor" href="#saml-capabilities"></a>SAML capabilities</h5> <div class="dlist"> <dl> <dt class="hdlist1"><strong>Name ID Format</strong></dt> <dd> <p>The Name ID Format for the subject. This format is used if no name ID policy is specified in a request, or if the Force Name ID Format attribute is set to ON.</p> </dd> <dt class="hdlist1"><strong>Force Name ID Format</strong></dt> <dd> <p>If a request has a name ID policy, ignore it and use the value configured in the Admin Console under <strong>Name ID Format</strong>.</p> </dd> <dt class="hdlist1"><strong>Force POST Binding</strong></dt> <dd> <p>By default, Keycloak responds using the initial SAML binding of the original request. By enabling <strong>Force POST Binding</strong>, Keycloak responds using the SAML POST binding even if the original request used the redirect binding.</p> </dd> <dt class="hdlist1"><strong>Force artifact binding</strong></dt> <dd> <p>If enabled, response messages are returned to the client through the SAML ARTIFACT binding system.</p> </dd> <dt class="hdlist1"><strong>Include AuthnStatement</strong></dt> <dd> <p>SAML login responses may specify the authentication method used, such as password, as well as timestamps of the login and the session expiration. <strong>Include AuthnStatement</strong> is enabled by default, so that the <strong>AuthnStatement</strong> element will be included in login responses. Setting this to OFF prevents clients from determining the maximum session length, which can create client sessions that do not expire.</p> </dd> <dt class="hdlist1"><strong>Include OneTimeUse Condition</strong></dt> <dd> <p>If enable, a OneTimeUse Condition is included in login responses.</p> </dd> <dt class="hdlist1"><strong>Optimize REDIRECT signing key lookup</strong></dt> <dd> <p>When set to ON, the SAML protocol messages include the Keycloak native extension. This extension contains a hint with the signing key ID. The SP uses the extension for signature validation instead of attempting to validate the signature using keys.</p> <div class="paragraph"> <p>This option applies to REDIRECT bindings where the signature is transferred in query parameters and this information is not found in the signature information. This is contrary to POST binding messages where key ID is always included in document signature.</p> </div> <div class="paragraph"> <p>This option is used when Keycloak server and adapter provide the IDP and SP. This option is only relevant when <strong>Sign Documents</strong> is set to ON.</p> </div> </dd> </dl> </div> </div> <div class="sect4"> <h5 id="signature-and-encryption"><a class="anchor" href="#signature-and-encryption"></a>Signature and Encryption</h5> <div class="dlist"> <dl> <dt class="hdlist1"><strong>Sign Documents</strong></dt> <dd> <p>When set to ON, Keycloak signs the document using the realms private key.</p> </dd> <dt class="hdlist1"><strong>Sign Assertions</strong></dt> <dd> <p>The assertion is signed and embedded in the SAML XML Auth response.</p> </dd> <dt class="hdlist1"><strong>Signature Algorithm</strong></dt> <dd> <p>The algorithm used in signing SAML documents. Note that <code>SHA1</code> based algorithms are deprecated and may be removed in a future release. We recommend the use of some more secure algorithm instead of <code>*_SHA1</code>. Also, with <code>*_SHA1</code> algorithms, verifying signatures do not work if the SAML client runs on Java 17 or higher.</p> </dd> <dt class="hdlist1"><strong>SAML Signature Key Name</strong></dt> <dd> <p>Signed SAML documents sent using POST binding contain the identification of the signing key in the <strong>KeyName</strong> element. This action can be controlled by the <strong>SAML Signature Key Name</strong> option. This option controls the contents of the <strong>Keyname</strong>.</p> <div class="openblock"> <div class="content"> <div class="ulist"> <ul> <li> <p><strong>KEY_ID</strong> The <strong>KeyName</strong> contains the key ID. This option is the default option.</p> </li> <li> <p><strong>CERT_SUBJECT</strong> The <strong>KeyName</strong> contains the subject from the certificate corresponding to the realm key. This option is expected by Microsoft Active Directory Federation Services.</p> </li> <li> <p><strong>NONE</strong> The <strong>KeyName</strong> hint is completely omitted from the SAML message.</p> </li> </ul> </div> </div> </div> </dd> <dt class="hdlist1"><strong>Canonicalization Method</strong></dt> <dd> <p>The canonicalization method for XML signatures.</p> </dd> </dl> </div> </div> <div class="sect4"> <h5 id="login-settings-2"><a class="anchor" href="#login-settings-2"></a>Login settings</h5> <div class="dlist"> <dl> <dt class="hdlist1"><strong>Login theme</strong></dt> <dd> <p>A theme to use for login, OTP, grant registration, and forgotten password pages.</p> </dd> <dt class="hdlist1"><strong>Consent required</strong></dt> <dd> <p>If enabled, users have to consent to client access.</p> <div class="paragraph"> <p>For client-side clients that perform browser logins. As it is not possible to ensure that secrets can be kept safe with client-side clients, it is important to restrict access by configuring correct redirect URIs.</p> </div> </dd> <dt class="hdlist1"><strong>Display client on screen</strong></dt> <dd> <p>This switch applies if <strong>Consent Required</strong> is <strong>Off</strong>.</p> <div class="ulist"> <ul> <li> <p><em>Off</em></p> <div class="paragraph"> <p>The consent screen will contain only the consents corresponding to configured client scopes.</p> </div> </li> <li> <p><em>On</em></p> <div class="paragraph"> <p>There will be also one item on the consent screen about this client itself.</p> </div> </li> </ul> </div> </dd> <dt class="hdlist1"><strong>Client consent screen text</strong></dt> <dd> <p>Applies if <strong>Consent required</strong> and <strong>Display client on screen</strong> are enabled. Contains the text that will be on the consent screen about permissions for this client.</p> </dd> </dl> </div> </div> <div class="sect4"> <h5 id="logout-settings-2"><a class="anchor" href="#logout-settings-2"></a>Logout settings</h5> <div class="dlist"> <dl> <dt class="hdlist1"><strong>Front channel logout</strong></dt> <dd> <p>If <strong>Front Channel Logout</strong> is enabled, the application requires a browser redirect to perform a logout. For example, the application may require a cookie to be reset which could only be done via a redirect. If <strong>Front Channel Logout</strong> is disabled, Keycloak invokes a background SAML request to log out of the application.</p> </dd> </dl> </div> </div> </div> <div class="sect3"> <h4 id="keys-tab"><a class="anchor" href="#keys-tab"></a>Keys tab</h4> <div class="dlist"> <dl> <dt class="hdlist1"><strong>Encrypt Assertions</strong></dt> <dd> <p>Encrypts the assertions in SAML documents with the realms private key. The AES algorithm uses a key size of 128 bits.</p> </dd> <dt class="hdlist1"><strong>Client Signature Required</strong></dt> <dd> <p>If <strong>Client Signature Required</strong> is enabled, documents coming from a client are expected to be signed. Keycloak will validate this signature using the client public key or cert set up in the <code>Keys</code> tab.</p> </dd> <dt class="hdlist1"><strong>Allow ECP Flow</strong></dt> <dd> <p>If true, this application is allowed to use SAML ECP profile for authentication.</p> </dd> </dl> </div> </div> <div class="sect3"> <h4 id="advanced-tab-2"><a class="anchor" href="#advanced-tab-2"></a>Advanced tab</h4> <div class="paragraph"> <p>This tab has many fields for specific situations. Some fields are covered in other topics. For details on other fields, click the question mark icon.</p> </div> <div class="sect4"> <h5 id="fine-grain-saml-endpoint-configuration"><a class="anchor" href="#fine-grain-saml-endpoint-configuration"></a>Fine Grain SAML Endpoint Configuration</h5> <div class="dlist"> <dl> <dt class="hdlist1"><strong>Logo URL</strong></dt> <dd> <p>URL that references a logo for the Client application.</p> </dd> <dt class="hdlist1"><strong>Policy URL</strong></dt> <dd> <p>URL that the Relying Party Client provides to the End-User to read about how the profile data will be used.</p> </dd> <dt class="hdlist1"><strong>Terms of Service URL</strong></dt> <dd> <p>URL that the Relying Party Client provides to the End-User to read about the Relying Party&#8217;s terms of service.</p> </dd> <dt class="hdlist1"><strong>Assertion Consumer Service POST Binding URL</strong></dt> <dd> <p>POST Binding URL for the Assertion Consumer Service.</p> </dd> <dt class="hdlist1"><strong>Assertion Consumer Service Redirect Binding URL</strong></dt> <dd> <p>Redirect Binding URL for the Assertion Consumer Service.</p> </dd> <dt class="hdlist1"><strong>Logout Service POST Binding URL</strong></dt> <dd> <p>POST Binding URL for the Logout Service.</p> </dd> <dt class="hdlist1"><strong>Logout Service Redirect Binding URL</strong></dt> <dd> <p>Redirect Binding URL for the Logout Service.</p> </dd> <dt class="hdlist1"><strong>Logout Service Artifact Binding URL</strong></dt> <dd> <p><em>Artifact</em> Binding URL for the Logout Service. When set together with the <code>Force Artifact Binding</code> option, <em>Artifact</em> binding is forced for both login and logout flows. <em>Artifact</em> binding is not used for logout unless this property is set.</p> </dd> <dt class="hdlist1"><strong>Logout Service SOAP Binding URL</strong></dt> <dd> <p>Redirect Binding URL for the Logout Service. Only applicable if <strong>back channel logout</strong> is used.</p> </dd> <dt class="hdlist1"><strong>Artifact Binding URL</strong></dt> <dd> <p>URL to send the HTTP artifact messages to.</p> </dd> <dt class="hdlist1"><strong>Artifact Resolution Service</strong></dt> <dd> <p>URL of the client SOAP endpoint where to send the <code>ArtifactResolve</code> messages to.</p> </dd> </dl> </div> </div> </div> <div class="sect3"> <h4 id="idp-initiated-login"><a class="anchor" href="#idp-initiated-login"></a>IDP Initiated login</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/clients/saml/idp-initiated-login.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/clients/saml/idp-initiated-login.adoc&amp;description=%0A%0AFile:%20server_admin/topics/clients/saml/idp-initiated-login.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>IDP Initiated Login is a feature that allows you to set up an endpoint on the Keycloak server that will log you into a specific application/client. In the <strong>Settings</strong> tab for your client, you need to specify the <strong>IDP Initiated SSO URL Name</strong>. This is a simple string with no whitespace in it. After this you can reference your client at the following URL: <code>root/realms/{realm}/protocol/saml/clients/{url-name}</code></p> </div> <div class="paragraph"> <p>The IDP initiated login implementation prefers <em>POST</em> over <em>REDIRECT</em> binding (check <a href="#_saml">saml bindings</a> for more information). Therefore the final binding and SP URL are selected in the following way:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>If the specific <strong>Assertion Consumer Service POST Binding URL</strong> is defined (inside <strong>Fine Grain SAML Endpoint Configuration</strong> section of the client settings) <em>POST</em> binding is used through that URL.</p> </li> <li> <p>If the general <strong>Master SAML Processing URL</strong> is specified then <em>POST</em> binding is used again throughout this general URL.</p> </li> <li> <p>As the last resort, if the <strong>Assertion Consumer Service Redirect Binding URL</strong> is configured (inside <strong>Fine Grain SAML Endpoint Configuration</strong>) <em>REDIRECT</em> binding is used with this URL.</p> </li> </ol> </div> <div class="paragraph"> <p>If your client requires a special relay state, you can also configure this on the <strong>Settings</strong> tab in the <strong>IDP Initiated SSO Relay State</strong> field. Alternatively, browsers can specify the relay state in a <strong>RelayState</strong> query parameter, i.e. <code>root/realms/{realm}/protocol/saml/clients/{url-name}?RelayState=thestate</code>.</p> </div> <div class="paragraph"> <p>When using <a href="#_identity_broker">identity brokering</a>, it is possible to set up an IDP Initiated Login for a client from an external IDP. The actual client is set up for IDP Initiated Login at broker IDP as described above. The external IDP has to set up the client for application IDP Initiated Login that will point to a special URL pointing to the broker and representing IDP Initiated Login endpoint for a selected client at the brokering IDP. This means that in client settings at the external IDP:</p> </div> <div class="ulist"> <ul> <li> <p><strong>IDP Initiated SSO URL Name</strong> is set to a name that will be published as IDP Initiated Login initial point,</p> </li> <li> <p><strong>Assertion Consumer Service POST Binding URL</strong> in the <strong>Fine Grain SAML Endpoint Configuration</strong> section has to be set to the following URL: <code>broker-root/realms/{broker-realm}/broker/{idp-name}/endpoint/clients/{client-id}</code>, where:</p> <div class="ulist"> <ul> <li> <p><em>broker-root</em> is base broker URL</p> </li> <li> <p><em>broker-realm</em> is name of the realm at broker where external IDP is declared</p> </li> <li> <p><em>idp-name</em> is name of the external IDP at broker</p> </li> <li> <p><em>client-id</em> is the value of <strong>IDP Initiated SSO URL Name</strong> attribute of the SAML client defined at broker. It is this client, which will be made available for IDP Initiated Login from the external IDP.</p> </li> </ul> </div> </li> </ul> </div> <div class="paragraph"> <p>Please note that you can import basic client settings from the brokering IDP into client settings of the external IDP - just use <a href="#_identity_broker_saml_sp_descriptor">SP Descriptor</a> available from the settings of the identity provider in the brokering IDP, and add <code>clients/<em>client-id</em></code> to the endpoint URL.</p> </div> </div> <div class="sect3"> <h4 id="proc-using-an-entity-descriptors_server_administration_guide"><a class="anchor" href="#proc-using-an-entity-descriptors_server_administration_guide"></a>Using an entity descriptor to create a client</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/clients/saml/proc-using-an-entity-descriptor.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/clients/saml/proc-using-an-entity-descriptor.adoc&amp;description=%0A%0AFile:%20server_admin/topics/clients/saml/proc-using-an-entity-descriptor.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>Instead of registering a SAML 2.0 client manually, you can import the client using a standard SAML Entity Descriptor XML file.</p> </div> <div class="paragraph"> <p>The Client page includes an <strong>Import client</strong> option.</p> </div> <div class="paragraph"> <div class="title">Add client</div> <p><span class="image"><img src="./images/import-client-saml.png" alt="Import SAML client"></span></p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Browse</strong>.</p> </li> <li> <p>Load the file that contains the XML entity descriptor information.</p> </li> <li> <p>Review the information to ensure everything is set up correctly.</p> </li> </ol> </div> <div class="paragraph"> <p>Some SAML client adapters, such as <em>mod-auth-mellon</em>, need the XML Entity Descriptor for the IDP. You can find this descriptor by going to this URL:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>root/realms/{realm}/protocol/saml/descriptor</code></pre> </div> </div> <div class="paragraph"> <p>where <em>realm</em> is the realm of your client.</p> </div> </div> </div> <div class="sect2"> <h3 id="con-client-links_server_administration_guide"><a class="anchor" href="#con-client-links_server_administration_guide"></a>Client links</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/clients/con-client-links.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/clients/con-client-links.adoc&amp;description=%0A%0AFile:%20server_admin/topics/clients/con-client-links.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>To link from one client to another, Keycloak provides a redirect endpoint: <code>/realms/realm_name/clients/{client-id}/redirect</code>.</p> </div> <div class="paragraph"> <p>If a client accesses this endpoint using a <code>HTTP GET</code> request, Keycloak returns the configured base URL for the provided Client and Realm in the form of an <code>HTTP 307</code> (Temporary Redirect) in the response&#8217;s <code>Location</code> header. As a result of this, a client needs only to know the Realm name and the Client ID to link to them. This indirection avoids hard-coding client base URLs.</p> </div> <div class="paragraph"> <p>As an example, given the realm <code>master</code> and the client-id <code>account</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>http://host:port/realms/master/clients/account/redirect</code></pre> </div> </div> <div class="paragraph"> <p>This URL temporarily redirects to: <a href="http://host:port/realms/master/account" class="bare">http://host:port/realms/master/account</a></p> </div> </div> <div class="sect2"> <h3 id="_protocol-mappers"><a class="anchor" href="#_protocol-mappers"></a>OIDC token and SAML assertion mappings</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/clients/con-protocol-mappers.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/clients/con-protocol-mappers.adoc&amp;description=%0A%0AFile:%20server_admin/topics/clients/con-protocol-mappers.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>Applications receiving ID tokens, access tokens, or SAML assertions may require different roles and user metadata.</p> </div> <div class="paragraph"> <p>You can use Keycloak to:</p> </div> <div class="ulist"> <ul> <li> <p>Hardcode roles, claims and custom attributes.</p> </li> <li> <p>Pull user metadata into a token or assertion.</p> </li> <li> <p>Rename roles.</p> </li> </ul> </div> <div class="paragraph"> <p>You perform these actions in the <strong>Mappers</strong> tab in the Admin Console.</p> </div> <div class="paragraph"> <div class="title">Mappers tab</div> <p><span class="image"><img src="./images/mappers-oidc.png" alt="mappers oidc"></span></p> </div> <div class="paragraph"> <p>New clients do not have built-in mappers, but they can inherit some mappers from client scopes. See the <a href="#_client_scopes">client scopes section</a> for more details.</p> </div> <div class="paragraph"> <p>Protocol mappers map items (such as an email address, for example) to a specific claim in the identity and access token. The function of a mapper should be self-explanatory from its name. You add pre-configured mappers by clicking <strong>Add Builtin</strong>.</p> </div> <div class="paragraph"> <p>Each mapper has a set of common settings. Additional settings are available, depending on the mapper type. Click <strong>Edit</strong> next to a mapper to access the configuration screen to adjust these settings.</p> </div> <div class="paragraph"> <div class="title">Mapper config</div> <p><span class="image"><img src="./images/mapper-config.png" alt="mapper config"></span></p> </div> <div class="paragraph"> <p>Details on each option can be viewed by hovering over its tooltip.</p> </div> <div class="paragraph"> <p>You can use most OIDC mappers to control where the claim gets placed. You opt to include or exclude the claim from the <em>id</em> and <em>access</em> tokens by adjusting the <strong>Add to ID token</strong> and <strong>Add to access token</strong> switches.</p> </div> <div id="proc-creating-mappers_server_administration_guide" class="paragraph _abstract"> <p>You can add mapper types as follows:</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Go to the <strong>Mappers</strong> tab.</p> </li> <li> <p>Click <strong>Configure a new mapper</strong>.</p> <div class="paragraph"> <div class="title">Add mapper</div> <p><span class="image"><img src="./images/add-mapper.png" alt="add mapper"></span></p> </div> </li> <li> <p>Select a <strong>Mapper Type</strong> from the list box.</p> </li> </ol> </div> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/clients/proc-creating-mappers.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/clients/proc-creating-mappers.adoc&amp;description=%0A%0AFile:%20server_admin/topics/clients/proc-creating-mappers.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="sect3"> <h4 id="_protocol-mappers_priority"><a class="anchor" href="#_protocol-mappers_priority"></a>Priority order</h4> <div class="paragraph"> <p>Mapper implementations have <em>priority order</em>. <em>Priority order</em> is not the configuration property of the mapper. It is the property of the concrete implementation of the mapper.</p> </div> <div class="paragraph"> <p>Mappers are sorted by the order in the list of mappers. The changes in the token or assertion are applied in that order with the lowest applying first. Therefore, the implementations that are dependent on other implementations are processed in the necessary order.</p> </div> <div class="paragraph"> <p>For example, to compute the roles which will be included with a token:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Resolve audiences based on those roles.</p> </li> <li> <p>Process a JavaScript script that uses the roles and audiences already available in the token.</p> </li> </ol> </div> </div> <div class="sect3"> <h4 id="_protocol-mappers_oidc-user-session-note-mappers"><a class="anchor" href="#_protocol-mappers_oidc-user-session-note-mappers"></a>OIDC user session note mappers</h4> <div class="paragraph"> <p>User session details are defined using mappers and are automatically included when you use or enable a feature on a client. Click <strong>Add builtin</strong> to include session details.</p> </div> <div class="paragraph"> <p>Impersonated user sessions provide the following details:</p> </div> <div class="ulist"> <ul> <li> <p><strong>IMPERSONATOR_ID</strong>: The ID of an impersonating user.</p> </li> <li> <p><strong>IMPERSONATOR_USERNAME</strong>: The username of an impersonating user.</p> </li> </ul> </div> <div class="paragraph"> <p>Service account sessions provide the following details:</p> </div> <div class="ulist"> <ul> <li> <p><strong>clientId</strong>: The client ID of the service account.</p> </li> <li> <p><strong>client_id</strong>: The client ID of the service account.</p> </li> <li> <p><strong>clientAddress</strong>: The remote host IP of the service account&#8217;s authenticated device.</p> </li> <li> <p><strong>clientHost</strong>: The remote host name of the service account&#8217;s authenticated device.</p> </li> </ul> </div> </div> <div class="sect3"> <h4 id="script-mapper"><a class="anchor" href="#script-mapper"></a>Script mapper</h4> <div class="paragraph"> <p>Use the <strong>Script Mapper</strong> to map claims to tokens by running user-defined JavaScript code. For more details about deploying scripts to the server, see <a href="https://www.keycloak.org/docs/26.0.6/server_development/#_script_providers">JavaScript Providers</a>.</p> </div> <div class="paragraph"> <p>When scripts deploy, you should be able to select the deployed scripts from the list of available mappers.</p> </div> </div> <div class="sect3"> <h4 id="pairwise-subject-identifier-mapper"><a class="anchor" href="#pairwise-subject-identifier-mapper"></a>Pairwise subject identifier mapper</h4> <div class="paragraph"> <p>Subject claim <em>sub</em> is mapped by default by <strong>Subject (sub)</strong> protocol mapper in the default client scope <strong>basic</strong>.</p> </div> <div class="paragraph"> <p>To use a pairwise subject identifier by using a protocol mapper such as <strong>Pairwise subject identifier</strong>, you can remove the <strong>Subject (sub)</strong> protocol mapper from the <strong>basic</strong> client scope. However it is not strictly needed as the <strong>Subject (sub)</strong> protocol mapper is executed before the <strong>Pairwise subject identifier</strong> mapper and hence the pairwise value will override the value added by the Subject mapper. This is due to the <a href="#_protocol-mappers_priority">priority</a> of the Subject mapper. So the only advantage of removing the built-in <strong>Subject (sub)</strong> mapper might be to save a little bit of performance by avoiding the use of the protocol mapper, which may not have any effect.</p> </div> </div> <div class="sect3"> <h4 id="_using_lightweight_access_token"><a class="anchor" href="#_using_lightweight_access_token"></a>Using lightweight access token</h4> <div class="paragraph"> <p>The access token in Keycloak contains sensitive information, including Personal Identifiable Information (PII). Therefore, if the resource server does not want to disclose this type of information to third party entities such as clients, Keycloak supports lightweight access tokens that remove PII from access tokens. Further, when the resource server acquires the PII removed from the access token, it can acquire the PII by sending the access token to Keycloak&#8217;s token introspection endpoint.</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Information that cannot be removed from a lightweight access token</dt> <dd> <p>Protocol mappers can controls which information is put onto an access token and the lightweight access token use the protocol mappers. Therefore, the following information cannot be removed from the lightweight access.<br> <code>exp</code>, <code>iat</code>, <code>jti</code>, <code>iss</code>, <code>typ</code>, <code>azp</code>, <code>sid</code>, <code>scope</code>, <code>cnf</code></p> </dd> <dt class="hdlist1">Using a lightweight access token in Keycloak</dt> <dd> <p>By applying <code>use-lightweight-access-token</code> executor of <a href="#_client_policies">client policies</a> to a client, the client can receive a lightweight access token instead of an access token. The lightweight access token contains a claim controlled by a protocol mapper where its setting <code>Add to lightweight access token</code>(default OFF) is turned ON. Also, by turning ON its setting <code>Add to token introspection</code> of the protocol mapper, the client can obtain the claim by sending the access token to Keycloak&#8217;s token introspection endpoint.</p> </dd> <dt class="hdlist1">Introspection endpoint</dt> <dd> <p>In some cases, it might be useful to trigger the token introspection endpoint with the HTTP header <code>Accept: application/jwt</code> instead of <code>Accept: application/json</code>, which can be useful especially for lightweight access tokens. See the details of <strong>Token Introspection endpoint</strong> in the <a href="https://www.keycloak.org/guides#securing-apps">securing apps</a> section.</p> </dd> </dl> </div> </div> </div> <div class="sect2"> <h3 id="_client_installation"><a class="anchor" href="#_client_installation"></a>Generating client adapter config</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/clients/proc-generating-client-adapter-config.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/clients/proc-generating-client-adapter-config.adoc&amp;description=%0A%0AFile:%20server_admin/topics/clients/proc-generating-client-adapter-config.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>Keycloak can generate configuration files that you can use to install a client adapter in your application&#8217;s deployment environment. A number of adapter types are supported for OIDC and SAML.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Click on the <em>Action</em> menu and select the <strong>Download adapter config</strong> option</p> <div class="paragraph"> <p><span class="image"><img src="./images/client-installation.png" alt="client installation"></span></p> </div> </li> <li> <p>Select the <strong>Format Option</strong> you want configuration generated for.</p> </li> </ol> </div> <div class="paragraph"> <p>All Keycloak client adapters for OIDC and SAML are supported. The mod-auth-mellon Apache HTTPD adapter for SAML is supported as well as standard SAML entity descriptor files.</p> </div> </div> <div class="sect2"> <h3 id="_client_scopes"><a class="anchor" href="#_client_scopes"></a>Client scopes</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/clients/con-client-scopes.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/clients/con-client-scopes.adoc&amp;description=%0A%0AFile:%20server_admin/topics/clients/con-client-scopes.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>Use Keycloak to define a shared client configuration in an entity called a <em>client scope</em>. A <em>client scope</em> configures <a href="#_protocol-mappers">protocol mappers</a> and <a href="#_role_scope_mappings">role scope mappings</a> for multiple clients.</p> </div> <div class="paragraph"> <p>Client scopes also support the OAuth 2 <strong>scope</strong> parameter. Client applications use this parameter to request claims or roles in the access token, depending on the requirement of the application.</p> </div> <div id="proc_creating_client_scopes_server_administration_guide" class="paragraph _abstract"> <p>To create a client scope, follow these steps:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Click <strong>Client Scopes</strong> in the menu.</p> <div class="paragraph"> <div class="title">Client scopes list</div> <p><span class="image"><img src="./images/client-scopes-list.png" alt="client scopes list"></span></p> </div> </li> <li> <p>Click <strong>Create</strong>.</p> </li> <li> <p>Name your client scope.</p> </li> <li> <p>Click <strong>Save</strong>.</p> </li> </ol> </div> <div class="paragraph"> <p>A <em>client scope</em> has similar tabs to regular clients. You can define <a href="#_protocol-mappers">protocol mappers</a> and <a href="#_role_scope_mappings">role scope mappings</a>. These mappings can be inherited by other clients and are configured to inherit from this client scope.</p> </div> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/clients/proc-creating-client-scopes.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/clients/proc-creating-client-scopes.adoc&amp;description=%0A%0AFile:%20server_admin/topics/clients/proc-creating-client-scopes.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="sect3"> <h4 id="protocol"><a class="anchor" href="#protocol"></a>Protocol</h4> <div class="paragraph"> <p>When you create a client scope, choose the <strong>Protocol</strong>. Clients linked in the same scope must have the same protocol.</p> </div> <div class="paragraph"> <p>Each realm has a set of pre-defined built-in client scopes in the menu.</p> </div> <div class="ulist"> <ul> <li> <p>SAML protocol: The <strong>role_list</strong>. This scope contains one protocol mapper for the roles list in the SAML assertion.</p> </li> <li> <p>OpenID Connect protocol: Several client scopes are available:</p> <div class="ulist"> <ul> <li> <p><strong>roles</strong></p> <div class="paragraph"> <p>This scope is not defined in the OpenID Connect specification and is not added automatically to the <strong>scope</strong> claim in the access token. This scope has mappers, which are used to add the roles of the user to the access token and add audiences for clients that have at least one client role. These mappers are described in more detail in the <a href="#_audience_resolve">Audience section</a>.</p> </div> </li> <li> <p><strong>web-origins</strong></p> <div class="paragraph"> <p>This scope is also not defined in the OpenID Connect specification and not added to the <strong>scope</strong> claiming the access token. This scope is used to add allowed web origins to the access token <strong>allowed-origins</strong> claim.</p> </div> </li> <li> <p><strong>microprofile-jwt</strong></p> <div class="paragraph"> <p>This scope handles claims defined in the <a href="https://github.com/eclipse/microprofile/wiki/JWT_Auth">MicroProfile/JWT Auth Specification</a>. This scope defines a user property mapper for the <strong>upn</strong> claim and a realm role mapper for the <strong>groups</strong> claim. These mappers can be changed so different properties can be used to create the MicroProfile/JWT specific claims.</p> </div> </li> <li> <p><strong>offline_access</strong></p> <div class="paragraph"> <p>This scope is used in cases when clients need to obtain offline tokens. More details on offline tokens is available in the <a href="#_offline-access">Offline Access section</a> and in the <a href="https://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess">OpenID Connect specification</a>.</p> </div> </li> <li> <p><strong>profile</strong></p> </li> <li> <p><strong>email</strong></p> </li> <li> <p><strong>address</strong></p> </li> <li> <p><strong>phone</strong></p> </li> </ul> </div> </li> </ul> </div> <div class="paragraph"> <p>The client scopes <strong>profile</strong>, <strong>email</strong>, <strong>address</strong> and <strong>phone</strong> are defined in the <a href="https://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims">OpenID Connect specification</a>. These scopes do not have any role scope mappings defined but they do have protocol mappers defined. These mappers correspond to the claims defined in the OpenID Connect specification.</p> </div> <div class="paragraph"> <p>For example, when you open the <strong>phone</strong> client scope and open the <strong>Mappers</strong> tab, you will see the protocol mappers which correspond to the claims defined in the specification for the scope <strong>phone</strong>.</p> </div> <div class="paragraph"> <div class="title">Client scope mappers</div> <p><span class="image"><img src="./images/client-scopes-phone.png" alt="client scopes phone"></span></p> </div> <div class="paragraph"> <p>When the <strong>phone</strong> client scope is linked to a client, the client automatically inherits all the protocol mappers defined in the <strong>phone</strong> client scope. Access tokens issued for this client contain the phone number information about the user, assuming that the user has a defined phone number.</p> </div> <div class="paragraph"> <p>Built-in client scopes contain the protocol mappers as defined in the specification. You are free to edit client scopes and create, update, or remove any protocol mappers or role scope mappings.</p> </div> </div> <div class="sect3"> <h4 id="consent-related-settings"><a class="anchor" href="#consent-related-settings"></a>Consent related settings</h4> <div class="paragraph"> <p>Client scopes contain options related to the consent screen. Those options are useful if the linked client if <strong>Consent Required</strong> is enabled on the client.</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Display On Consent Screen</dt> <dd> <p>If <strong>Display On Consent Screen</strong> is enabled, and the scope is added to a client that requires consent, the text specified in <strong>Consent Screen Text</strong> will be displayed on the consent screen. This text is shown when the user is authenticated and before the user is redirected from Keycloak to the client. If <strong>Display On Consent Screen</strong> is disabled, this client scope will not be displayed on the consent screen.</p> </dd> <dt class="hdlist1">Consent Screen Text</dt> <dd> <p>The text displayed on the consent screen when this client scope is added to a client when consent required defaults to the name of client scope. The value for this text can be customised by specifying a substitution variable with <strong>${var-name}</strong> strings. The customised value is configured within the property files in your theme. See the <a href="https://www.keycloak.org/docs/26.0.6/server_development/">Server Developer Guide</a> for more information on customisation.</p> </dd> </dl> </div> </div> <div class="sect3"> <h4 id="_client_scopes_linking"><a class="anchor" href="#_client_scopes_linking"></a>Link client scope with the client</h4> <div class="paragraph"> <p>Linking between a client scope and a client is configured in the <strong>Client Scopes</strong> tab of the client. Two ways of linking between client scope and client are available.</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Default Client Scopes</dt> <dd> <p>This setting is applicable to the OpenID Connect and SAML clients. Default client scopes are applied when issuing OpenID Connect tokens or SAML assertions for a client. The client will inherit Protocol Mappers and Role Scope Mappings that are defined on the client scope. For the OpenID Connect Protocol, the Mappers and Role Scope Mappings are always applied, regardless of the value used for the scope parameter in the OpenID Connect authorization request.</p> </dd> <dt class="hdlist1">Optional Client Scopes</dt> <dd> <p>This setting is applicable only for OpenID Connect clients. Optional client scopes are applied when issuing tokens for this client but only when requested by the <strong>scope</strong> parameter in the OpenID Connect authorization request.</p> </dd> </dl> </div> <div class="sect4"> <h5 id="example"><a class="anchor" href="#example"></a>Example</h5> <div class="paragraph"> <p>For this example, assume the client has <strong>profile</strong> and <strong>email</strong> linked as default client scopes, and <strong>phone</strong> and <strong>address</strong> linked as optional client scopes. The client uses the value of the scope parameter when sending a request to the OpenID Connect authorization endpoint.</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">scope=openid phone</code></pre> </div> </div> <div class="paragraph"> <p>The scope parameter contains the string, with the scope values divided by spaces. The value <strong>openid</strong> is the meta-value used for all OpenID Connect requests. The token will contain mappers and role scope mappings from the default client scopes <strong>profile</strong> and <strong>email</strong> as well as <strong>phone</strong>, an optional client scope requested by the scope parameter.</p> </div> </div> </div> <div class="sect3"> <h4 id="_client_scopes_evaluate"><a class="anchor" href="#_client_scopes_evaluate"></a>Evaluating Client Scopes</h4> <div id="proc_evaluating_client_scopes_server_administration_guide" class="paragraph _abstract"> <p>The <strong>Mappers</strong> tab contains the protocol mappers and the <strong>Scope</strong> tab contains the role scope mappings declared for this client. They do not contain the mappers and scope mappings inherited from client scopes. It is possible to see the effective protocol mappers (that is the protocol mappers defined on the client itself as well as inherited from the linked client scopes) and the effective role scope mappings used when generating a token for a client.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click the <strong>Client Scopes</strong> tab for the client.</p> </li> <li> <p>Open the sub-tab <strong>Evaluate</strong>.</p> </li> <li> <p>Select the optional client scopes that you want to apply.</p> </li> </ol> </div> <div class="paragraph"> <p>This will also show you the value of the <strong>scope</strong> parameter. This parameter needs to be sent from the application to the Keycloak OpenID Connect authorization endpoint.</p> </div> <div class="paragraph"> <div class="title">Evaluating client scopes</div> <p><span class="image"><img src="./images/client-scopes-evaluate.png" alt="client scopes evaluate"></span></p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/clients/proc-evaluating-client-scopes.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/clients/proc-evaluating-client-scopes.adoc&amp;description=%0A%0AFile:%20server_admin/topics/clients/proc-evaluating-client-scopes.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>To send a custom value for a <strong>scope</strong> parameter from your application, see the <strong>Keycloak JavaScript adapter</strong> in the <a href="https://www.keycloak.org/guides#securing-apps">securing apps</a> section, for javascript adapters.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>All examples are generated for the particular user and issued for the particular client, with the specified value of the <strong>scope</strong> parameter. The examples include all of the claims and role mappings used.</p> </div> </div> <div class="sect3"> <h4 id="client-scopes-permissions"><a class="anchor" href="#client-scopes-permissions"></a>Client scopes permissions</h4> <div class="paragraph"> <p>When issuing tokens to a user, the client scope applies only if the user is permitted to use it.</p> </div> <div class="paragraph"> <p>When a client scope does not have any role scope mappings defined, each user is permitted to use this client scope. However, when a client scope has role scope mappings defined, the user must be a member of at least one of the roles. There must be an intersection between the user roles and the roles of the client scope. Composite roles are factored into evaluating this intersection.</p> </div> <div class="paragraph"> <p>If a user is not permitted to use the client scope, no protocol mappers or role scope mappings will be used when generating tokens. The client scope will not appear in the <em>scope</em> value in the token.</p> </div> </div> <div class="sect3"> <h4 id="realm-default-client-scopes"><a class="anchor" href="#realm-default-client-scopes"></a>Realm default client scopes</h4> <div id="proc_updating_client_scopes_server_administration_guide" class="paragraph _abstract"> <p>Use <strong>Realm Default Client Scopes</strong> to define sets of client scopes that are automatically linked to newly created clients.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click the <strong>Client Scopes</strong> tab for the client.</p> </li> </ol> </div> <div class="paragraph"> <p>From here, select the client scopes that you want to add as <strong>Default Client Scopes</strong> to newly created clients and <strong>Optional Client Scopes</strong>.</p> </div> <div class="paragraph"> <div class="title">Default client scopes</div> <p><span class="image"><img src="./images/client-scopes-default.png" alt="client scopes default"></span></p> </div> <div class="paragraph"> <p>When a client is created, you can unlink the default client scopes, if needed. This is similar to removing <a href="#_default_roles">Default Roles</a>.</p> </div> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/clients/proc-updating-default-scopes.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/clients/proc-updating-default-scopes.adoc&amp;description=%0A%0AFile:%20server_admin/topics/clients/proc-updating-default-scopes.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> </div> <div class="sect3"> <h4 id="scopes-explained"><a class="anchor" href="#scopes-explained"></a>Scopes explained</h4> <div class="dlist"> <dl> <dt class="hdlist1">Client scope</dt> <dd> <p>Client scopes are entities in Keycloak that are configured at the realm level and can be linked to clients. Client scopes are referenced by their name when a request is sent to the Keycloak authorization endpoint with a corresponding value of the <strong>scope</strong> parameter. See the <a href="#_client_scopes_linking">client scopes linking</a> section for more details.</p> </dd> <dt class="hdlist1">Role scope mapping</dt> <dd> <p>This is available under the <strong>Scope</strong> tab of a client or client scope. Use <strong>Role scope mapping</strong> to limit the roles that can be used in the access tokens. See the <a href="#_role_scope_mappings">Role Scope Mappings section</a> for more details.</p> </dd> <dt class="hdlist1">Authorization scopes</dt> <dd> <p>The <strong>Authorization Scope</strong> covers the actions that can be performed in the application. See the <a href="https://www.keycloak.org/docs/26.0.6/authorization_services/">Authorization Services Guide</a> for more details.</p> </dd> </dl> </div> </div> </div> <div class="sect2"> <h3 id="_client_policies"><a class="anchor" href="#_client_policies"></a>Client Policies</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/clients/client-policies.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/clients/client-policies.adoc&amp;description=%0A%0AFile:%20server_admin/topics/clients/client-policies.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>To make it easy to secure client applications, it is beneficial to realize the following points in a unified way.</p> </div> <div class="ulist"> <ul> <li> <p>Setting policies on what configuration a client can have</p> </li> <li> <p>Validation of client configurations</p> </li> <li> <p>Conformance to a required security standards and profiles such as Financial-grade API (FAPI) and OAuth 2.1</p> </li> </ul> </div> <div class="paragraph"> <p>To realize these points in a unified way, <em>Client Policies</em> concept is introduced.</p> </div> <div class="sect3"> <h4 id="use-cases"><a class="anchor" href="#use-cases"></a>Use-cases</h4> <div class="paragraph"> <p>Client Policies realize the following points mentioned as follows.</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Setting policies on what configuration a client can have</dt> <dd> <p>Configuration settings on the client can be enforced by client policies during client creation/update, but also during OpenID Connect requests to Keycloak server, which are related to particular client. Keycloak supports similar thing also through the <strong>Client Registration Policies</strong> described in the <strong>Client registration service</strong> from <a href="https://www.keycloak.org/guides#securing-apps">Securing applications Guides</a>. However, Client Registration Policies can only cover OIDC Dynamic Client Registration. Client Policies cover not only what Client Registration Policies can do, but other client registration and configuration ways. The current plans are for Client Registration to be replaced by Client Policies.</p> </dd> <dt class="hdlist1">Validation of client configurations</dt> <dd> <p>Keycloak supports validation whether the client follows settings like Proof Key for Code Exchange, Request Object Signing Algorithm, Holder-of-Key Token, and so on some endpoints like Authorization Endpoint, Token Endpoint, and so on. These can be specified by each setting item (on Admin Console, switch, pull-down menu and so on). To make the client application secure, the administrator needs to set many settings in the appropriate way, which makes it difficult for the administrator to secure the client application. Client Policies can do these validation of client configurations mentioned just above and they can also be used to autoconfigure some client configuration switches to meet the advanced security requirements. In the future, individual client configuration settings may be replaced by Client Policies directly performing required validations.</p> </dd> <dt class="hdlist1">Conformance to a required security standards and profiles such as FAPI and OAuth 2.1</dt> <dd> <p>The <em>Global client profiles</em> are client profiles pre-configured in Keycloak by default. They are pre-configured to be compliant with standard security profiles like <strong>FAPI</strong> and <strong>OAuth 2.1</strong> in the <a href="https://www.keycloak.org/guides#securing-apps">securing apps</a> section, which makes it easy for the administrator to secure their client application to be compliant with the particular security profile. At this moment, Keycloak has global profiles for the support of FAPI and OAuth 2.1 specifications. The administrator will just need to configure the client policies to specify which clients should be compliant with the FAPI and OAuth 2.1. The administrator can configure client profiles and client policies, so that Keycloak clients can be easily made compliant with various other security profiles like SPA, Native App, Open Banking and so on.</p> </dd> </dl> </div> </div> <div class="sect3"> <h4 id="protocol-2"><a class="anchor" href="#protocol-2"></a>Protocol</h4> <div class="paragraph"> <p>The client policy concept is independent of any specific protocol. Keycloak currently supports especially client profiles for the <a href="https://www.keycloak.org/docs/26.0.6/server_admin/#con-oidc_server_administration_guide">OpenID Connect (OIDC) protocol</a>, but there is also a client profile available for the <a href="https://www.keycloak.org/docs/26.0.6/server_admin/#_saml">SAML protocol</a>.</p> </div> </div> <div class="sect3"> <h4 id="architecture"><a class="anchor" href="#architecture"></a>Architecture</h4> <div class="paragraph"> <p>Client Policies consists of the four building blocks: Condition, Executor, Profile and Policy.</p> </div> <div class="sect4"> <h5 id="condition"><a class="anchor" href="#condition"></a>Condition</h5> <div class="paragraph"> <p>A condition determines to which client a policy is adopted and when it is adopted. Some conditions are checked at the time of client create/update when some other conditions are checked during client requests (OIDC Authorization request, Token endpoint request and so on). The condition checks whether one specified criteria is satisfied. For example, some condition checks whether the access type of the client is confidential.</p> </div> <div class="paragraph"> <p>The condition can not be used solely by itself. It can be used in a <a href="#_client_policy_policy">policy</a> that is described afterwards.</p> </div> <div class="paragraph"> <p>A condition can be configurable the same as other configurable providers. What can be configured depends on each condition&#8217;s nature.</p> </div> <div class="paragraph"> <p>The following conditions are provided:</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">The way of creating/updating a client</dt> <dd> <div class="ulist"> <ul> <li> <p>Dynamic Client Registration (Anonymous or Authenticated with Initial access token or Registration access token)</p> </li> <li> <p>Admin REST API (Admin Console and so on)</p> </li> </ul> </div> </dd> </dl> </div> <div class="paragraph"> <p>So for example when creating a client, a condition can be configured to evaluate to true when this client is created by OIDC Dynamic Client Registration without initial access token (Anonymous Dynamic Client Registration). So this condition can be used for example to ensure that all clients registered through OIDC Dynamic Client Registration are FAPI or OAuth 2.1 compliant.</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Author of a client (Checked by presence to the particular role or group)</dt> <dd> <p>On OpenID Connect dynamic client registration, an author of a client is the end user who was authenticated to get an access token for generating a new client, not Service Account of the existing client that actually accesses the registration endpoint with the access token. On registration by Admin REST API, an author of a client is the end user like the administrator of the Keycloak.</p> </dd> <dt class="hdlist1">Client Access Type (confidential, public, bearer-only)</dt> <dd> <p>For example when a client sends an authorization request, a policy is adopted if this client is confidential. Confidential client has enabled client authentication when public client has disabled client authentication. Bearer-only is a deprecated client type.</p> </dd> <dt class="hdlist1">Client Scope</dt> <dd> <p>Evaluates to true if the client has a particular client scope (either as default or as an optional scope used in current request). This can be used for example to ensure that OIDC authorization requests with scope <code>fapi-example-scope</code> need to be FAPI compliant.</p> </dd> <dt class="hdlist1">Client Role</dt> <dd> <p>Applies for clients with the client role of the specified name. Typically you can create a client role of specified name to requested clients and use it as a "marker role" to make sure that specified client policy will be applied for requested clients.</p> </dd> </dl> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> A use-case often exists for requiring the application of a particular client policy for the specified clients such as <code>my-client-1</code> and <code>my-client-2</code>. The best way to achieve this result is to use a <strong>Client Role</strong> condition in your policy and then a create client role of specified name to requested clients. This client role can be used as a "marker role" used solely for marking that particular client policy for particular clients. </td> </tr> </table> </div> <div class="dlist"> <dl> <dt class="hdlist1">Client Domain Name, Host or IP Address</dt> <dd> <p>Applied for specific domain names of client. Or for the cases when the administrator registers/updates client from particular Host or IP Address.</p> </dd> <dt class="hdlist1">Client Attribute</dt> <dd> <p>Applies to clients with the client attribute of the specified name and value. If you specify multiple client attributes, they will be evaluated using AND conditions. If you want to evaluate using OR conditions, set this condition multiple times.</p> </dd> <dt class="hdlist1">Any Client</dt> <dd> <p>This condition always evaluates to true. It can be used for example to ensure that all clients in the particular realm are FAPI compliant.</p> </dd> </dl> </div> </div> <div class="sect4"> <h5 id="executor"><a class="anchor" href="#executor"></a>Executor</h5> <div class="paragraph"> <p>An executor specifies what action is executed on a client to which a policy is adopted. The executor executes one or several specified actions. For example, some executor checks whether the value of the parameter <code>redirect_uri</code> in the authorization request matches exactly with one of the pre-registered redirect URIs on Authorization Endpoint and rejects this request if not.</p> </div> <div class="paragraph"> <p>The executor can not be used solely by itself. It can be used in a <a href="#_client_policy_profile">profile</a> that is described afterwards.</p> </div> <div class="paragraph"> <p>An executor can be configurable the same as other configurable providers. What can be configured depends on the nature of each executor.</p> </div> <div class="paragraph"> <p>An executor acts on various events. An executor implementation can ignore certain types of events (For example, executor for checking OIDC <code>request</code> object acts just on the OIDC authorization request). Events are:</p> </div> <div class="ulist"> <ul> <li> <p>Creating a client (including creation through dynamic client registration)</p> </li> <li> <p>Updating a client</p> </li> <li> <p>Sending an authorization request</p> </li> <li> <p>Sending a token request</p> </li> <li> <p>Sending a token refresh request</p> </li> <li> <p>Sending a token revocation request</p> </li> <li> <p>Sending a token introspection request</p> </li> <li> <p>Sending a userinfo request</p> </li> <li> <p>Sending a logout request with a refresh token (note that logout with refresh token is proprietary Keycloak functionality unsupported by any specification. It is rather recommended to rely on the <a href="#_oidc-logout">official OIDC logout</a>).</p> </li> </ul> </div> <div class="paragraph"> <p>On each event, an executor can work in multiple phases. For example, on creating/updating a client, the executor can modify the client configuration by autoconfigure specific client settings. After that, the executor validates this configuration in validation phase.</p> </div> <div class="paragraph"> <p>One of several purposes for this executor is to realize the security requirements of client conformance profiles like FAPI and OAuth 2.1. To do so, the following executors are needed:</p> </div> <div class="ulist"> <ul> <li> <p>Enforce secure <a href="#_client-credentials">Client Authentication method</a> is used for the client</p> </li> <li> <p>Enforce <a href="#_mtls-client-certificate-bound-tokens">Holder-of-key tokens</a> are used</p> </li> <li> <p>Enforce <a href="#_proof-key-for-code-exchange">Proof Key for Code Exchange (PKCE)</a> is used</p> </li> <li> <p>Enforce secure signature algorithm for <a href="#_client-credentials">Signed JWT client authentication (private-key-jwt)</a> is used</p> </li> <li> <p>Enforce HTTPS redirect URI and make sure that configured redirect URI does not contain wildcards</p> </li> <li> <p>Enforce OIDC <code>request</code> object satisfying high security level</p> </li> <li> <p>Enforce Response Type of OIDC Hybrid Flow including ID Token used as <em>detached signature</em> as described in the FAPI 1 specification, which means that ID Token returned from Authorization response won&#8217;t contain user profile data</p> </li> <li> <p>Enforce more secure <code>state</code> and <code>nonce</code> parameters treatment for preventing CSRF</p> </li> <li> <p>Enforce more secure signature algorithm when client registration</p> </li> <li> <p>Enforce <code>binding_message</code> parameter is used for CIBA requests</p> </li> <li> <p>Enforce <a href="#_secret_rotation">Client Secret Rotation</a></p> </li> <li> <p>Enforce Client Registration Access Token</p> </li> <li> <p>Enforce checking if a client is the one to which an intent was issued in a use case where an intent is issued before starting an authorization code flow to get an access token like UK OpenBanking</p> </li> <li> <p>Enforce prohibiting implicit and hybrid flow</p> </li> <li> <p>Enforce checking if a PAR request includes necessary parameters included by an authorization request</p> </li> <li> <p>Enforce <a href="#_dpop-bound-tokens">DPoP-binding tokens</a> is used (available when <code>dpop</code> feature is enabled)</p> </li> <li> <p>Enforce <a href="#_using_lightweight_access_token">using lightweight access token</a></p> </li> <li> <p>Enforce that <a href="#_refresh_token_rotation">refresh token rotation</a> is skipped and there is no refresh token returned from the refresh token response</p> </li> <li> <p>Enforce a valid redirect URI that the OAuth 2.1 specification requires</p> </li> <li> <p>Enforce SAML Redirect binding cannot be used or SAML requests and assertions are signed</p> </li> </ul> </div> </div> <div class="sect4"> <h5 id="_client_policy_profile"><a class="anchor" href="#_client_policy_profile"></a>Profile</h5> <div class="paragraph"> <p>A profile consists of several executors, which can realize a security profile like FAPI and OAuth 2.1. Profile can be configured by the Admin REST API (Admin Console) together with its executors. Three <em>global profiles</em> exist and they are configured in Keycloak by default with pre-configured executors compliant with the FAPI 1 Baseline, FAPI 1 Advanced, FAPI CIBA, FAPI 2 and OAuth 2.1 specifications. More details exist in the <strong>FAPI</strong> and <strong>OAuth 2.1</strong> in the <a href="https://www.keycloak.org/guides#securing-apps">securing apps</a> section.</p> </div> </div> <div class="sect4"> <h5 id="_client_policy_policy"><a class="anchor" href="#_client_policy_policy"></a>Policy</h5> <div class="paragraph"> <p>A policy consists of several conditions and profiles. The policy can be adopted to clients satisfying all conditions of this policy. The policy refers several profiles and all executors of these profiles execute their task against the client that this policy is adopted to.</p> </div> </div> </div> <div class="sect3"> <h4 id="configuration"><a class="anchor" href="#configuration"></a>Configuration</h4> <div class="paragraph"> <p>Policies, profiles, conditions, executors can be configured by Admin REST API, which means also the Admin Console. To do so, there is a tab <em>Realm</em> &#8594; <em>Realm Settings</em> &#8594; <em>Client Policies</em> , which means the administrator can have client policies per realm.</p> </div> <div class="paragraph"> <p>The <em>Global Client Profiles</em> are automatically available in each realm. However there are no client policies configured by default. This means that the administrator is always required to create any client policy if they want for example the clients of his realm to be FAPI compliant. Global profiles cannot be updated, but the administrator can easily use them as a template and create their own profile if they want to do some slight changes in the global profile configurations. There is JSON Editor available in the Admin Console, which simplifies the creation of new profile based on some global profile.</p> </div> </div> <div class="sect3"> <h4 id="backward-compatibility"><a class="anchor" href="#backward-compatibility"></a>Backward Compatibility</h4> <div class="paragraph"> <p>Client Policies can replace Client Registration Policies described in the <strong>Client registration service</strong> from <a href="https://www.keycloak.org/guides#securing-apps">Securing applications Guides</a>. However, Client Registration Policies also still co-exist. This means that for example during a Dynamic Client Registration request to create/update a client, both client policies and client registration policies are applied.</p> </div> <div class="paragraph"> <p>The current plans are for the Client Registration Policies feature to be removed and the existing client registration policies will be migrated into new client policies automatically.</p> </div> </div> <div class="sect3"> <h4 id="client-secret-rotation-example"><a class="anchor" href="#client-secret-rotation-example"></a>Client Secret Rotation Example</h4> <div class="paragraph"> <p>See an example configuration for <a href="#_proc-secret-rotation">client secret rotation</a>.</p> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="_vault-administration"><a class="anchor" href="#_vault-administration"></a>Using a vault to obtain secrets</h2> <div class="sectionbody"> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/vault.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/vault.adoc&amp;description=%0A%0AFile:%20server_admin/topics/vault.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Keycloak currently provides two out-of-the-box implementations of the Vault SPI: a plain-text file-based vault and Java KeyStore-based vault.</p> </div> <div class="paragraph"> <p>To obtain a secret from a vault rather than entering it directly, enter the following specially crafted string into the appropriate field:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>${vault.key}</code></pre> </div> </div> <div class="paragraph"> <p>where the <code>key</code> is the name of the secret recognized by the vault.</p> </div> <div class="paragraph"> <p>To prevent secrets from leaking across realms, Keycloak combines the realm name with the <code>key</code> obtained from the vault expression. This method means that the <code>key</code> does not directly map to an entry in the vault but creates the final entry name according to the algorithm used to combine the <code>key</code> with the realm name. In case of the file-based vault, such combination reflects to a specific filename, for the Java KeyStore-based vault it&#8217;s a specific alias name.</p> </div> <div class="paragraph"> <p>You can obtain the secret from the vault in the following fields:</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">SMTP password</dt> <dd> <p>In the realm <a href="#_email">SMTP settings</a></p> </dd> <dt class="hdlist1">LDAP bind credential</dt> <dd> <p>In the <a href="#_ldap">LDAP settings</a> of LDAP-based user federation.</p> </dd> <dt class="hdlist1">OIDC identity provider secret</dt> <dd> <p>In the <em>Client Secret</em> inside identity provider <a href="#_identity_broker_oidc">OpenID Connect Config</a></p> </dd> </dl> </div> <div class="sect2"> <h3 id="_vault-key-resolvers"><a class="anchor" href="#_vault-key-resolvers"></a>Key resolvers</h3> <div class="paragraph"> <p>All built-in providers support the configuration of key resolvers. A key resolver implements the algorithm or strategy for combining the realm name with the key, obtained from the <code>${vault.key}</code> expression, into the final entry name used to retrieve the secret from the vault. Keycloak uses the <code>keyResolvers</code> property to configure the resolvers that the provider uses. The value is a comma-separated list of resolver names. An example of the configuration for the <code>files-plaintext</code> provider follows:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">kc.[sh|bat] start --spi-vault-file-key-resolvers=REALM_UNDERSCORE_KEY,KEY_ONLY</code></pre> </div> </div> <div class="paragraph"> <p>The resolvers run in the same order you declare them in the configuration. For each resolver, Keycloak uses the last entry name the resolver produces, which combines the realm with the vault key to search for the vault&#8217;s secret. If Keycloak finds a secret, it returns the secret. If not, Keycloak uses the next resolver. This search continues until Keycloak finds a non-empty secret or runs out of resolvers. If Keycloak finds no secret, Keycloak returns an empty secret.</p> </div> <div class="paragraph"> <p>In the previous example, Keycloak uses the <code>REALM_UNDERSCORE_KEY</code> resolver first. If Keycloak finds an entry in the vault that using that resolver, Keycloak returns that entry. If not, Keycloak searches again using the <code>KEY_ONLY</code> resolver. If Keycloak finds an entry by using the <code>KEY_ONLY</code> resolver, Keycloak returns that entry. If Keycloak uses all resolvers, Keycloak returns an empty secret.</p> </div> <div class="paragraph"> <p>A list of the currently available resolvers follows:</p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 50%;"> <col style="width: 50%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Name</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">KEY_ONLY</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Keycloak ignores the realm name and uses the key from the vault expression. Keycloak escapes occurrences of underscores in the key with another underscore character. For example, if the key is called <code>my_secret</code>, Keycloak searches for an entry in the vault named <code>my__secret</code>. This is to prevent conflicts with the default <code>REALM_UNDERSCORE_KEY</code> resolver.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">REALM_UNDERSCORE_KEY</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Keycloak combines the realm and key by using an underscore character. Keycloak escapes occurrences of underscores in the realm or key with another underscore character. For example, if the realm is called <code>master_realm</code> and the key is <code>smtp_key</code>, the combined key is <code>master__realm_smtp__key</code>.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">REALM_FILESEPARATOR_KEY</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Keycloak combines the realm and key by using the platform file separator character. The vault expression prohibits the use of characters that could cause path traversal, thus preventing access to secrets outside the corresponding realm.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">FACTORY_PROVIDED</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Keycloak combines the realm and key by using the vault provider factory&#8217;s <code>VaultKeyResolver</code>, allowing the creation of a custom key resolver by extending an existing factory and implementing the <code>getFactoryResolver</code> method.</p></td> </tr> </tbody> </table> <div class="paragraph"> <p>If you have not configured a resolver for the built-in providers, Keycloak selects the <code>REALM_UNDERSCORE_KEY</code>.</p> </div> </div> </div> </div> <div class="sect1"> <h2 id="configuring-auditing-to-track-events"><a class="anchor" href="#configuring-auditing-to-track-events"></a>Configuring auditing to track events</h2> <div class="sectionbody"> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/events.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/events.adoc&amp;description=%0A%0AFile:%20server_admin/topics/events.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph _abstract"> <p>Keycloak includes a suite of auditing capabilities. You can record every login and administrator action and review those actions in the Admin Console. Keycloak also includes a Listener SPI that listens for events and can trigger actions. Examples of built-in listeners include log files and sending emails if an event occurs.</p> </div> <div class="sect2"> <h3 id="auditing-user-events"><a class="anchor" href="#auditing-user-events"></a>Auditing user events</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/events/login.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/events/login.adoc&amp;description=%0A%0AFile:%20server_admin/topics/events/login.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>You can record and view every event that affects users. Keycloak triggers login events for actions such as successful user login, a user entering an incorrect password, or a user account updating. By default, Keycloak does not store or display events in the Admin Console. Only the error events are logged to the Admin Console and the server’s log file.</p> </div> <div class="paragraph"> <div class="title">Procedure</div> <p>Use this procedure to start auditing user events.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Click <strong>Realm settings</strong> in the menu.</p> </li> <li> <p>Click the <strong>Events</strong> tab.</p> </li> <li> <p>Click the <strong>User events settings</strong> tab.</p> </li> <li> <p>Toggle <strong>Save events</strong> to <strong>ON</strong>.</p> <div class="paragraph"> <div class="title">User events settings</div> <p><span class="image"><img src="./images/user-events-settings.png" alt="User events settings"></span></p> </div> </li> <li> <p>Specify the length of time to store events in the <strong>Expiration</strong> field.</p> </li> <li> <p>Click <strong>Add saved types</strong> to see other events you can save.</p> <div class="paragraph"> <div class="title">Add types</div> <p><span class="image"><img src="./images/add-event-types.png" alt="Add types"></span></p> </div> </li> <li> <p>Click <strong>Add</strong>.</p> </li> </ol> </div> <div class="paragraph"> <p>Click <strong>Clear user events</strong> when you want to delete all saved events.</p> </div> <div class="paragraph"> <div class="title">Procedure</div> <p>You can now view events.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Click the <strong>Events</strong> tab in the menu.</p> <div class="paragraph"> <div class="title">User events</div> <p><span class="image"><img src="./images/user-events.png" alt="Login Events"></span></p> </div> </li> <li> <p>To filter events, click <strong>Search user event</strong>.</p> <div class="paragraph"> <div class="title">Search user event</div> <p><span class="image"><img src="./images/search-user-event.png" alt="Search user event"></span></p> </div> </li> </ol> </div> <div class="sect3"> <h4 id="event-types"><a class="anchor" href="#event-types"></a>Event types</h4> <div class="paragraph"> <p><strong>Login events:</strong></p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 50%;"> <col style="width: 50%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Event</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Login</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">A user logs in.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Register</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">A user registers.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Logout</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">A user logs out.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Code to Token</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">An application, or client, exchanges a code for a token.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Refresh Token</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">An application, or client, refreshes a token.</p></td> </tr> </tbody> </table> <div class="paragraph"> <p><strong>Brute force protection:</strong></p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 50%;"> <col style="width: 50%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Event</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">User disabled by permanent lockout</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Brute force protection disabled the user account permanently due to too many login failures.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">User disabled by temporary lockout</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Brute force protection disabled the user account temporarily due to too many login failures.</p></td> </tr> </tbody> </table> <div class="paragraph"> <p><strong>Identity Brokering:</strong></p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 50%;"> <col style="width: 50%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Event</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Federated identity link override</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">An existing Federated identity link was overridden</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Federated identity link override error</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Error occurred when trying to override an existing Federated identity link</p></td> </tr> </tbody> </table> <div class="paragraph"> <p><strong>OAuth:</strong></p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 50%;"> <col style="width: 50%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Event</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">OAuth2 extension grant</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">OAuth2 grant was executed</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">OAuth2 extension grant error</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Error occurred during OAuth2 grant execution</p></td> </tr> </tbody> </table> <div class="paragraph"> <p><strong>Account events:</strong></p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 50%;"> <col style="width: 50%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Event</th> <th class="tableblock halign-left valign-top">Description</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Social Link</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">A user account links to a social media provider.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Remove Social Link</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The link from a social media account to a user account severs.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Update Email</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">An email address for an account changes.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Update Profile</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">A profile for an account changes.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Send Password Reset</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Keycloak sends a password reset email.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Update Password (deprecated)</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The password for an account changes.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Update Credential</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The password or (time-based) one-time Password (OTP/TOTP) settings for an account changes.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Update TOTP (deprecated)</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The Time-based One-time Password (TOTP) settings for an account changes.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Remove TOTP (deprecated)</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Keycloak removes TOTP from an account.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Remove Credential</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Keycloak removes a credential from an account.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Send Verify Email</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Keycloak sends an email verification email.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Verify Email</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Keycloak verifies the email address for an account.</p></td> </tr> </tbody> </table> <div class="paragraph"> <p>Each event has a corresponding error event.</p> </div> </div> <div class="sect3"> <h4 id="event-listener"><a class="anchor" href="#event-listener"></a>Event listener</h4> <div class="paragraph"> <p>Event listeners listen for events and perform actions based on that event. Keycloak includes two built-in listeners, the Logging Event Listener and Email Event Listener.</p> </div> <div class="sect4"> <h5 id="the-logging-event-listener"><a class="anchor" href="#the-logging-event-listener"></a>The logging event listener</h5> <div class="paragraph"> <p>When the Logging Event Listener is enabled, this listener writes to a log file when an error event occurs.</p> </div> <div class="paragraph"> <p>An example log message from a Logging Event Listener:</p> </div> <div class="listingblock"> <div class="content"> <pre>11:36:09,965 WARN [org.keycloak.events] (default task-51) type=LOGIN_ERROR, realmId=master, clientId=myapp, userId=19aeb848-96fc-44f6-b0a3-59a17570d374, ipAddress=127.0.0.1, error=invalid_user_credentials, auth_method=openid-connect, auth_type=code, redirect_uri=http://localhost:8180/myapp, code_id=b669da14-cdbb-41d0-b055-0810a0334607, username=admin</pre> </div> </div> <div class="paragraph"> <p>You can use the Logging Event Listener to protect against hacker bot attacks:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Parse the log file for the <code>LOGIN_ERROR</code> event.</p> </li> <li> <p>Extract the IP Address of the failed login event.</p> </li> <li> <p>Send the IP address to an intrusion prevention software framework tool.</p> </li> </ol> </div> <div class="paragraph"> <p>The Logging Event Listener logs events to the <code>org.keycloak.events</code> log category. Keycloak does not include debug log events in server logs, by default.</p> </div> <div class="paragraph"> <p>To include debug log events in server logs:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Change the log level for the <code>org.keycloak.events</code> category</p> </li> <li> <p>Change the log level used by the Logging Event listener.</p> </li> </ol> </div> <div class="paragraph"> <p>To change the log level used by the Logging Event listener, add the following:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">bin/kc.[sh|bat] start --spi-events-listener-jboss-logging-success-level=info --spi-events-listener-jboss-logging-error-level=error</code></pre> </div> </div> <div class="paragraph"> <p>The valid values for log levels are <code>debug</code>, <code>info</code>, <code>warn</code>, <code>error</code>, and <code>fatal</code>.</p> </div> </div> <div class="sect4"> <h5 id="the-email-event-listener"><a class="anchor" href="#the-email-event-listener"></a>The Email Event Listener</h5> <div class="paragraph"> <p>The Email Event Listener sends a message to the user&#8217;s email address when an event occurs and supports the following events:</p> </div> <div class="ulist"> <ul> <li> <p>Login Error.</p> </li> <li> <p>Update Password.</p> </li> <li> <p>Update Time-based One-time Password (TOTP).</p> </li> <li> <p>Remove One-time Password (OTP).</p> </li> <li> <p>Update Credential.</p> </li> <li> <p>Remove Credential.</p> </li> </ul> </div> <div class="paragraph"> <p>The following conditions need to be met for an email to be sent:</p> </div> <div class="ulist"> <ul> <li> <p>User has an email address.</p> </li> <li> <p>User&#8217;s email address is marked as verified.</p> </li> </ul> </div> <div class="ulist"> <div class="title">Prerequisites</div> <ul> <li> <p>Realm&#8217;s email settings configured.</p> </li> </ul> </div> <div class="paragraph"> <div class="title">Procedure</div> <p>To enable the Email Listener:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Click <strong>Realm settings</strong> in the menu.</p> </li> <li> <p>Click the <strong>Events</strong> tab.</p> </li> <li> <p>Click the <strong>Event listeners</strong> field.</p> </li> <li> <p>Select <code>email</code>.</p> <div class="paragraph"> <div class="title">Event listeners</div> <p><span class="image"><img src="./images/event-listeners.png" alt="Event listeners"></span></p> </div> </li> </ol> </div> <div class="paragraph"> <p>You can exclude events by using the <code>--spi-events-listener-email-exclude-events</code> argument. For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">kc.[sh|bat] --spi-events-listener-email-exclude-events=UPDATE_CREDENTIAL,REMOVE_CREDENTIAL</code></pre> </div> </div> </div> </div> </div> <div class="sect2"> <h3 id="auditing-admin-events"><a class="anchor" href="#auditing-admin-events"></a>Auditing admin events</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/events/admin.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/events/admin.adoc&amp;description=%0A%0AFile:%20server_admin/topics/events/admin.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>You can record all actions that are performed by an administrator in the Admin Console. The Admin Console performs administrative actions by invoking the Keycloak REST interface and Keycloak audits these REST invocations. You can view the resulting events in the Admin Console.</p> </div> <div class="paragraph"> <div class="title">Procedure</div> <p>Use this procedure to start auditing admin actions.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Click <strong>Realm settings</strong> in the menu.</p> </li> <li> <p>Click the <strong>Events</strong> tab.</p> </li> <li> <p>Click the <strong>Admin events settings</strong> tab.</p> </li> <li> <p>Toggle <strong>Save events</strong> to <strong>ON</strong>.</p> <div class="paragraph"> <p>Keycloak displays the <strong>Include representation</strong> switch.</p> </div> </li> <li> <p>Toggle <strong>Include representation</strong> to <strong>ON</strong>.</p> <div class="paragraph"> <p>The <code>Include Representation</code> switch includes JSON documents sent through the admin REST API so you can view the administrators actions.</p> </div> <div class="paragraph"> <div class="title">Admin events settings</div> <p><span class="image"><img src="./images/admin-events-settings.png" alt="Admin events settings"></span></p> </div> </li> <li> <p>Click <strong>Save</strong>.</p> </li> <li> <p>To clear the database of stored actions, click <strong>Clear admin events</strong>.</p> </li> </ol> </div> <div class="paragraph"> <div class="title">Procedure</div> <p>You can now view admin events.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Click <strong>Events</strong> in the menu.</p> </li> <li> <p>Click the <strong>Admin events</strong> tab.</p> <div class="paragraph"> <div class="title">Admin events</div> <p><span class="image"><img src="./images/admin-events.png" alt="Admin events"></span></p> </div> </li> </ol> </div> <div class="paragraph"> <p>When the <code>Include Representation</code> switch is ON, it can lead to storing a lot of information in the database. You can set a maximum length of the representation by using the <code>--spi-events-store-jpa-max-field-length</code> argument. This setting is useful if you want to adhere to the underlying storage limitation. For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">kc.[sh|bat] --spi-events-store-jpa-max-field-length=2500</code></pre> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="mitigating_security_threats"><a class="anchor" href="#mitigating_security_threats"></a>Mitigating security threats</h2> <div class="sectionbody"> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/threat.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/threat.adoc&amp;description=%0A%0AFile:%20server_admin/topics/threat.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Security vulnerabilities exist in any authentication server. See the Internet Engineering Task Force&#8217;s (IETF) <a href="https://datatracker.ietf.org/doc/html/rfc6819">OAuth 2.0 Threat Model</a> and the <a href="https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics">OAuth 2.0 Security Best Current Practice</a> for more information.</p> </div> <div class="sect2"> <h3 id="host"><a class="anchor" href="#host"></a>Host</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/threat/host.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/threat/host.adoc&amp;description=%0A%0AFile:%20server_admin/topics/threat/host.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Keycloak uses the public hostname in several ways, such as within token issuer fields and URLs in password reset emails.</p> </div> <div class="paragraph"> <p>By default, the hostname derives from request headers. No validation exists to ensure a hostname is valid. If you are not using a load balancer, or proxy, with Keycloak to prevent invalid host headers, configure the acceptable hostnames.</p> </div> <div class="paragraph"> <p>The hostname&#8217;s Service Provider Interface (SPI) provides a way to configure the hostname for requests. You can use this built-in provider to set a fixed URL for frontend requests while allowing backend requests based on the request URI. If the built-in provider does not have the required capability, you can develop a customized provider.</p> </div> </div> <div class="sect2"> <h3 id="admin-endpoints-and-admin-console"><a class="anchor" href="#admin-endpoints-and-admin-console"></a>Admin endpoints and Admin Console</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/threat/admin.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/threat/admin.adoc&amp;description=%0A%0AFile:%20server_admin/topics/threat/admin.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Keycloak exposes the administrative REST API and the web console on the same port as non-administrative usage. Do not expose administrative endpoints externally if external access is not necessary.</p> </div> </div> <div class="sect2"> <h3 id="password-guess-brute-force-attacks"><a class="anchor" href="#password-guess-brute-force-attacks"></a>Brute force attacks</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/threat/brute-force.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/threat/brute-force.adoc&amp;description=%0A%0AFile:%20server_admin/topics/threat/brute-force.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>A brute force attack attempts to guess a user&#8217;s password by trying to log in multiple times. Keycloak has brute force detection capabilities and can temporarily disable a user account if the number of login failures exceeds a specified threshold.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>Keycloak disables brute force detection by default. Enable this feature to protect against brute force attacks.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <div class="title">Procedure</div> <p>To enable this protection:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Click <strong>Realm Settings</strong> in the menu</p> </li> <li> <p>Click the <strong>Security Defenses</strong> tab.</p> </li> <li> <p>Click the <strong>Brute Force Detection</strong> tab.</p> <div class="paragraph"> <div class="title">Brute force detection</div> <p><span class="image"><img src="./images/brute-force.png" alt="brute force"></span></p> </div> </li> </ol> </div> <div class="paragraph"> <p>Keycloak can deploy permanent lockout and temporary lockout actions when it detects an attack. Permanent lockout disables a user account until an administrator re-enables it. Temporary lockout disables a user account for a specific period of time. The time period that the account is disabled increases as the attack continues and subsequent failures reach multiples of <code>Max Login Failures</code>.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>When a user is temporarily locked and attempts to log in, Keycloak displays the default <code>Invalid username or password</code> error message. This message is the same error message as the message displayed for an invalid username or invalid password to ensure the attacker is unaware the account is disabled.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p><strong>Common Parameters</strong></p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 33.3333%;"> <col style="width: 33.3333%;"> <col style="width: 33.3334%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Name</th> <th class="tableblock halign-left valign-top">Description</th> <th class="tableblock halign-left valign-top">Default</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Max Login Failures</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The maximum number of login failures.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">30 failures.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Quick Login Check Milliseconds</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The minimum time between login attempts.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">1000 milliseconds.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Minimum Quick Login Wait</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The minimum time the user is disabled when login attempts are quicker than <em>Quick Login Check Milliseconds</em>.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">1 minute.</p></td> </tr> </tbody> </table> <div class="paragraph"> <p><strong>Temporary Lockout Parameters</strong></p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 33.3333%;"> <col style="width: 33.3333%;"> <col style="width: 33.3334%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Name</th> <th class="tableblock halign-left valign-top">Description</th> <th class="tableblock halign-left valign-top">Default</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Wait Increment</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The time added to the time a user is temporarily disabled when the user&#8217;s login attempts exceed <em>Max Login Failures</em>.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">1 minute.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Max Wait</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The maximum time a user is temporarily disabled.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">15 minutes.</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Failure Reset Time</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The time when the failure count resets. The timer runs from the last failed login. Make sure this number is always greater than <code>Max wait</code>; otherwise the effective wait time will never reach the value you have set to <code>Max wait</code>.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">12 hours.</p></td> </tr> </tbody> </table> <div class="paragraph"> <p><strong>Temporary Lockout Algorithm</strong></p> </div> <div class="exampleblock"> <div class="content"> <div class="olist arabic"> <ol class="arabic"> <li> <p>On successful login</p> <div class="olist loweralpha"> <ol class="loweralpha" type="a"> <li> <p>Reset <code>count</code></p> </li> </ol> </div> </li> <li> <p>On failed login</p> <div class="olist loweralpha"> <ol class="loweralpha" type="a"> <li> <p>If the time between this failure and the last failure is greater than <em>Failure Reset Time</em></p> <div class="olist lowerroman"> <ol class="lowerroman" type="i"> <li> <p>Reset <code>count</code></p> </li> </ol> </div> </li> <li> <p>Increment <code>count</code></p> </li> <li> <p>Calculate <code>wait</code> according the brute force strategy defined (see below Strategies to set Wait Time).</p> </li> <li> <p>If <code>wait</code> equals is less than 0 and the time between this failure and the last failure is less than <em>Quick Login Check Milliseconds</em>, set <code>wait</code> to <em>Minimum Quick Login Wait</em>.</p> <div class="olist lowerroman"> <ol class="lowerroman" type="i"> <li> <p>Temporarily disable the user for the smallest of <code>wait</code> and <em>Max Wait</em> seconds</p> </li> <li> <p>Increment the temporary lockout counter</p> </li> </ol> </div> </li> </ol> </div> </li> </ol> </div> <div class="paragraph"> <p><code>count</code> does not increment when a temporarily disabled account commits a login failure.</p> </div> </div> </div> <div class="paragraph"> <p><strong>Strategies to set Wait Time</strong></p> </div> <div class="paragraph"> <p>Keycloak provides two strategies to calculate wait time: By multiples or Linear. By multiples is the first strategy introduced by Keycloak, so that is the default one.</p> </div> <div class="paragraph"> <p>By multiples strategy, wait time is incremented when the number (or count) of failures are multiples of <code>Max Login Failure</code>. For instance, if you set <code>Max Login Failures</code> to <code>5</code> and a <code>Wait Increment</code> to <code>30</code> seconds, the effective time that an account is disabled after several failed authentication attempts will be:</p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 25%;"> <col style="width: 25%;"> <col style="width: 25%;"> <col style="width: 25%;"> </colgroup> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>Number of Failures</code></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>Wait Increment</code></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>Max Login Failures</code></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>Effective Wait Time</code></p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">1</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">30</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">0</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">2</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">30</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">0</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">3</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">30</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">0</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">4</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">30</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">0</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>5</strong></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>30</strong></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>30</strong></p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">6</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">30</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">30</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">7</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">30</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">30</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">8</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">30</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">30</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">9</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">30</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">30</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>10</strong></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>30</strong></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>60</strong></p></td> </tr> </tbody> </table> <div class="paragraph"> <p>At the fifth failed attempt of the <code>Effective Wait Time</code>, the account is disabled for <code>30</code> seconds. After reaching the next multiple of <code>Max Login Failures</code>, in this case <code>10</code>, the time increases from <code>30</code> to <code>60</code> seconds.</p> </div> <div class="paragraph"> <p>The By multiple strategy uses the following formula to calculate wait time: <em>Wait Increment</em> * (<code>count</code> / <em>Max Login Failures</em>). The division is an integer division rounded down to a whole number.</p> </div> <div class="paragraph"> <p>For linear strategy, wait time is incremented when the number (or count) of failures equals or is greater than <code>Max Login Failure</code>. For instance, if you have set <code>Max Login Failures</code> to <code>5</code> and a <code>Wait Increment</code> to`30` seconds, the effective time that an account is disabled after several failed authentication attempts will be:</p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 25%;"> <col style="width: 25%;"> <col style="width: 25%;"> <col style="width: 25%;"> </colgroup> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>Number of Failures</code></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>Wait Increment</code></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>Max Login Failures</code></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>Effective Wait Time</code></p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">1</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">30</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">0</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">2</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">30</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">0</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">3</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">30</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">0</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">4</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">30</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">0</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>5</strong></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>30</strong></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>30</strong></p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>6</strong></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>30</strong></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>60</strong></p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>7</strong></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>30</strong></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>90</strong></p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>8</strong></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>30</strong></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>120</strong></p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>9</strong></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>30</strong></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>150</strong></p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>10</strong></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>30</strong></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>180</strong></p></td> </tr> </tbody> </table> <div class="paragraph"> <p>At the fifth failed attempt for the <code>Effective Wait Time</code>, the account is disabled for <code>30</code> seconds. Each new failed attempt increases wait time.</p> </div> <div class="paragraph"> <p>The linear strategy uses the following formula to calculate wait time: <em>Wait Increment</em> * (1 + <code>count</code> - <em>Max Login Failures</em>).</p> </div> <div class="paragraph"> <p><strong>Permanent Lockout Parameters</strong></p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 33.3333%;"> <col style="width: 33.3333%;"> <col style="width: 33.3334%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Name</th> <th class="tableblock halign-left valign-top">Description</th> <th class="tableblock halign-left valign-top">Default</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Max temporary Lockouts</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">The maximum number of temporary lockouts permitted before permanent lockout occurs.</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">0</p></td> </tr> </tbody> </table> <div class="paragraph"> <p><strong>Permanent Lockout Flow</strong></p> </div> <div class="exampleblock"> <div class="content"> <div class="olist arabic"> <ol class="arabic"> <li> <p>Follow temporary lockout flow</p> </li> <li> <p>If temporary lockout counter exceeds Max temporary lockouts</p> <div class="olist loweralpha"> <ol class="loweralpha" type="a"> <li> <p>Permanently disable user</p> </li> </ol> </div> </li> </ol> </div> <div class="paragraph"> <p>When Keycloak disables a user, the user cannot log in until an administrator enables the user. Enabling an account resets the <code>count</code>.</p> </div> </div> </div> <div class="paragraph"> <p>The downside of Keycloak brute force detection is that the server becomes vulnerable to denial of service attacks. When implementing a denial of service attack, an attacker can attempt to log in by guessing passwords for any accounts it knows and eventually causing Keycloak to disable the accounts.</p> </div> <div class="paragraph"> <p>Consider using intrusion prevention software (IPS). Keycloak logs every login failure and client IP address failure. You can point the IPS to the Keycloak server&#8217;s log file, and the IPS can modify firewalls to block connections from these IP addresses.</p> </div> <div class="sect3"> <h4 id="password-policies"><a class="anchor" href="#password-policies"></a>Password policies</h4> <div class="paragraph"> <p>Ensure you have a complex password policy to force users to choose complex passwords. See the <a href="#_password-policies">Password Policies</a> chapter for more information. Prevent password guessing by setting up the Keycloak server to use one-time-passwords.</p> </div> </div> </div> <div class="sect2"> <h3 id="read_only_user_attributes"><a class="anchor" href="#read_only_user_attributes"></a>Read-only user attributes</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/threat/read-only-attributes.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/threat/read-only-attributes.adoc&amp;description=%0A%0AFile:%20server_admin/topics/threat/read-only-attributes.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Typical users who are stored in Keycloak have various attributes related to their user profiles. Such attributes include email, firstName or lastName. However users may also have attributes, which are not typical profile data, but rather metadata. The metadata attributes usually should be read-only for the users and the typical users never should have a way to update those attributes from the Keycloak user interface or Account REST API. Some of the attributes should be even read-only for the administrators when creating or updating user with the Admin REST API.</p> </div> <div class="paragraph"> <p>The metadata attributes are usually attributes from those groups:</p> </div> <div class="ulist"> <ul> <li> <p>Various links or metadata related to the user storage providers. For example in case of the LDAP integration, the <code>LDAP_ID</code> attribute contains the ID of the user in the LDAP server.</p> </li> <li> <p>Metadata provisioned by User Storage. For example <code>createdTimestamp</code> provisioned from the LDAP should be always read-only by user or administrator.</p> </li> <li> <p>Metadata related to various authenticators. For example <code>KERBEROS_PRINCIPAL</code> attribute can contain the kerberos principal name of the particular user. Similarly attribute <code>usercertificate</code> can contain metadata related to binding the user with the data from the X.509 certificate, which is used typically when X.509 certificate authentication is enabled.</p> </li> <li> <p>Metadata related to the identificator of users by the applications/clients. For example <code>saml.persistent.name.id.for.my_app</code> can contain SAML NameID, which will be used by the client application <code>my_app</code> as the identifier of the user.</p> </li> <li> <p>Metadata related to the authorization policies, which are used for the attribute based access control (ABAC). Values of those attributes may be used for the authorization decisions. Hence it is important that those attributes cannot be updated by the users.</p> </li> </ul> </div> <div class="paragraph"> <p>From the long term perspective, Keycloak will have a proper User Profile SPI, which will allow fine-grained configuration of every user attribute. Currently this capability is not fully available yet. So Keycloak has the internal list of user attributes, which are read-only for the users and read-only for the administrators configured at the server level.</p> </div> <div class="paragraph"> <p>This is the list of the read-only attributes, which are used internally by the Keycloak default providers and functionalities and hence are always read-only:</p> </div> <div class="ulist"> <ul> <li> <p>For users: <code>KERBEROS_PRINCIPAL</code>, <code>LDAP_ID</code>, <code>LDAP_ENTRY_DN</code>, <code>CREATED_TIMESTAMP</code>, <code>createTimestamp</code>, <code>modifyTimestamp</code>, <code>userCertificate</code>, <code>saml.persistent.name.id.for.*</code>, <code>ENABLED</code>, <code>EMAIL_VERIFIED</code></p> </li> <li> <p>For administrators: <code>KERBEROS_PRINCIPAL</code>, <code>LDAP_ID</code>, <code>LDAP_ENTRY_DN</code>, <code>CREATED_TIMESTAMP</code>, <code>createTimestamp</code>, <code>modifyTimestamp</code></p> </li> </ul> </div> <div class="paragraph"> <p>System administrators have a way to add additional attributes to this list. The configuration is currently available at the server level.</p> </div> <div class="paragraph"> <p>You can add this configuration by using the <code>spi-user-profile-declarative-user-profile-read-only-attributes</code> and <code>`spi-user-profile-declarative-user-profile-admin-read-only-attributes</code> options. For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight nowrap"><code data-lang="bash">kc.[sh|bat] start --spi-user-profile-declarative-user-profile-read-only-attributes=foo,bar*</code></pre> </div> </div> <div class="paragraph"> <p>For this example, users and administrators would not be able to update attribute <code>foo</code>. Users would not be able to edit any attributes starting with the <code>bar</code>. So for example <code>bar</code> or <code>barrier</code>. Configuration is case-insensitive, so attributes like <code>FOO</code> or <code>BarRier</code> will be denied as well for this example. The wildcard character <code>*</code> is supported only at the end of the attribute name, so the administrator can effectively deny all the attributes starting with the specified character. The <code>*</code> in the middle of the attribute is considered as a normal character.</p> </div> </div> <div class="sect2"> <h3 id="validate_user_attributes"><a class="anchor" href="#validate_user_attributes"></a>Validate user attributes</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/threat/validate-user-attributes.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/threat/validate-user-attributes.adoc&amp;description=%0A%0AFile:%20server_admin/topics/threat/validate-user-attributes.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>With the functionality in <a href="#user-profile">Managing user attributes</a>, administrators can restrict the data users enter for attributes, for example, in user registration or the account console.</p> </div> <div class="paragraph"> <p>Administrators should not allow unmanaged attributes for users to prevent attackers adding an unlimited number of attributes. Attributes should have a validation that restricts the amount of data entered by attackers.</p> </div> <div class="paragraph"> <p>When using regular expressions to validate user attributes, avoid regular expressions that use an excessive amount of memory or CPU. See <a href="https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS">OWASP&#8217;s Regular expression Denial of Service</a> for details.</p> </div> </div> <div class="sect2"> <h3 id="clickjacking"><a class="anchor" href="#clickjacking"></a>Clickjacking</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/threat/clickjacking.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/threat/clickjacking.adoc&amp;description=%0A%0AFile:%20server_admin/topics/threat/clickjacking.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Clickjacking is a technique of tricking users into clicking on a user interface element different from what users perceive. A malicious site loads the target site in a transparent iFrame, overlaid on top of a set of dummy buttons placed directly under important buttons on the target site. When a user clicks a visible button, they are clicking a button on the hidden page. An attacker can steal a user&#8217;s authentication credentials and access their resources by using this method.</p> </div> <div class="paragraph"> <p>By default, every response by Keycloak sets some specific HTTP headers that can prevent this from happening. Specifically, it sets <a href="https://datatracker.ietf.org/doc/html/rfc7034">X-Frame-Options</a> and <a href="https://www.w3.org/TR/CSP/">Content-Security-Policy</a>. You should take a look at the definition of both of these headers as there is a lot of fine-grain browser access you can control.</p> </div> <div class="paragraph"> <div class="title">Procedure</div> <p>In the Admin Console, you can specify the values of the X-Frame-Options and Content-Security-Policy headers.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Click the <strong>Realm Settings</strong> menu item.</p> </li> <li> <p>Click the <strong>Security Defenses</strong> tab.</p> <div class="paragraph"> <div class="title">Security Defenses</div> <p><span class="image"><img src="./images/security-headers.png" alt="Security Defenses"></span></p> </div> </li> </ol> </div> <div class="paragraph"> <p>By default, Keycloak only sets up a <em>same-origin</em> policy for iframes.</p> </div> </div> <div class="sect2"> <h3 id="sslhttps-requirement"><a class="anchor" href="#sslhttps-requirement"></a>SSL/HTTPS requirement</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/threat/ssl.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/threat/ssl.adoc&amp;description=%0A%0AFile:%20server_admin/topics/threat/ssl.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>OAuth 2.0/OpenID Connect uses access tokens for security. Attackers can scan your network for access tokens and use them to perform malicious operations for which the token has permission. This attack is known as a man-in-the-middle attack. Use SSL/HTTPS for communication between the Keycloak auth server and the clients Keycloak secures to prevent man-in-the-middle attacks.</p> </div> <div class="paragraph"> <p>Keycloak has <a href="#_ssl_modes">three modes for SSL/HTTPS</a>. SSL is complex to set up, so Keycloak allows non-HTTPS communication over private IP addresses such as localhost, 192.168.x.x, and other private IP addresses. In production, ensure you enable SSL and SSL is compulsory for all operations.</p> </div> <div class="paragraph"> <p>On the adapter/client-side, you can disable the SSL trust manager. The trust manager ensures the client&#8217;s identity that Keycloak communicates with is valid and ensures the DNS domain name against the server&#8217;s certificate. In production, ensure that each of your client adapters uses a truststore to prevent DNS man-in-the-middle attacks.</p> </div> </div> <div class="sect2"> <h3 id="csrf-attacks"><a class="anchor" href="#csrf-attacks"></a>CSRF attacks</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/threat/csrf.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/threat/csrf.adoc&amp;description=%0A%0AFile:%20server_admin/topics/threat/csrf.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>A Cross-site request forgery (CSRF) attack uses HTTP requests from users that websites have already authenticated. Any site using cookie-based authentication is vulnerable to CSRF attacks. You can mitigate these attacks by matching a state cookie against a posted form or query parameter.</p> </div> <div class="paragraph"> <p>The OAuth 2.0 login specification requires that a state cookie matches against a transmitted state parameter. Keycloak fully implements this part of the specification, so all logins are protected.</p> </div> <div class="paragraph"> <p>The Keycloak Admin Console is a JavaScript/HTML5 application that makes REST calls to the backend Keycloak admin REST API. These calls all require bearer token authentication and consist of JavaScript Ajax calls, so CSRF is impossible. You can configure the admin REST API to validate the CORS origins.</p> </div> <div class="paragraph"> <p>The Account Console in Keycloak can be vulnerable to CSRF. To prevent CSRF attacks, Keycloak sets a state cookie and embeds the value of this cookie in hidden form fields or query parameters within action links. Keycloak checks the query/form parameter against the state cookie to verify that the same user made the call.</p> </div> </div> <div class="sect2"> <h3 id="unspecific-redirect-uris_server_administration_guide"><a class="anchor" href="#unspecific-redirect-uris_server_administration_guide"></a>Unspecific redirect URIs</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/threat/redirect.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/threat/redirect.adoc&amp;description=%0A%0AFile:%20server_admin/topics/threat/redirect.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Make your registered redirect URIs as specific as feasible. Registering vague redirect URIs for <a href="#con-oidc-auth-flows_server_administration_guide">Authorization Code Flows</a> can allow malicious clients to impersonate another client with broader access. Impersonation can happen if two clients live under the same domain, for example.</p> </div> <div class="paragraph"> <p>You can use secure redirect uris enforcer executor for your realm. The result makes sure that client administrators are able to register only clients with specific redirect-uris matching various requirements such as requiring that a URL cannot have wildcards in the context path or can be limited to specified permitted domains. See <a href="#_client_policies">Client Policies</a> for details about how to configure client policies with a specific executor.</p> </div> </div> <div class="sect2"> <h3 id="fapi-compliance"><a class="anchor" href="#fapi-compliance"></a>FAPI compliance</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/threat/fapi-compliance.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/threat/fapi-compliance.adoc&amp;description=%0A%0AFile:%20server_admin/topics/threat/fapi-compliance.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>To make sure that Keycloak server will validate your client to be more secure and FAPI compliant, you can configure client policies for the FAPI support. <strong>FAPI</strong> details are described in the <a href="https://www.keycloak.org/guides#securing-apps">securing apps</a> section. Among other things, this ensures some security best practices described above like SSL required for clients, secure redirect URI used and more of similar best practices.</p> </div> </div> <div class="sect2"> <h3 id="oauth-2-1-compliance"><a class="anchor" href="#oauth-2-1-compliance"></a>OAuth 2.1 compliance</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/threat/oauth21-compliance.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/threat/oauth21-compliance.adoc&amp;description=%0A%0AFile:%20server_admin/topics/threat/oauth21-compliance.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>To make sure that Keycloak server will validate your client to be more secure and OAuth 2.1 compliant, you can configure client policies for the OAuth 2.1 support. <strong>OAuth 2.1</strong> details are described in the <a href="https://www.keycloak.org/guides#securing-apps">securing apps</a> section.</p> </div> </div> <div class="sect2"> <h3 id="compromised-access-and-refresh-tokens"><a class="anchor" href="#compromised-access-and-refresh-tokens"></a>Compromised access and refresh tokens</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/threat/compromised-tokens.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/threat/compromised-tokens.adoc&amp;description=%0A%0AFile:%20server_admin/topics/threat/compromised-tokens.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Keycloak includes several actions to prevent malicious actors from stealing access tokens and refresh tokens. The crucial action is to enforce SSL/HTTPS communication between Keycloak and its clients and applications. Keycloak does not enable SSL by default.</p> </div> <div class="paragraph"> <p>Another action to mitigate damage from leaked access tokens is to shorten the token&#8217;s lifespans. You can specify token lifespans within the <a href="#_timeouts">timeouts page</a>. Short lifespans for access tokens force clients and applications to refresh their access tokens after a short time. If an admin detects a leak, the admin can log out all user sessions to invalidate these refresh tokens or set up a revocation policy.</p> </div> <div class="paragraph"> <p>Ensure refresh tokens always stay private to the client and are never transmitted.</p> </div> <div class="paragraph"> <p>You can mitigate damage from leaked access tokens and refresh tokens by issuing these tokens as holder-of-key tokens. See <a href="#_mtls-client-certificate-bound-tokens">OAuth 2.0 Mutual TLS Client Certificate Bound Access Token</a> for more information.</p> </div> <div class="paragraph"> <p>If an access token or refresh token is compromised, access the Admin Console and push a not-before revocation policy to all applications. Pushing a not-before policy ensures that any tokens issued before that time become invalid. Pushing a new not-before policy ensures that applications must download new public keys from Keycloak and mitigate damage from a compromised realm signing key. See the <a href="#realm_keys">keys chapter</a> for more information.</p> </div> <div class="paragraph"> <p>You can disable specific applications, clients, or users if they are compromised.</p> </div> </div> <div class="sect2"> <h3 id="compromised-authorization-code"><a class="anchor" href="#compromised-authorization-code"></a>Compromised authorization code</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/threat/compromised-codes.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/threat/compromised-codes.adoc&amp;description=%0A%0AFile:%20server_admin/topics/threat/compromised-codes.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>For the <a href="#con-oidc-auth-flows_server_administration_guide">OIDC Auth Code Flow</a>, Keycloak generates a cryptographically strong random value for its authorization codes. An authorization code is used only once to obtain an access token.</p> </div> <div class="paragraph"> <p>On the <a href="#_timeouts">timeouts page</a> in the Admin Console, you can specify the length of time an authorization code is valid. Ensure that the length of time is less than 10 seconds, which is long enough for a client to request a token from the code.</p> </div> <div class="paragraph"> <p>You can also defend against leaked authorization codes by applying <a href="#_proof-key-for-code-exchange">Proof Key for Code Exchange (PKCE)</a> to clients.</p> </div> </div> <div class="sect2"> <h3 id="open-redirectors"><a class="anchor" href="#open-redirectors"></a>Open redirectors</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/threat/open-redirect.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/threat/open-redirect.adoc&amp;description=%0A%0AFile:%20server_admin/topics/threat/open-redirect.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>An open redirector is an endpoint using a parameter to automatically redirect a user agent to the location specified by the parameter value without validation. An attacker can use the end-user authorization endpoint and the redirect URI parameter to use the authorization server as an open redirector, using a user&#8217;s trust in an authorization server to launch a phishing attack.</p> </div> <div class="paragraph"> <p>Keycloak requires that all registered applications and clients register at least one redirection URI pattern. When a client requests that Keycloak performs a redirect, Keycloak checks the redirect URI against the list of valid registered URI patterns. Clients and applications must register as specific a URI pattern as possible to mitigate open redirector attacks.</p> </div> <div class="paragraph"> <p>If an application requires a non http(s) custom scheme, it should be an explicit part of the validation pattern (for example <code>custom:/app/*</code>). For security reasons a general pattern like <code>*</code> does not cover non http(s) schemes.</p> </div> <div class="paragraph"> <p>By using <a href="#_client_policies">Client Policies</a>, an administrator can make sure that clients cannot register open redirect URLs such as <code>*</code>.</p> </div> </div> <div class="sect2"> <h3 id="password-database-compromised"><a class="anchor" href="#password-database-compromised"></a>Password database compromised</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/threat/password-db-compromised.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/threat/password-db-compromised.adoc&amp;description=%0A%0AFile:%20server_admin/topics/threat/password-db-compromised.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Keycloak does not store passwords in raw text but as hashed text, using the <code>PBKDF2-HMAC-SHA512</code> message digest algorithm. Keycloak performs <code>210,000</code> hashing iterations, the number of iterations recommended by the security community. This number of hashing iterations can adversely affect performance as PBKDF2 hashing uses a significant amount of CPU resources.</p> </div> </div> <div class="sect2"> <h3 id="limiting-scope"><a class="anchor" href="#limiting-scope"></a>Limiting scope</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/threat/scope.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/threat/scope.adoc&amp;description=%0A%0AFile:%20server_admin/topics/threat/scope.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>By default, new client applications have unlimited <code>role scope mappings</code>. Every access token for that client contains all permissions that the user has. If an attacker compromises the client and obtains the client&#8217;s access tokens, each system that the user can access is compromised.</p> </div> <div class="paragraph"> <p>Limit the roles of an access token by using the <a href="#_role_scope_mappings">Scope menu</a> for each client. Alternatively, you can set role scope mappings at the Client Scope level and assign Client Scopes to your client by using the <a href="#_client_scopes_linking">Client Scope menu</a>.</p> </div> </div> <div class="sect2"> <h3 id="limit-token-audience"><a class="anchor" href="#limit-token-audience"></a>Limit token audience</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/threat/audience-limit.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/threat/audience-limit.adoc&amp;description=%0A%0AFile:%20server_admin/topics/threat/audience-limit.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>In environments with low levels of trust among services, limit the audiences on the token. See the <a href="https://datatracker.ietf.org/doc/html/rfc6819#section-5.1.5.5">OAuth2 Threat Model</a> and the <a href="#audience-support">Audience Support</a> section for more information.</p> </div> </div> <div class="sect2"> <h3 id="_limit-authentication-sessions"><a class="anchor" href="#_limit-authentication-sessions"></a>Limit Authentication Sessions</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/threat/auth-sessions-limit.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/threat/auth-sessions-limit.adoc&amp;description=%0A%0AFile:%20server_admin/topics/threat/auth-sessions-limit.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p><a href="#_authentication-sessions">Authentication sessions</a> track the state of the authentication. The text below is applicable regardless of the source flow.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> This section describes deployments that use the Infinispan provider for authentication sessions. </td> </tr> </table> </div> <div class="paragraph"> <p>Authentication session is internally stored as <code>RootAuthenticationSessionEntity</code>. Each <code>RootAuthenticationSessionEntity</code> can have multiple authentication sub-sessions stored within the <code>RootAuthenticationSessionEntity</code> as a collection of <code>AuthenticationSessionEntity</code> objects. Keycloak stores authentication sessions in a dedicated Infinispan cache. The number of <code>AuthenticationSessionEntity</code> per <code>RootAuthenticationSessionEntity</code> contributes to the size of each cache entry. Total memory footprint of authentication session cache is determined by the number of stored <code>RootAuthenticationSessionEntity</code> and by the number of <code>AuthenticationSessionEntity</code> within each <code>RootAuthenticationSessionEntity</code>.</p> </div> <div class="paragraph"> <p>The number of maintained <code>RootAuthenticationSessionEntity</code> objects corresponds to the number of unfinished login flows from the browser. To keep the number of <code>RootAuthenticationSessionEntity</code> under control, using an advanced firewall control to limit ingress network traffic is recommended.</p> </div> <div class="paragraph"> <p>Higher memory usage may occur for deployments where there are many active <code>RootAuthenticationSessionEntity</code> with a lot of <code>AuthenticationSessionEntity</code>. If the load balancer does not support or is not configured for session stickiness, the load over network in a cluster can increase significantly. The reason for this load is that each request that lands on a node that does not own the appropriate authentication session needs to retrieve and update the authentication session record in the owner node which involves a separate network transmission for both the retrieval and the storage.</p> </div> <div class="paragraph"> <p>The maximum number of <code>AuthenticationSessionEntity</code> per <code>RootAuthenticationSessionEntity</code> can be configured in <code>authenticationSessions</code> SPI by setting property <code>authSessionsLimit</code>. The default value is set to 300 <code>AuthenticationSessionEntity</code> per a <code>RootAuthenticationSessionEntity</code>. When this limit is reached, the oldest authentication sub-session will be removed after a new authentication session request.</p> </div> <div class="paragraph"> <p>The following example shows how to limit the number of active <code>AuthenticationSessionEntity</code> per a <code>RootAuthenticationSessionEntity</code> to 100.</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">bin/kc.[sh|bat] start --spi-authentication-sessions-infinispan-auth-sessions-limit=100</code></pre> </div> </div> <div class="paragraph"> <p>The equivalent command for the new map storage:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">bin/kc.[sh|bat] start --spi-authentication-sessions-map-auth-sessions-limit=100</code></pre> </div> </div> </div> <div class="sect2"> <h3 id="sql-injection-attacks"><a class="anchor" href="#sql-injection-attacks"></a>SQL injection attacks</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/threat/sql.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/threat/sql.adoc&amp;description=%0A%0AFile:%20server_admin/topics/threat/sql.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Currently, Keycloak has no known SQL injection vulnerabilities.</p> </div> </div> </div> </div> <div class="sect1"> <h2 id="_account-service"><a class="anchor" href="#_account-service"></a>Account Console</h2> <div class="sectionbody"> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/account.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/account.adoc&amp;description=%0A%0AFile:%20server_admin/topics/account.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>Keycloak users can manage their accounts through the Account Console. They can configure their profiles, add two-factor authentication, include identity provider accounts, and oversee device activity.</p> </div> <div class="ulist _additional-resources"> <div class="title">Additional resources</div> <ul> <li> <p>The Account Console can be configured in terms of appearance and language preferences. An example is adding additional attributes to the <strong>Personal info</strong> page. For more information, see the <a href="https://www.keycloak.org/docs/26.0.6/server_development/">Server Developer Guide</a>.</p> </li> </ul> </div> <div class="sect2"> <h3 id="accessing-the-account-console"><a class="anchor" href="#accessing-the-account-console"></a>Accessing the Account Console</h3> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Make note of the realm name and IP address for the Keycloak server where your account exists.</p> </li> <li> <p>In a web browser, enter a URL in this format: <em>server-root</em>/realms/{realm-name}/account.</p> </li> <li> <p>Enter your login name and password.</p> </li> </ol> </div> <div class="paragraph"> <div class="title">Account Console</div> <p><span class="image"><img src="./images/account-console-intro.png" alt="Account Console"></span></p> </div> </div> <div class="sect2"> <h3 id="configuring-ways-to-sign-in"><a class="anchor" href="#configuring-ways-to-sign-in"></a>Configuring ways to sign in</h3> <div class="paragraph"> <p>You can sign in to this console using basic authentication (a login name and password) or two-factor authentication. For two-factor authentication, use one of the following procedures.</p> </div> <div class="sect3"> <h4 id="two-factor-authentication-with-otp"><a class="anchor" href="#two-factor-authentication-with-otp"></a>Two-factor authentication with OTP</h4> <div class="ulist"> <div class="title">Prerequisites</div> <ul> <li> <p>OTP is a valid authentication mechanism for your realm.</p> </li> </ul> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Account security</strong> in the menu.</p> </li> <li> <p>Click <strong>Signing in</strong>.</p> </li> <li> <p>Click <strong>Set up Authenticator application</strong>.</p> <div class="paragraph"> <div class="title">Signing in</div> <p><span class="image"><img src="./images/account-console-signing-in.png" alt="Signing in"></span></p> </div> </li> <li> <p>Follow the directions that appear on the screen to use your mobile device as your OTP generator.</p> </li> <li> <p>Scan the QR code in the screen shot into the OTP generator on your mobile device.</p> </li> <li> <p>Log out and log in again.</p> </li> <li> <p>Respond to the prompt by entering an OTP that is provided on your mobile device.</p> </li> </ol> </div> </div> <div class="sect3"> <h4 id="two-factor-authentication-with-webauthn"><a class="anchor" href="#two-factor-authentication-with-webauthn"></a>Two-factor authentication with WebAuthn</h4> <div class="ulist"> <div class="title">Prerequisites</div> <ul> <li> <p>WebAuthn is a valid two-factor authentication mechanism for your realm. Please follow the <a href="#webauthn_server_administration_guide">WebAuthn</a> section for more details.</p> </li> </ul> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Account Security</strong> in the menu.</p> </li> <li> <p>Click <strong>Signing In</strong>.</p> </li> <li> <p>Click <strong>Set up a Passkey</strong>.</p> <div class="paragraph"> <div class="title">Signing In</div> <p><span class="image"><img src="./images/account-console-signing-in-webauthn-2factor.png" alt="Signing in with a Passkey"></span></p> </div> </li> <li> <p>Prepare your Passkey. How you prepare this key depends on the type of Passkey you use. For example, for a USB based Yubikey, you may need to put your key into the USB port on your laptop.</p> </li> <li> <p>Click <strong>Register</strong> to register your Passkey.</p> </li> <li> <p>Log out and log in again.</p> </li> <li> <p>Assuming authentication flow was correctly set, a message appears asking you to authenticate with your Passkey as second factor.</p> </li> </ol> </div> </div> <div class="sect3"> <h4 id="passwordless-authentication-with-webauthn"><a class="anchor" href="#passwordless-authentication-with-webauthn"></a>Passwordless authentication with WebAuthn</h4> <div class="ulist"> <div class="title">Prerequisites</div> <ul> <li> <p>WebAuthn is a valid passwordless authentication mechanism for your realm. Please follow the <a href="#_webauthn_passwordless">Passwordless WebAuthn section</a> for more details.</p> </li> </ul> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Account Security</strong> in the menu.</p> </li> <li> <p>Click <strong>Signing In</strong>.</p> </li> <li> <p>Click <strong>Set up a Passkey</strong> in the <strong>Passwordless</strong> section.</p> <div class="paragraph"> <div class="title">Signing In</div> <p><span class="image"><img src="./images/account-console-signing-in-webauthn-passwordless.png" alt="Signing in with a Passkey"></span></p> </div> </li> <li> <p>Prepare your Passkey. How you prepare this key depends on the type of Passkey you use. For example, for a USB based Yubikey, you may need to put your key into the USB port on your laptop.</p> </li> <li> <p>Click <strong>Register</strong> to register your Passkey.</p> </li> <li> <p>Log out and log in again.</p> </li> <li> <p>Assuming authentication flow was correctly set, a message appears asking you to authenticate with your Passkey as second factor. You no longer need to provide your password to log in.</p> </li> </ol> </div> </div> </div> <div class="sect2"> <h3 id="viewing-device-activity"><a class="anchor" href="#viewing-device-activity"></a>Viewing device activity</h3> <div class="paragraph"> <p>You can view the devices that are logged in to your account.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Click <strong>Account security</strong> in the menu.</p> </li> <li> <p>Click <strong>Device activity</strong>.</p> </li> <li> <p>Log out a device if it looks suspicious.</p> </li> </ol> </div> <div class="paragraph"> <div class="title">Devices</div> <p><span class="image"><img src="./images/account-console-device.png" alt="Devices"></span></p> </div> </div> <div class="sect2"> <h3 id="adding-an-identity-provider-account"><a class="anchor" href="#adding-an-identity-provider-account"></a>Adding an identity provider account</h3> <div class="paragraph"> <p>You can link your account with an <a href="#_identity_broker">identity broker</a>. This option is often used to link social provider accounts.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Log into the Admin Console.</p> </li> <li> <p>Click <strong>Identity providers</strong> in the menu.</p> </li> <li> <p>Select a provider and complete the fields.</p> </li> <li> <p>Return to the Account Console.</p> </li> <li> <p>Click <strong>Account security</strong> in the menu.</p> </li> <li> <p>Click <strong>Linked accounts</strong>.</p> </li> </ol> </div> <div class="paragraph"> <p>The identity provider you added appears in this page.</p> </div> <div class="paragraph"> <div class="title">Linked Accounts</div> <p><span class="image"><img src="./images/account-console-linked.png" alt="Linked Accounts"></span></p> </div> </div> <div class="sect2"> <h3 id="accessing-other-applications"><a class="anchor" href="#accessing-other-applications"></a>Accessing other applications</h3> <div class="paragraph"> <p>The <strong>Applications</strong> menu item shows users which applications you can access. In this case, only the Account Console is available.</p> </div> <div class="paragraph"> <div class="title">Applications</div> <p><span class="image"><img src="./images/account-console-applications.png" alt="Applications"></span></p> </div> </div> <div class="sect2"> <h3 id="viewing-group-memberships"><a class="anchor" href="#viewing-group-memberships"></a>Viewing group memberships</h3> <div class="paragraph"> <p>You can view the groups you are associated with by clicking the <strong>Groups</strong> menu. If you select <strong>Direct membership</strong> checkbox, you will see only the groups you are direct associated with.</p> </div> <div class="ulist"> <div class="title">Prerequisites</div> <ul> <li> <p>You need to have the <strong>view-groups</strong> account role for being able to view <strong>Groups</strong> menu.</p> </li> </ul> </div> <div class="paragraph"> <div class="title">View group memberships</div> <p><span class="image"><img src="./images/account-console-groups.png" alt="View group memberships"></span></p> </div> </div> </div> </div> <div class="sect1"> <h2 id="admin-cli"><a class="anchor" href="#admin-cli"></a>Admin CLI</h2> <div class="sectionbody"> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/server_admin/topics/admin-cli.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20server_admin/topics/admin-cli.adoc&amp;description=%0A%0AFile:%20server_admin/topics/admin-cli.adoc&amp;version=26.0.6&amp;behaviorExpected=%3C!--%20describe%20what%20you%20want%20to%20see%20in%20the%20docs%20--%3E&amp;behaviorActual=%3C!--%20describe%20what%20is%20currently%20wrong%20or%20missing%20in%20the%20docs%20--%3E&amp;reproducer=%3C!--%20list%20steps%20in%20the%20application%20that%20show%20behavior%20that%20should%20be%20documented%20--%3E" target="_blank" rel="noopener">Report an issue</a> </div> </div> <div class="paragraph"> <p>With Keycloak, you can perform administration tasks from the command-line interface (CLI) by using the Admin CLI command-line tool.</p> </div> <div class="sect2"> <h3 id="installing-the-admin-cli"><a class="anchor" href="#installing-the-admin-cli"></a>Installing the Admin CLI</h3> <div class="paragraph"> <p>Keycloak packages the Admin CLI server distribution with the execution scripts in the <code>bin</code> directory.</p> </div> <div class="paragraph"> <p>The Linux script is called <code>kcadm.sh</code>, and the script for Windows is called <code>kcadm.bat</code>. Add the Keycloak server directory to your <code>PATH</code> to use the client from any location on your file system.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="ulist"> <ul> <li> <p>Linux:</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ export PATH=$PATH:$KEYCLOAK_HOME/bin $ kcadm.sh</pre> </div> </div> </li> <li> <p>Windows:</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">c:\&gt; set PATH=%PATH%;%KEYCLOAK_HOME%\bin c:\&gt; kcadm</pre> </div> </div> </li> </ul> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>You must set the <code>KEYCLOAK_HOME</code> environment variable to the path where you extracted the Keycloak Server distribution.</p> </div> <div class="paragraph"> <p>To avoid repetition, the rest of this document only uses Windows examples in places where the CLI differences are more than just in the <code>kcadm</code> command name.</p> </div> </td> </tr> </table> </div> </div> <div class="sect2"> <h3 id="using-the-admin-cli"><a class="anchor" href="#using-the-admin-cli"></a>Using the Admin CLI</h3> <div class="paragraph"> <p>The Admin CLI makes HTTP requests to Admin REST endpoints. Access to the Admin REST endpoints requires authentication.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>Consult the Admin REST API documentation for details about JSON attributes for specific endpoints.</p> </div> </td> </tr> </table> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Start an authenticated session by logging in. You can now perform create, read, update, and delete (CRUD) operations.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="ulist"> <ul> <li> <p>Linux:</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh config credentials --server http://localhost:8080 --realm demo --user admin --client admin $ kcadm.sh create realms -s realm=demorealm -s enabled=true -o $ CID=$(kcadm.sh create clients -r demorealm -s clientId=my_client -s 'redirectUris=["http://localhost:8980/myapp/*"]' -i) $ kcadm.sh get clients/$CID/installation/providers/keycloak-oidc-keycloak-json</pre> </div> </div> </li> <li> <p>Windows:</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">c:\&gt; kcadm config credentials --server http://localhost:8080 --realm demo --user admin --client admin c:\&gt; kcadm create realms -s realm=demorealm -s enabled=true -o c:\&gt; kcadm create clients -r demorealm -s clientId=my_client -s "redirectUris=[\"http://localhost:8980/myapp/*\"]" -i &gt; clientid.txt c:\&gt; set /p CID=&lt;clientid.txt c:\&gt; kcadm get clients/%CID%/installation/providers/keycloak-oidc-keycloak-json</pre> </div> </div> </li> </ul> </div> </li> <li> <p>In a production environment, access Keycloak by using <code>https:</code> to avoid exposing tokens. If a trusted certificate authority, included in Java&#8217;s default certificate truststore, has not issued a server&#8217;s certificate, prepare a <code>truststore.jks</code> file and instruct the Admin CLI to use it.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="ulist"> <ul> <li> <p>Linux:</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh config truststore --trustpass $PASSWORD ~/.keycloak/truststore.jks</pre> </div> </div> </li> <li> <p>Windows:</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">c:\&gt; kcadm config truststore --trustpass %PASSWORD% %HOMEPATH%\.keycloak\truststore.jks</pre> </div> </div> </li> </ul> </div> </li> </ol> </div> </div> <div class="sect2"> <h3 id="sensitive-options"><a class="anchor" href="#sensitive-options"></a>Sensitive Options</h3> <div class="paragraph"> <p>Sensitive values, such as passwords, may be specified as command options. That is generally not recommended. There are also mechanisms by which you can be prompted for the sensitive value - by either omitting the option or providing a value or -. Finally all will have a corresponding env variable that can be used instead - check the help of the command you are running to see all possible options.</p> </div> </div> <div class="sect2"> <h3 id="authenticating"><a class="anchor" href="#authenticating"></a>Authenticating</h3> <div class="paragraph"> <p>When you log in with the Admin CLI, you specify:</p> </div> <div class="ulist"> <ul> <li> <p>A server endpoint URL</p> </li> <li> <p>A realm</p> </li> <li> <p>A user name</p> </li> </ul> </div> <div class="paragraph"> <p>Another option is to specify a clientId only, which creates a unique service account for you to use.</p> </div> <div class="paragraph"> <p>When you log in using a user name, use a password for the specified user. When you log in using a clientId, you need the client secret only, not the user password. You can also use the <code>Signed JWT</code> rather than the client secret.</p> </div> <div class="paragraph"> <p>Ensure the account used for the session has the proper permissions to invoke Admin REST API operations. For example, the <code>realm-admin</code> role of the <code>realm-management</code> client can administer the realm of the user.</p> </div> <div class="paragraph"> <p>Two primary mechanisms are available for authentication. One mechanism uses <code>kcadm config credentials</code> to start an authenticated session.</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh config credentials --server http://localhost:8080 --realm master --user admin</pre> </div> </div> <div class="paragraph"> <p>This mechanism maintains an authenticated session between the <code>kcadm</code> command invocations by saving the obtained access token and its associated refresh token. It can maintain other secrets in a private configuration file. See the <a href="#_working_with_alternative_configurations">next chapter</a> for more information.</p> </div> <div class="paragraph"> <p>The second mechanism authenticates each command invocation for the duration of the invocation. This mechanism increases the load on the server and the time spent on round trips obtaining tokens. The benefit of this approach is that it is unnecessary to save tokens between invocations, so nothing is saved to disk. Keycloak uses this mode when the <code>--no-config</code> argument is specified.</p> </div> <div class="paragraph"> <p>For example, when performing an operation, specify all the information required for authentication.</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get realms --no-config --server http://localhost:8080 --realm master --user admin</pre> </div> </div> <div class="paragraph"> <p>Run the <code>kcadm.sh help</code> command for more information on using the Admin CLI.</p> </div> <div class="paragraph"> <p>Run the <code>kcadm.sh config credentials --help</code> command for more information about starting an authenticated session.</p> </div> <div class="paragraph"> <p>If you do not specify the --password option (it is generally recommended to not provide passwords as part of the command), you will be prompted for a password unless one is specified as the environment variable KC_CLI_PASSWORD.</p> </div> </div> <div class="sect2"> <h3 id="_working_with_alternative_configurations"><a class="anchor" href="#_working_with_alternative_configurations"></a>Working with alternative configurations</h3> <div class="paragraph"> <p>By default, the Admin CLI maintains a configuration file named <code>kcadm.config</code>. Keycloak places this file in the user&#8217;s home directory. In Linux-based systems, the full pathname is <code>$HOME/.keycloak/kcadm.config</code>. In Windows, the full pathname is <code>%HOMEPATH%\.keycloak\kcadm.config</code>.</p> </div> <div class="paragraph"> <p>You can use the <code>--config</code> option to point to a different file or location so you can maintain multiple authenticated sessions in parallel.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>Perform operations tied to a single configuration file from a single thread.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>Ensure the configuration file is invisible to other users on the system. It contains access tokens and secrets that must be private. Keycloak creates the <code>~/.keycloak</code> directory and its contents automatically with proper access limits. If the directory already exists, Keycloak does not update the directory&#8217;s permissions.</p> </div> <div class="paragraph"> <p>It is possible to avoid storing secrets inside a configuration file, but doing so is inconvenient and increases the number of token requests. Use the <code>--no-config</code> option with all commands and specify the authentication information the <code>config credentials</code> command requires with each invocation of <code>kcadm</code>.</p> </div> </div> <div class="sect2"> <h3 id="basic-operations-and-resource-uris"><a class="anchor" href="#basic-operations-and-resource-uris"></a>Basic operations and resource URIs</h3> <div class="paragraph"> <p>The Admin CLI can generically perform CRUD operations against Admin REST API endpoints with additional commands that simplify particular tasks.</p> </div> <div class="paragraph"> <p>The main usage pattern is listed here:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create ENDPOINT [ARGUMENTS] $ kcadm.sh get ENDPOINT [ARGUMENTS] $ kcadm.sh update ENDPOINT [ARGUMENTS] $ kcadm.sh delete ENDPOINT [ARGUMENTS]</pre> </div> </div> <div class="paragraph"> <p>The <code>create</code>, <code>get</code>, <code>update</code>, and <code>delete</code> commands map to the HTTP verbs <code>POST</code>, <code>GET</code>, <code>PUT</code>, and <code>DELETE</code>, respectively. ENDPOINT is a target resource URI and can be absolute (starting with <code>http:</code> or <code>https:</code>) or relative, that Keycloak uses to compose absolute URLs in the following format:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">SERVER_URI/admin/realms/REALM/ENDPOINT</pre> </div> </div> <div class="paragraph"> <p>For example, if you authenticate against the server <a href="http://localhost:8080" class="bare">http://localhost:8080</a> and realm is <code>master</code>, using <code>users</code> as ENDPOINT creates the <a href="http://localhost:8080/admin/realms/master/users" class="bare">http://localhost:8080/admin/realms/master/users</a> resource URL.</p> </div> <div class="paragraph"> <p>If you set ENDPOINT to <code>clients</code>, the effective resource URI is <a href="http://localhost:8080/admin/realms/master/clients" class="bare">http://localhost:8080/admin/realms/master/clients</a>.</p> </div> <div class="paragraph"> <p>Keycloak has a <code>realms</code> endpoint that is the container for realms. It resolves to:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">SERVER_URI/admin/realms</pre> </div> </div> <div class="paragraph"> <p>Keycloak has a <code>serverinfo</code> endpoint. This endpoint is independent of realms.</p> </div> <div class="paragraph"> <p>When you authenticate as a user with realm-admin powers, you may need to perform commands on multiple realms. If so, specify the <code>-r</code> option to tell the CLI which realm the command is to execute against explicitly. Instead of using <code>REALM</code> as specified by the <code>--realm</code> option of <code>kcadm.sh config credentials</code>, the command uses <code>TARGET_REALM</code>.</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">SERVER_URI/admin/realms/TARGET_REALM/ENDPOINT</pre> </div> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh config credentials --server http://localhost:8080 --realm master --user admin $ kcadm.sh create users -s username=testuser -s enabled=true -r demorealm</pre> </div> </div> <div class="paragraph"> <p>In this example, you start a session authenticated as the <code>admin</code> user in the <code>master</code> realm. You then perform a POST call against the resource URL <code><a href="http://localhost:8080/admin/realms/demorealm/users" class="bare">http://localhost:8080/admin/realms/demorealm/users</a></code>.</p> </div> <div class="paragraph"> <p>The <code>create</code> and <code>update</code> commands send a JSON body to the server. You can use <code>-f FILENAME</code> to read a pre-made document from a file. When you can use the <code>-f -</code> option, Keycloak reads the message body from the standard input. You can specify individual attributes and their values, as seen in the <code>create users</code> example. Keycloak composes the attributes into a JSON body and sends them to the server.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>The value in name=value pairs used in --set, -s options, are assumed to be JSON. If it cannot be parsed as valid JSON, then it will be sent to the server as a text value.</p> </div> <div class="paragraph"> <p>If the value is enclosed in quotes after shell processing, but is not valid JSON, the quotes will be stripped and the rest of the value will be sent as text. This behavior is deprecated, please consider specifying your value without quotes or a valid JSON string literal with double quotes.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>Several methods are available in Keycloak to update a resource using the <code>update</code> command. You can determine the current state of a resource and save it to a file, edit that file, and send it to the server for an update.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre>$ kcadm.sh get realms/demorealm &gt; demorealm.json $ vi demorealm.json $ kcadm.sh update realms/demorealm -f demorealm.json</pre> </div> </div> <div class="paragraph"> <p>This method updates the resource on the server with the attributes in the sent JSON document.</p> </div> <div class="paragraph"> <p>Another method is to perform an on-the-fly update by using the <code>-s, --set</code> options to set new values.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre>$ kcadm.sh update realms/demorealm -s enabled=false</pre> </div> </div> <div class="paragraph"> <p>This method sets the <code>enabled</code> attribute to <code>false</code>.</p> </div> <div class="paragraph"> <p>By default, the <code>update</code> command performs a <code>get</code> and then merges the new attribute values with existing values. In some cases, the endpoint may support the <code>put</code> command but not the <code>get</code> command. You can use the <code>-n</code> option to perform a no-merge update, which performs a <code>put</code> command without first running a <code>get</code> command.</p> </div> </div> <div class="sect2"> <h3 id="realm-operations"><a class="anchor" href="#realm-operations"></a>Realm operations</h3> <h4 id="creating-a-new-realm" class="discrete">Creating a new realm</h4> <div class="paragraph"> <p>Use the <code>create</code> command on the <code>realms</code> endpoint to create a new enabled realm. Set the attributes to <code>realm</code> and <code>enabled</code>.</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create realms -s realm=demorealm -s enabled=true</pre> </div> </div> <div class="paragraph"> <p>Keycloak disables realms by default. You can use a realm immediately for authentication by enabling it.</p> </div> <div class="paragraph"> <p>A description for a new object can also be in JSON format.</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create realms -f demorealm.json</pre> </div> </div> <div class="paragraph"> <p>You can send a JSON document with realm attributes directly from a file or pipe the document to standard input.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="ulist"> <ul> <li> <p>Linux:</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create realms -f - &lt;&lt; EOF { "realm": "demorealm", "enabled": true } EOF</pre> </div> </div> </li> <li> <p>Windows:</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">c:\&gt; echo { "realm": "demorealm", "enabled": true } | kcadm create realms -f -</pre> </div> </div> </li> </ul> </div> <h4 id="listing-existing-realms" class="discrete">Listing existing realms</h4> <div class="paragraph"> <p>This command returns a list of all realms.</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get realms</pre> </div> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>Keycloak filters the list of realms on the server to return realms a user can see only.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>The list of all realm attributes can be verbose, and most users are interested in a subset of attributes, such as the realm name and the enabled status of the realm. You can specify the attributes to return by using the <code>--fields</code> option.</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get realms --fields realm,enabled</pre> </div> </div> <div class="paragraph"> <p>You can display the result as comma-separated values.</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get realms --fields realm --format csv --noquotes</pre> </div> </div> <h4 id="getting-a-specific-realm" class="discrete">Getting a specific realm</h4> <div class="paragraph"> <p>Append a realm name to a collection URI to get an individual realm.</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get realms/master</pre> </div> </div> <h4 id="updating-a-realm" class="discrete">Updating a realm</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Use the <code>-s</code> option to set new values for the attributes when you do not want to change all of the realm&#8217;s attributes.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh update realms/demorealm -s enabled=false</pre> </div> </div> </li> <li> <p>If you want to set all writable attributes to new values:</p> <div class="olist loweralpha"> <ol class="loweralpha" type="a"> <li> <p>Run a <code>get</code> command.</p> </li> <li> <p>Edit the current values in the JSON file.</p> </li> <li> <p>Resubmit.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get realms/demorealm &gt; demorealm.json $ vi demorealm.json $ kcadm.sh update realms/demorealm -f demorealm.json</pre> </div> </div> </li> </ol> </div> </li> </ol> </div> <h4 id="deleting-a-realm" class="discrete">Deleting a realm</h4> <div class="paragraph"> <p>Run the following command to delete a realm:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh delete realms/demorealm</pre> </div> </div> <h4 id="turning-on-all-login-page-options-for-the-realm" class="discrete">Turning on all login page options for the realm</h4> <div class="paragraph"> <p>Set the attributes that control specific capabilities to <code>true</code>.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh update realms/demorealm -s registrationAllowed=true -s registrationEmailAsUsername=true -s rememberMe=true -s verifyEmail=true -s resetPasswordAllowed=true -s editUsernameAllowed=true</pre> </div> </div> <h4 id="listing-the-realm-keys" class="discrete">Listing the realm keys</h4> <div class="paragraph"> <p>Use the <code>get</code> operation on the <code>keys</code> endpoint of the target realm.</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get keys -r demorealm</pre> </div> </div> <h4 id="generating-new-realm-keys" class="discrete">Generating new realm keys</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Get the ID of the target realm before adding a new RSA-generated key pair.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get realms/demorealm --fields id --format csv --noquotes</pre> </div> </div> </li> <li> <p>Add a new key provider with a higher priority than the existing providers as revealed by <code>kcadm.sh get keys -r demorealm</code>.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="ulist"> <ul> <li> <p>Linux:</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create components -r demorealm -s name=rsa-generated -s providerId=rsa-generated -s providerType=org.keycloak.keys.KeyProvider -s parentId=959844c1-d149-41d7-8359-6aa527fca0b0 -s 'config.priority=["101"]' -s 'config.enabled=["true"]' -s 'config.active=["true"]' -s 'config.keySize=["2048"]'</pre> </div> </div> </li> <li> <p>Windows:</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">c:\&gt; kcadm create components -r demorealm -s name=rsa-generated -s providerId=rsa-generated -s providerType=org.keycloak.keys.KeyProvider -s parentId=959844c1-d149-41d7-8359-6aa527fca0b0 -s "config.priority=[\"101\"]" -s "config.enabled=[\"true\"]" -s "config.active=[\"true\"]" -s "config.keySize=[\"2048\"]"</pre> </div> </div> </li> </ul> </div> </li> <li> <p>Set the <code>parentId</code> attribute to the value of the target realm&#8217;s ID.</p> <div class="paragraph"> <p>The newly added key is now the active key, as revealed by <code>kcadm.sh get keys -r demorealm</code>.</p> </div> </li> </ol> </div> <h4 id="adding-new-realm-keys-from-a-java-key-store-file" class="discrete">Adding new realm keys from a Java Key Store file</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Add a new key provider to add a new key pair pre-prepared as a JKS file.</p> <div class="paragraph"> <p>For example, on:</p> </div> <div class="ulist"> <ul> <li> <p>Linux:</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create components -r demorealm -s name=java-keystore -s providerId=java-keystore -s providerType=org.keycloak.keys.KeyProvider -s parentId=959844c1-d149-41d7-8359-6aa527fca0b0 -s 'config.priority=["101"]' -s 'config.enabled=["true"]' -s 'config.active=["true"]' -s 'config.keystore=["/opt/keycloak/keystore.jks"]' -s 'config.keystorePassword=["secret"]' -s 'config.keyPassword=["secret"]' -s 'config.keyAlias=["localhost"]'</pre> </div> </div> </li> <li> <p>Windows:</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">c:\&gt; kcadm create components -r demorealm -s name=java-keystore -s providerId=java-keystore -s providerType=org.keycloak.keys.KeyProvider -s parentId=959844c1-d149-41d7-8359-6aa527fca0b0 -s "config.priority=[\"101\"]" -s "config.enabled=[\"true\"]" -s "config.active=[\"true\"]" -s "config.keystore=[\"/opt/keycloak/keystore.jks\"]" -s "config.keystorePassword=[\"secret\"]" -s "config.keyPassword=[\"secret\"]" -s "config.keyAlias=[\"localhost\"]"</pre> </div> </div> </li> </ul> </div> </li> <li> <p>Ensure you change the attribute values for <code>keystore</code>, <code>keystorePassword</code>, <code>keyPassword</code>, and <code>alias</code> to match your specific keystore.</p> </li> <li> <p>Set the <code>parentId</code> attribute to the value of the target realm&#8217;s ID.</p> </li> </ol> </div> <h4 id="making-the-key-passive-or-disabling-the-key" class="discrete">Making the key passive or disabling the key</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Identify the key you want to make passive.</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get keys -r demorealm</pre> </div> </div> </li> <li> <p>Use the key&#8217;s <code>providerId</code> attribute to construct an endpoint URI, such as <code>components/PROVIDER_ID</code>.</p> </li> <li> <p>Perform an <code>update</code>.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="ulist"> <ul> <li> <p>Linux:</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh update components/PROVIDER_ID -r demorealm -s 'config.active=["false"]'</pre> </div> </div> </li> <li> <p>Windows:</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">c:\&gt; kcadm update components/PROVIDER_ID -r demorealm -s "config.active=[\"false\"]"</pre> </div> </div> <div class="paragraph"> <p>You can update other key attributes:</p> </div> </li> <li> <p>Set a new <code>enabled</code> value to disable the key, for example, <code>config.enabled=["false"]</code>.</p> </li> <li> <p>Set a new <code>priority</code> value to change the key&#8217;s priority, for example, <code>config.priority=["110"]</code>.</p> </li> </ul> </div> </li> </ol> </div> <h4 id="deleting-an-old-key" class="discrete">Deleting an old key</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Ensure the key you are deleting is inactive and you have disabled it. This action is to prevent existing tokens held by applications and users from failing.</p> </li> <li> <p>Identify the key to delete.</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get keys -r demorealm</pre> </div> </div> </li> <li> <p>Use the <code>providerId</code> of the key to perform the delete.</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh delete components/PROVIDER_ID -r demorealm</pre> </div> </div> </li> </ol> </div> <h4 id="configuring-event-logging-for-a-realm" class="discrete">Configuring event logging for a realm</h4> <div class="paragraph"> <p>Use the <code>update</code> command on the <code>events/config</code> endpoint.</p> </div> <div class="paragraph"> <p>The <code>eventsListeners</code> attribute contains a list of EventListenerProviderFactory IDs, specifying all event listeners that receive events. Attributes are available that control built-in event storage, so you can query past events using the Admin REST API. Keycloak has separate control over the logging of service calls (<code>eventsEnabled</code>) and the auditing events triggered by the Admin Console or Admin REST API (<code>adminEventsEnabled</code>). You can set up the <code>eventsExpiration</code> event to expire to prevent your database from filling. Keycloak sets <code>eventsExpiration</code> to time-to-live expressed in seconds.</p> </div> <div class="paragraph"> <p>You can set up a built-in event listener that receives all events and logs the events through JBoss-logging. Using the <code>org.keycloak.events</code> logger, Keycloak logs error events as <code>WARN</code> and other events as <code>DEBUG</code>.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="ulist"> <ul> <li> <p>Linux:</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh update events/config -r demorealm -s 'eventsListeners=["jboss-logging"]'</pre> </div> </div> </li> <li> <p>Windows:</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">c:\&gt; kcadm update events/config -r demorealm -s "eventsListeners=[\"jboss-logging\"]"</pre> </div> </div> </li> </ul> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="paragraph"> <p>You can turn on storage for all available ERROR events, not including auditing events, for two days so you can retrieve the events through Admin REST.</p> </div> <div class="ulist"> <ul> <li> <p>Linux:</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh update events/config -r demorealm -s eventsEnabled=true -s 'enabledEventTypes=["LOGIN_ERROR","REGISTER_ERROR","LOGOUT_ERROR","CODE_TO_TOKEN_ERROR","CLIENT_LOGIN_ERROR","FEDERATED_IDENTITY_LINK_ERROR","REMOVE_FEDERATED_IDENTITY_ERROR","UPDATE_EMAIL_ERROR","UPDATE_PROFILE_ERROR","UPDATE_PASSWORD_ERROR","UPDATE_TOTP_ERROR","UPDATE_CREDENTIAL_ERROR","VERIFY_EMAIL_ERROR","REMOVE_TOTP_ERROR","REMOVE_CREDENTIAL_ERROR","SEND_VERIFY_EMAIL_ERROR","SEND_RESET_PASSWORD_ERROR","SEND_IDENTITY_PROVIDER_LINK_ERROR","RESET_PASSWORD_ERROR","IDENTITY_PROVIDER_FIRST_LOGIN_ERROR","IDENTITY_PROVIDER_POST_LOGIN_ERROR","CUSTOM_REQUIRED_ACTION_ERROR","EXECUTE_ACTIONS_ERROR","CLIENT_REGISTER_ERROR","CLIENT_UPDATE_ERROR","CLIENT_DELETE_ERROR"]' -s eventsExpiration=172800</pre> </div> </div> </li> <li> <p>Windows:</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">c:\&gt; kcadm update events/config -r demorealm -s eventsEnabled=true -s "enabledEventTypes=[\"LOGIN_ERROR\",\"REGISTER_ERROR\",\"LOGOUT_ERROR\",\"CODE_TO_TOKEN_ERROR\",\"CLIENT_LOGIN_ERROR\",\"FEDERATED_IDENTITY_LINK_ERROR\",\"REMOVE_FEDERATED_IDENTITY_ERROR\",\"UPDATE_EMAIL_ERROR\",\"UPDATE_PROFILE_ERROR\",\"UPDATE_PASSWORD_ERROR\",\"UPDATE_TOTP_ERROR\",\"UPDATE_CREDENTIAL_ERROR\",\"VERIFY_EMAIL_ERROR\",\"REMOVE_TOTP_ERROR\",\"REMOVE_CREDENTIAL_ERROR\",\"SEND_VERIFY_EMAIL_ERROR\",\"SEND_RESET_PASSWORD_ERROR\",\"SEND_IDENTITY_PROVIDER_LINK_ERROR\",\"RESET_PASSWORD_ERROR\",\"IDENTITY_PROVIDER_FIRST_LOGIN_ERROR\",\"IDENTITY_PROVIDER_POST_LOGIN_ERROR\",\"CUSTOM_REQUIRED_ACTION_ERROR\",\"EXECUTE_ACTIONS_ERROR\",\"CLIENT_REGISTER_ERROR\",\"CLIENT_UPDATE_ERROR\",\"CLIENT_DELETE_ERROR\"]" -s eventsExpiration=172800</pre> </div> </div> </li> </ul> </div> <div class="paragraph"> <p>You can reset stored event types to <strong>all available event types</strong>. Setting the value to an empty list is the same as enumerating all.</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh update events/config -r demorealm -s enabledEventTypes=[]</pre> </div> </div> <div class="paragraph"> <p>You can enable storage of auditing events.</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh update events/config -r demorealm -s adminEventsEnabled=true -s adminEventsDetailsEnabled=true</pre> </div> </div> <div class="paragraph"> <p>You can get the last 100 events. The events are ordered from newest to oldest.</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get events --offset 0 --limit 100</pre> </div> </div> <div class="paragraph"> <p>You can delete all saved events.</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm delete events</pre> </div> </div> <h4 id="flushing-the-caches" class="discrete">Flushing the caches</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Use the <code>create</code> command with one of these endpoints to clear caches:</p> <div class="ulist"> <ul> <li> <p><code>clear-realm-cache</code></p> </li> <li> <p><code>clear-user-cache</code></p> </li> <li> <p><code>clear-keys-cache</code></p> </li> </ul> </div> </li> <li> <p>Set <code>realm</code> to the same value as the target realm.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create clear-realm-cache -r demorealm -s realm=demorealm $ kcadm.sh create clear-user-cache -r demorealm -s realm=demorealm $ kcadm.sh create clear-keys-cache -r demorealm -s realm=demorealm</pre> </div> </div> </li> </ol> </div> <h4 id="importing-a-realm-from-exported-json-file" class="discrete">Importing a realm from exported .json file</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Use the <code>create</code> command on the <code>partialImport</code> endpoint.</p> </li> <li> <p>Set <code>ifResourceExists</code> to <code>FAIL</code>, <code>SKIP</code>, or <code>OVERWRITE</code>.</p> </li> <li> <p>Use <code>-f</code> to submit the exported realm <code>.json</code> file.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create partialImport -r demorealm2 -s ifResourceExists=FAIL -o -f demorealm.json</pre> </div> </div> <div class="paragraph"> <p>If the realm does not yet exist, create it first.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create realms -s realm=demorealm2 -s enabled=true</pre> </div> </div> </li> </ol> </div> </div> <div class="sect2"> <h3 id="role-operations"><a class="anchor" href="#role-operations"></a>Role operations</h3> <h4 id="creating-a-realm-role" class="discrete">Creating a realm role</h4> <div class="paragraph"> <p>Use the <code>roles</code> endpoint to create a realm role.</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create roles -r demorealm -s name=user -s 'description=Regular user with a limited set of permissions'</pre> </div> </div> <h4 id="creating-a-client-role" class="discrete">Creating a client role</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Identify the client.</p> </li> <li> <p>Use the <code>get</code> command to list the available clients.</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get clients -r demorealm --fields id,clientId</pre> </div> </div> </li> <li> <p>Create a new role by using the <code>clientId</code> attribute to construct an endpoint URI, such as <code>clients/ID/roles</code>.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create clients/a95b6af3-0bdc-4878-ae2e-6d61a4eca9a0/roles -r demorealm -s name=editor -s 'description=Editor can edit, and publish any article'</pre> </div> </div> </li> </ol> </div> <h4 id="listing-realm-roles" class="discrete">Listing realm roles</h4> <div class="paragraph"> <p>Use the <code>get</code> command on the <code>roles</code> endpoint to list existing realm roles.</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get roles -r demorealm</pre> </div> </div> <div class="paragraph"> <p>You can use the <code>get-roles</code> command also.</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get-roles -r demorealm</pre> </div> </div> <h4 id="listing-client-roles" class="discrete">Listing client roles</h4> <div class="paragraph"> <p>Keycloak has a dedicated <code>get-roles</code> command to simplify the listing of realm and client roles. The command is an extension of the <code>get</code> command and behaves the same as the <code>get</code> command but with additional semantics for listing roles.</p> </div> <div class="paragraph"> <p>Use the <code>get-roles</code> command by passing it the clientId (<code>--cclientid</code>) option or the <code>id</code> (<code>--cid</code>) option to identify the client to list client roles.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get-roles -r demorealm --cclientid realm-management</pre> </div> </div> <h4 id="getting-a-specific-realm-role" class="discrete">Getting a specific realm role</h4> <div class="paragraph"> <p>Use the <code>get</code> command and the role <code>name</code> to construct an endpoint URI for a specific realm role, <code>roles/ROLE_NAME</code>, where <code>user</code> is the existing role&#8217;s name.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get roles/user -r demorealm</pre> </div> </div> <div class="paragraph"> <p>You can use the <code>get-roles</code> command, passing it a role name (<code>--rolename</code> option) or ID (<code>--roleid</code> option).</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get-roles -r demorealm --rolename user</pre> </div> </div> <h4 id="getting-a-specific-client-role" class="discrete">Getting a specific client role</h4> <div class="paragraph"> <p>Use the <code>get-roles</code> command, passing it the clientId attribute (<code>--cclientid</code> option) or ID attribute (<code>--cid</code> option) to identify the client, and pass the role name (<code>--rolename</code> option) or the role ID attribute (<code>--roleid</code>) to identify a specific client role.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get-roles -r demorealm --cclientid realm-management --rolename manage-clients</pre> </div> </div> <h4 id="updating-a-realm-role" class="discrete">Updating a realm role</h4> <div class="paragraph"> <p>Use the <code>update</code> command with the endpoint URI you used to get a specific realm role.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh update roles/user -r demorealm -s 'description=Role representing a regular user'</pre> </div> </div> <h4 id="updating-a-client-role" class="discrete">Updating a client role</h4> <div class="paragraph"> <p>Use the <code>update</code> command with the endpoint URI that you used to get a specific client role.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh update clients/a95b6af3-0bdc-4878-ae2e-6d61a4eca9a0/roles/editor -r demorealm -s 'description=User that can edit, and publish articles'</pre> </div> </div> <h4 id="deleting-a-realm-role" class="discrete">Deleting a realm role</h4> <div class="paragraph"> <p>Use the <code>delete</code> command with the endpoint URI that you used to get a specific realm role.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh delete roles/user -r demorealm</pre> </div> </div> <h4 id="deleting-a-client-role" class="discrete">Deleting a client role</h4> <div class="paragraph"> <p>Use the <code>delete</code> command with the endpoint URI that you used to get a specific client role.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh delete clients/a95b6af3-0bdc-4878-ae2e-6d61a4eca9a0/roles/editor -r demorealm</pre> </div> </div> <h4 id="listing-assigned-available-and-effective-realm-roles-for-a-composite-role" class="discrete">Listing assigned, available, and effective realm roles for a composite role</h4> <div class="paragraph"> <p>Use the <code>get-roles</code> command to list assigned, available, and effective realm roles for a composite role.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>To list <strong>assigned</strong> realm roles for the composite role, specify the target composite role by name (<code>--rname</code> option) or ID (<code>--rid</code> option).</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get-roles -r demorealm --rname testrole</pre> </div> </div> </li> <li> <p>Use the <code>--effective</code> option to list <strong>effective</strong> realm roles.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get-roles -r demorealm --rname testrole --effective</pre> </div> </div> </li> <li> <p>Use the <code>--available</code> option to list realm roles that you can add to the composite role.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get-roles -r demorealm --rname testrole --available</pre> </div> </div> </li> </ol> </div> <h4 id="listing-assigned-available-and-effective-client-roles-for-a-composite-role" class="discrete">Listing assigned, available, and effective client roles for a composite role</h4> <div class="paragraph"> <p>Use the <code>get-roles</code> command to list assigned, available, and effective client roles for a composite role.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>To list <strong>assigned</strong> client roles for the composite role, you can specify the target composite role by name (<code>--rname</code> option) or ID (<code>--rid</code> option) and client by the clientId attribute (<code>--cclientid</code> option) or ID (<code>--cid</code> option).</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get-roles -r demorealm --rname testrole --cclientid realm-management</pre> </div> </div> </li> <li> <p>Use the <code>--effective</code> option to list <strong>effective</strong> realm roles.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get-roles -r demorealm --rname testrole --cclientid realm-management --effective</pre> </div> </div> </li> <li> <p>Use the <code>--available</code> option to list realm roles that you can add to the target composite role.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get-roles -r demorealm --rname testrole --cclientid realm-management --available</pre> </div> </div> </li> </ol> </div> <h4 id="adding-realm-roles-to-a-composite-role" class="discrete">Adding realm roles to a composite role</h4> <div class="paragraph"> <p>Keycloak provides an <code>add-roles</code> command for adding realm roles and client roles.</p> </div> <div class="paragraph"> <p>This example adds the <code>user</code> role to the composite role <code>testrole</code>.</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh add-roles --rname testrole --rolename user -r demorealm</pre> </div> </div> <h4 id="removing-realm-roles-from-a-composite-role" class="discrete">Removing realm roles from a composite role</h4> <div class="paragraph"> <p>Keycloak provides a <code>remove-roles</code> command for removing realm roles and client roles.</p> </div> <div class="paragraph"> <p>The following example removes the <code>user</code> role from the target composite role <code>testrole</code>.</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh remove-roles --rname testrole --rolename user -r demorealm</pre> </div> </div> <h4 id="adding-client-roles-to-a-realm-role" class="discrete">Adding client roles to a realm role</h4> <div class="paragraph"> <p>Keycloak provides an <code>add-roles</code> command for adding realm roles and client roles.</p> </div> <div class="paragraph"> <p>The following example adds the roles defined on the client <code>realm-management</code>, <code>create-client</code>, and <code>view-users</code>, to the <code>testrole</code> composite role.</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh add-roles -r demorealm --rname testrole --cclientid realm-management --rolename create-client --rolename view-users</pre> </div> </div> <h4 id="adding-client-roles-to-a-client-role" class="discrete">Adding client roles to a client role</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Determine the ID of the composite client role by using the <code>get-roles</code> command.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get-roles -r demorealm --cclientid test-client --rolename operations</pre> </div> </div> </li> <li> <p>Assume that a client exists with a clientId attribute named <code>test-client</code>, a client role named <code>support</code>, and a client role named <code>operations</code> which becomes a composite role that has an ID of "fc400897-ef6a-4e8c-872b-1581b7fa8a71".</p> </li> <li> <p>Use the following example to add another role to the composite role.</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh add-roles -r demorealm --cclientid test-client --rid fc400897-ef6a-4e8c-872b-1581b7fa8a71 --rolename support</pre> </div> </div> </li> <li> <p>List the roles of a composite role by using the <code>get-roles --all</code> command.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get-roles --rid fc400897-ef6a-4e8c-872b-1581b7fa8a71 --all</pre> </div> </div> </li> </ol> </div> <h4 id="removing-client-roles-from-a-composite-role" class="discrete">Removing client roles from a composite role</h4> <div class="paragraph"> <p>Use the <code>remove-roles</code> command to remove client roles from a composite role.</p> </div> <div class="paragraph"> <p>Use the following example to remove two roles defined on the client <code>realm-management</code>, the <code>create-client</code> role and the <code>view-users</code> role, from the <code>testrole</code> composite role.</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh remove-roles -r demorealm --rname testrole --cclientid realm-management --rolename create-client --rolename view-users</pre> </div> </div> <h4 id="adding-client-roles-to-a-group" class="discrete">Adding client roles to a group</h4> <div class="paragraph"> <p>Use the <code>add-roles</code> command to add realm roles and client roles.</p> </div> <div class="paragraph"> <p>The following example adds the roles defined on the client <code>realm-management</code>, <code>create-client</code> and <code>view-users</code>, to the <code>Group</code> group (<code>--gname</code> option). Alternatively, you can specify the group by ID (<code>--gid</code> option).</p> </div> <div class="paragraph"> <p>See <a href="#_group_operations">Group operations</a> for more information.</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh add-roles -r demorealm --gname Group --cclientid realm-management --rolename create-client --rolename view-users</pre> </div> </div> <h4 id="removing-client-roles-from-a-group" class="discrete">Removing client roles from a group</h4> <div class="paragraph"> <p>Use the <code>remove-roles</code> command to remove client roles from a group.</p> </div> <div class="paragraph"> <p>The following example removes two roles defined on the client <code>realm management</code>, <code>create-client</code> and <code>view-users</code>, from the <code>Group</code> group.</p> </div> <div class="paragraph"> <p>See <a href="#_group_operations">Group operations</a> for more information.</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh remove-roles -r demorealm --gname Group --cclientid realm-management --rolename create-client --rolename view-users</pre> </div> </div> </div> <div class="sect2"> <h3 id="client-operations"><a class="anchor" href="#client-operations"></a>Client operations</h3> <h4 id="creating-a-client" class="discrete">Creating a client</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Run the <code>create</code> command on a <code>clients</code> endpoint to create a new client.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create clients -r demorealm -s clientId=myapp -s enabled=true</pre> </div> </div> </li> <li> <p>Specify a secret if to set a secret for adapters to authenticate.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create clients -r demorealm -s clientId=myapp -s enabled=true -s clientAuthenticatorType=client-secret -s secret=d0b8122f-8dfb-46b7-b68a-f5cc4e25d000</pre> </div> </div> </li> </ol> </div> <h4 id="listing-clients" class="discrete">Listing clients</h4> <div class="paragraph"> <p>Use the <code>get</code> command on the <code>clients</code> endpoint to list clients.</p> </div> <div class="paragraph"> <p>This example filters the output to list only the <code>id</code> and <code>clientId</code> attributes:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get clients -r demorealm --fields id,clientId</pre> </div> </div> <h4 id="getting-a-specific-client" class="discrete">Getting a specific client</h4> <div class="paragraph"> <p>Use the client ID to construct an endpoint URI that targets a specific client, such as <code>clients/ID</code>.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get clients/c7b8547f-e748-4333-95d0-410b76b3f4a3 -r demorealm</pre> </div> </div> <h4 id="getting-the-current-secret-for-a-specific-client" class="discrete">Getting the current secret for a specific client</h4> <div class="paragraph"> <p>Use the client ID to construct an endpoint URI, such as <code>clients/ID/client-secret</code>.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get clients/$CID/client-secret -r demorealm</pre> </div> </div> <h4 id="generate-a-new-secret-for-a-specific-client" class="discrete">Generate a new secret for a specific client</h4> <div class="paragraph"> <p>Use the client ID to construct an endpoint URI, such as <code>clients/ID/client-secret</code>.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create clients/$CID/client-secret -r demorealm</pre> </div> </div> <h4 id="updating-the-current-secret-for-a-specific-client" class="discrete">Updating the current secret for a specific client</h4> <div class="paragraph"> <p>Use the client ID to construct an endpoint URI, such as <code>clients/ID</code>.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh update clients/$CID -s "secret=newSecret" -r demorealm</pre> </div> </div> <h4 id="getting-an-adapter-configuration-file-keycloak-json-for-a-specific-client" class="discrete">Getting an adapter configuration file (keycloak.json) for a specific client</h4> <div class="paragraph"> <p>Use the client ID to construct an endpoint URI that targets a specific client, such as <code>clients/ID/installation/providers/keycloak-oidc-keycloak-json</code>.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get clients/c7b8547f-e748-4333-95d0-410b76b3f4a3/installation/providers/keycloak-oidc-keycloak-json -r demorealm</pre> </div> </div> <h4 id="getting-a-wildfly-subsystem-adapter-configuration-for-a-specific-client" class="discrete">Getting a WildFly subsystem adapter configuration for a specific client</h4> <div class="paragraph"> <p>Use the client ID to construct an endpoint URI that targets a specific client, such as <code>clients/ID/installation/providers/keycloak-oidc-jboss-subsystem</code>.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get clients/c7b8547f-e748-4333-95d0-410b76b3f4a3/installation/providers/keycloak-oidc-jboss-subsystem -r demorealm</pre> </div> </div> <h4 id="getting-a-docker-v2-example-configuration-for-a-specific-client" class="discrete">Getting a Docker-v2 example configuration for a specific client</h4> <div class="paragraph"> <p>Use the client ID to construct an endpoint URI that targets a specific client, such as <code>clients/ID/installation/providers/docker-v2-compose-yaml</code>.</p> </div> <div class="paragraph"> <p>The response is in <code>.zip</code> format.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get http://localhost:8080/admin/realms/demorealm/clients/8f271c35-44e3-446f-8953-b0893810ebe7/installation/providers/docker-v2-compose-yaml -r demorealm &gt; keycloak-docker-compose-yaml.zip</pre> </div> </div> <h4 id="updating-a-client" class="discrete">Updating a client</h4> <div class="paragraph"> <p>Use the <code>update</code> command with the same endpoint URI that you use to get a specific client.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="ulist"> <ul> <li> <p>Linux:</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh update clients/c7b8547f-e748-4333-95d0-410b76b3f4a3 -r demorealm -s enabled=false -s publicClient=true -s 'redirectUris=["http://localhost:8080/myapp/*"]' -s baseUrl=http://localhost:8080/myapp -s adminUrl=http://localhost:8080/myapp</pre> </div> </div> </li> <li> <p>Windows:</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">c:\&gt; kcadm update clients/c7b8547f-e748-4333-95d0-410b76b3f4a3 -r demorealm -s enabled=false -s publicClient=true -s "redirectUris=[\"http://localhost:8080/myapp/*\"]" -s baseUrl=http://localhost:8080/myapp -s adminUrl=http://localhost:8080/myapp</pre> </div> </div> </li> </ul> </div> <h4 id="deleting-a-client" class="discrete">Deleting a client</h4> <div class="paragraph"> <p>Use the <code>delete</code> command with the same endpoint URI that you use to get a specific client.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh delete clients/c7b8547f-e748-4333-95d0-410b76b3f4a3 -r demorealm</pre> </div> </div> <h4 id="adding-or-removing-roles-for-clients-service-account" class="discrete">Adding or removing roles for client&#8217;s service account</h4> <div class="paragraph"> <p>A client&#8217;s service account is a user account with username <code>service-account-CLIENT_ID</code>. You can perform the same user operations on this account as a regular account.</p> </div> </div> <div class="sect2"> <h3 id="user-operations"><a class="anchor" href="#user-operations"></a>User operations</h3> <h4 id="creating-a-user" class="discrete">Creating a user</h4> <div class="paragraph"> <p>Run the <code>create</code> command on the <code>users</code> endpoint to create a new user.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create users -r demorealm -s username=testuser -s enabled=true</pre> </div> </div> <h4 id="listing-users" class="discrete">Listing users</h4> <div class="paragraph"> <p>Use the <code>users</code> endpoint to list users. The target user must change their password the next time they log in.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get users -r demorealm --offset 0 --limit 1000</pre> </div> </div> <div class="paragraph"> <p>You can filter users by <code>username</code>, <code>firstName</code>, <code>lastName</code>, or <code>email</code>.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get users -r demorealm -q q=email:google.com $ kcadm.sh get users -r demorealm -q q=username:testuser</pre> </div> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>Filtering does not use exact matching. This example matches the value of the <code>username</code> attribute against the <code>*testuser*</code> pattern.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>For clients, groups, and users you can filter across multiple attributes by specifying a more complex <code>q</code> query parameter. you may use something like -q q="field1:value1 field2:value2". Keycloak returns users that match the condition for all the attributes only.</p> </div> <h4 id="getting-a-specific-user" class="discrete">Getting a specific user</h4> <div class="paragraph"> <p>Use the user ID to compose an endpoint URI, such as <code>users/USER_ID</code>.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get users/0ba7a3fd-6fd8-48cd-a60b-2e8fd82d56e2 -r demorealm</pre> </div> </div> <h4 id="updating-a-user" class="discrete">Updating a user</h4> <div class="paragraph"> <p>Use the <code>update</code> command with the same endpoint URI that you use to get a specific user.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="ulist"> <ul> <li> <p>Linux:</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh update users/0ba7a3fd-6fd8-48cd-a60b-2e8fd82d56e2 -r demorealm -s 'requiredActions=["VERIFY_EMAIL","UPDATE_PROFILE","CONFIGURE_TOTP","UPDATE_PASSWORD"]'</pre> </div> </div> </li> <li> <p>Windows:</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">c:\&gt; kcadm update users/0ba7a3fd-6fd8-48cd-a60b-2e8fd82d56e2 -r demorealm -s "requiredActions=[\"VERIFY_EMAIL\",\"UPDATE_PROFILE\",\"CONFIGURE_TOTP\",\"UPDATE_PASSWORD\"]"</pre> </div> </div> </li> </ul> </div> <h4 id="deleting-a-user" class="discrete">Deleting a user</h4> <div class="paragraph"> <p>Use the <code>delete</code> command with the same endpoint URI that you use to get a specific user.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh delete users/0ba7a3fd-6fd8-48cd-a60b-2e8fd82d56e2 -r demorealm</pre> </div> </div> <h4 id="resetting-a-users-password" class="discrete">Resetting a user&#8217;s password</h4> <div class="paragraph"> <p>Use the dedicated <code>set-password</code> command to reset a user&#8217;s password.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh set-password -r demorealm --username testuser --new-password NEWPASSWORD --temporary</pre> </div> </div> <div class="paragraph"> <p>This command sets a temporary password for the user. The target user must change the password the next time they log in.</p> </div> <div class="paragraph"> <p>You can use <code>--userid</code> to specify the user by using the <code>id</code> attribute.</p> </div> <div class="paragraph"> <p>You can achieve the same result using the <code>update</code> command on an endpoint constructed from the one you used to get a specific user, such as <code>users/USER_ID/reset-password</code>.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh update users/0ba7a3fd-6fd8-48cd-a60b-2e8fd82d56e2/reset-password -r demorealm -s type=password -s value=NEWPASSWORD -s temporary=true -n</pre> </div> </div> <div class="paragraph"> <p>The <code>-n</code> parameter ensures that Keycloak performs the <code>PUT</code> command without performing a <code>GET</code> command before the <code>PUT</code> command. This is necessary because the <code>reset-password</code> endpoint does not support <code>GET</code>.</p> </div> <h4 id="listing-assigned-available-and-effective-realm-roles-for-a-user" class="discrete">Listing assigned, available, and effective realm roles for a user</h4> <div class="paragraph"> <p>You can use a <code>get-roles</code> command to list assigned, available, and effective realm roles for a user.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Specify the target user by user name or ID to list the user&#8217;s <strong>assigned</strong> realm roles.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get-roles -r demorealm --uusername testuser</pre> </div> </div> </li> <li> <p>Use the <code>--effective</code> option to list <strong>effective</strong> realm roles.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get-roles -r demorealm --uusername testuser --effective</pre> </div> </div> </li> <li> <p>Use the <code>--available</code> option to list realm roles that you can add to a user.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get-roles -r demorealm --uusername testuser --available</pre> </div> </div> </li> </ol> </div> <h4 id="listing-assigned-available-and-effective-client-roles-for-a-user" class="discrete">Listing assigned, available, and effective client roles for a user</h4> <div class="paragraph"> <p>Use a <code>get-roles</code> command to list assigned, available, and effective client roles for a user.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Specify the target user by user name (<code>--uusername</code> option) or ID (<code>--uid</code> option) and client by a clientId attribute (<code>--cclientid</code> option) or an ID (<code>--cid</code> option) to list <strong>assigned</strong> client roles for the user.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get-roles -r demorealm --uusername testuser --cclientid realm-management</pre> </div> </div> </li> <li> <p>Use the <code>--effective</code> option to list <strong>effective</strong> realm roles.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get-roles -r demorealm --uusername testuser --cclientid realm-management --effective</pre> </div> </div> </li> <li> <p>Use the <code>--available</code> option to list realm roles that you can add to a user.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get-roles -r demorealm --uusername testuser --cclientid realm-management --available</pre> </div> </div> </li> </ol> </div> <h4 id="adding-realm-roles-to-a-user" class="discrete">Adding realm roles to a user</h4> <div class="paragraph"> <p>Use an <code>add-roles</code> command to add realm roles to a user.</p> </div> <div class="paragraph"> <p>Use the following example to add the <code>user</code> role to user <code>testuser</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh add-roles --uusername testuser --rolename user -r demorealm</pre> </div> </div> <h4 id="removing-realm-roles-from-a-user" class="discrete">Removing realm roles from a user</h4> <div class="paragraph"> <p>Use a <code>remove-roles</code> command to remove realm roles from a user.</p> </div> <div class="paragraph"> <p>Use the following example to remove the <code>user</code> role from the user <code>testuser</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh remove-roles --uusername testuser --rolename user -r demorealm</pre> </div> </div> <h4 id="adding-client-roles-to-a-user" class="discrete">Adding client roles to a user</h4> <div class="paragraph"> <p>Use an <code>add-roles</code> command to add client roles to a user.</p> </div> <div class="paragraph"> <p>Use the following example to add two roles defined on the client <code>realm management</code>, the <code>create-client</code> role and the <code>view-users</code> role, to the user <code>testuser</code>.</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh add-roles -r demorealm --uusername testuser --cclientid realm-management --rolename create-client --rolename view-users</pre> </div> </div> <h4 id="removing-client-roles-from-a-user" class="discrete">Removing client roles from a user</h4> <div class="paragraph"> <p>Use a <code>remove-roles</code> command to remove client roles from a user.</p> </div> <div class="paragraph"> <p>Use the following example to remove two roles defined on the realm management client:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh remove-roles -r demorealm --uusername testuser --cclientid realm-management --rolename create-client --rolename view-users</pre> </div> </div> <h4 id="listing-a-users-sessions" class="discrete">Listing a user&#8217;s sessions</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Identify the user&#8217;s ID,</p> </li> <li> <p>Use the ID to compose an endpoint URI, such as <code>users/ID/sessions</code>.</p> </li> <li> <p>Use the <code>get</code> command to retrieve a list of the user&#8217;s sessions.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get users/6da5ab89-3397-4205-afaa-e201ff638f9e/sessions -r demorealm</pre> </div> </div> </li> </ol> </div> <h4 id="logging-out-a-user-from-a-specific-session" class="discrete">Logging out a user from a specific session</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Determine the session&#8217;s ID as described earlier.</p> </li> <li> <p>Use the session&#8217;s ID to compose an endpoint URI, such as <code>sessions/ID</code>.</p> </li> <li> <p>Use the <code>delete</code> command to invalidate the session.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh delete sessions/d0eaa7cc-8c5d-489d-811a-69d3c4ec84d1 -r demorealm</pre> </div> </div> </li> </ol> </div> <h4 id="logging-out-a-user-from-all-sessions" class="discrete">Logging out a user from all sessions</h4> <div class="paragraph"> <p>Use the user&#8217;s ID to construct an endpoint URI, such as <code>users/ID/logout</code>.</p> </div> <div class="paragraph"> <p>Use the <code>create</code> command to perform <code>POST</code> on that endpoint URI.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create users/6da5ab89-3397-4205-afaa-e201ff638f9e/logout -r demorealm -s realm=demorealm -s user=6da5ab89-3397-4205-afaa-e201ff638f9e</pre> </div> </div> </div> <div class="sect2"> <h3 id="_group_operations"><a class="anchor" href="#_group_operations"></a>Group operations</h3> <h4 id="creating-a-group" class="discrete">Creating a group</h4> <div class="paragraph"> <p>Use the <code>create</code> command on the <code>groups</code> endpoint to create a new group.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create groups -r demorealm -s name=Group</pre> </div> </div> <h4 id="listing-groups" class="discrete">Listing groups</h4> <div class="paragraph"> <p>Use the <code>get</code> command on the <code>groups</code> endpoint to list groups.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get groups -r demorealm</pre> </div> </div> <h4 id="getting-a-specific-group" class="discrete">Getting a specific group</h4> <div class="paragraph"> <p>Use the group&#8217;s ID to construct an endpoint URI, such as <code>groups/GROUP_ID</code>.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get groups/51204821-0580-46db-8f2d-27106c6b5ded -r demorealm</pre> </div> </div> <h4 id="updating-a-group" class="discrete">Updating a group</h4> <div class="paragraph"> <p>Use the <code>update</code> command with the same endpoint URI that you use to get a specific group.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh update groups/51204821-0580-46db-8f2d-27106c6b5ded -s 'attributes.email=["group@example.com"]' -r demorealm</pre> </div> </div> <h4 id="deleting-a-group" class="discrete">Deleting a group</h4> <div class="paragraph"> <p>Use the <code>delete</code> command with the same endpoint URI that you use to get a specific group.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh delete groups/51204821-0580-46db-8f2d-27106c6b5ded -r demorealm</pre> </div> </div> <h4 id="creating-a-subgroup" class="discrete">Creating a subgroup</h4> <div class="paragraph"> <p>Find the ID of the parent group by listing groups. Use that ID to construct an endpoint URI, such as <code>groups/GROUP_ID/children</code>.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create groups/51204821-0580-46db-8f2d-27106c6b5ded/children -r demorealm -s name=SubGroup</pre> </div> </div> <h4 id="moving-a-group-under-another-group" class="discrete">Moving a group under another group</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Find the ID of an existing parent group and the ID of an existing child group.</p> </li> <li> <p>Use the parent group&#8217;s ID to construct an endpoint URI, such as <code>groups/PARENT_GROUP_ID/children</code>.</p> </li> <li> <p>Run the <code>create</code> command on this endpoint and pass the child group&#8217;s ID as a JSON body.</p> </li> </ol> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create groups/51204821-0580-46db-8f2d-27106c6b5ded/children -r demorealm -s id=08d410c6-d585-4059-bb07-54dcb92c5094 -s name=SubGroup</pre> </div> </div> <h4 id="get-groups-for-a-specific-user" class="discrete">Get groups for a specific user</h4> <div class="paragraph"> <p>Use a user&#8217;s ID to determine a user&#8217;s membership in groups to compose an endpoint URI, such as <code>users/USER_ID/groups</code>.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get users/b544f379-5fc4-49e5-8a8d-5cfb71f46f53/groups -r demorealm</pre> </div> </div> <h4 id="adding-a-user-to-a-group" class="discrete">Adding a user to a group</h4> <div class="paragraph"> <p>Use the <code>update</code> command with an endpoint URI composed of a user&#8217;s ID and a group&#8217;s ID, such as <code>users/USER_ID/groups/GROUP_ID</code>, to add a user to a group.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh update users/b544f379-5fc4-49e5-8a8d-5cfb71f46f53/groups/ce01117a-7426-4670-a29a-5c118056fe20 -r demorealm -s realm=demorealm -s userId=b544f379-5fc4-49e5-8a8d-5cfb71f46f53 -s groupId=ce01117a-7426-4670-a29a-5c118056fe20 -n</pre> </div> </div> <h4 id="removing-a-user-from-a-group" class="discrete">Removing a user from a group</h4> <div class="paragraph"> <p>Use the <code>delete</code> command on the same endpoint URI you use for adding a user to a group, such as <code>users/USER_ID/groups/GROUP_ID</code>, to remove a user from a group.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh delete users/b544f379-5fc4-49e5-8a8d-5cfb71f46f53/groups/ce01117a-7426-4670-a29a-5c118056fe20 -r demorealm</pre> </div> </div> <h4 id="listing-assigned-available-and-effective-realm-roles-for-a-group" class="discrete">Listing assigned, available, and effective realm roles for a group</h4> <div class="paragraph"> <p>Use a dedicated <code>get-roles</code> command to list assigned, available, and effective realm roles for a group.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Specify the target group by name (<code>--gname</code> option), path (<code>--gpath</code> option), or ID (<code>--gid</code> option) to list <strong>assigned</strong> realm roles for the group.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get-roles -r demorealm --gname Group</pre> </div> </div> </li> <li> <p>Use the <code>--effective</code> option to list <strong>effective</strong> realm roles.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get-roles -r demorealm --gname Group --effective</pre> </div> </div> </li> <li> <p>Use the <code>--available</code> option to list realm roles that you can add to the group.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get-roles -r demorealm --gname Group --available</pre> </div> </div> </li> </ol> </div> <h4 id="listing-assigned-available-and-effective-client-roles-for-a-group" class="discrete">Listing assigned, available, and effective client roles for a group</h4> <div class="paragraph"> <p>Use the <code>get-roles</code> command to list assigned, available, and effective client roles for a group.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Specify the target group by name (<code>--gname</code> option) or ID (<code>--gid</code> option),</p> </li> <li> <p>Specify the client by the clientId attribute (<code>--cclientid</code> option) or ID (<code>--id</code> option) to list <strong>assigned</strong> client roles for the user.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get-roles -r demorealm --gname Group --cclientid realm-management</pre> </div> </div> </li> <li> <p>Use the <code>--effective</code> option to list <strong>effective</strong> realm roles.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get-roles -r demorealm --gname Group --cclientid realm-management --effective</pre> </div> </div> </li> <li> <p>Use the <code>--available</code> option to list realm roles that you can still add to the group.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get-roles -r demorealm --gname Group --cclientid realm-management --available</pre> </div> </div> </li> </ol> </div> </div> <div class="sect2"> <h3 id="identity-provider-operations"><a class="anchor" href="#identity-provider-operations"></a>Identity provider operations</h3> <h4 id="listing-available-identity-providers" class="discrete">Listing available identity providers</h4> <div class="paragraph"> <p>Use the <code>serverinfo</code> endpoint to list available identity providers.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get serverinfo -r demorealm --fields 'identityProviders(*)'</pre> </div> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>Keycloak processes the <code>serverinfo</code> endpoint similarly to the <code>realms</code> endpoint. Keycloak does not resolve the endpoint relative to a target realm because it exists outside any specific realm.</p> </div> </td> </tr> </table> </div> <h4 id="listing-configured-identity-providers" class="discrete">Listing configured identity providers</h4> <div class="paragraph"> <p>Use the <code>identity-provider/instances</code> endpoint.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get identity-provider/instances -r demorealm --fields alias,providerId,enabled</pre> </div> </div> <h4 id="getting-a-specific-configured-identity-provider" class="discrete">Getting a specific configured identity provider</h4> <div class="paragraph"> <p>Use the identity provider&#8217;s <code>alias</code> attribute to construct an endpoint URI, such as <code>identity-provider/instances/ALIAS</code>, to get a specific identity provider.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get identity-provider/instances/facebook -r demorealm</pre> </div> </div> <h4 id="removing-a-specific-configured-identity-provider" class="discrete">Removing a specific configured identity provider</h4> <div class="paragraph"> <p>Use the <code>delete</code> command with the same endpoint URI that you use to get a specific configured identity provider to remove a specific configured identity provider.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh delete identity-provider/instances/facebook -r demorealm</pre> </div> </div> <h4 id="configuring-a-keycloak-openid-connect-identity-provider" class="discrete">Configuring a Keycloak OpenID Connect identity provider</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Use <code>keycloak-oidc</code> as the <code>providerId</code> when you create a new identity provider instance.</p> </li> <li> <p>Provide the <code>config</code> attributes: <code>authorizationUrl</code>, <code>tokenUrl</code>, <code>clientId</code>, and <code>clientSecret</code>.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create identity-provider/instances -r demorealm -s alias=keycloak-oidc -s providerId=keycloak-oidc -s enabled=true -s 'config.useJwksUrl="true"' -s config.authorizationUrl=http://localhost:8180/realms/demorealm/protocol/openid-connect/auth -s config.tokenUrl=http://localhost:8180/realms/demorealm/protocol/openid-connect/token -s config.clientId=demo-oidc-provider -s config.clientSecret=secret</pre> </div> </div> </li> </ol> </div> <h4 id="configuring-an-openid-connect-identity-provider" class="discrete">Configuring an OpenID Connect identity provider</h4> <div class="paragraph"> <p>Configure the generic OpenID Connect provider the same way you configure the Keycloak OpenID Connect provider, except you set the <code>providerId</code> attribute value to <code>oidc</code>.</p> </div> <h4 id="configuring-a-saml-2-identity-provider" class="discrete">Configuring a SAML 2 identity provider</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Use <code>saml</code> as the <code>providerId</code>.</p> </li> <li> <p>Provide the <code>config</code> attributes: <code>singleSignOnServiceUrl</code>, <code>nameIDPolicyFormat</code>, and <code>signatureAlgorithm</code>.</p> </li> </ol> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create identity-provider/instances -r demorealm -s alias=saml -s providerId=saml -s enabled=true -s 'config.useJwksUrl="true"' -s config.singleSignOnServiceUrl=http://localhost:8180/realms/saml-broker-realm/protocol/saml -s config.nameIDPolicyFormat=urn:oasis:names:tc:SAML:2.0:nameid-format:persistent -s config.signatureAlgorithm=RSA_SHA256</pre> </div> </div> <h4 id="configuring-a-facebook-identity-provider" class="discrete">Configuring a Facebook identity provider</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Use <code>facebook</code> as the <code>providerId</code>.</p> </li> <li> <p>Provide the <code>config</code> attributes: <code>clientId</code> and <code>clientSecret</code>. You can find these attributes in the Facebook Developers application configuration page for your application. See the <a href="#_facebook">Facebook identity broker</a> page for more information.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create identity-provider/instances -r demorealm -s alias=facebook -s providerId=facebook -s enabled=true -s 'config.useJwksUrl="true"' -s config.clientId=FACEBOOK_CLIENT_ID -s config.clientSecret=FACEBOOK_CLIENT_SECRET</pre> </div> </div> </li> </ol> </div> <h4 id="configuring-a-google-identity-provider" class="discrete">Configuring a Google identity provider</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Use <code>google</code> as the <code>providerId</code>.</p> </li> <li> <p>Provide the <code>config</code> attributes: <code>clientId</code> and <code>clientSecret</code>. You can find these attributes in the Google Developers application configuration page for your application. See the <a href="#_google">Google identity broker</a> page for more information.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create identity-provider/instances -r demorealm -s alias=google -s providerId=google -s enabled=true -s 'config.useJwksUrl="true"' -s config.clientId=GOOGLE_CLIENT_ID -s config.clientSecret=GOOGLE_CLIENT_SECRET</pre> </div> </div> </li> </ol> </div> <h4 id="configuring-a-twitter-identity-provider" class="discrete">Configuring a Twitter identity provider</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Use <code>twitter</code> as the <code>providerId</code>.</p> </li> <li> <p>Provide the <code>config</code> attributes <code>clientId</code> and <code>clientSecret</code>. You can find these attributes in the Twitter Application Management application configuration page for your application. See the <a href="#_twitter">Twitter identity broker</a> page for more information.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create identity-provider/instances -r demorealm -s alias=google -s providerId=google -s enabled=true -s 'config.useJwksUrl="true"' -s config.clientId=TWITTER_API_KEY -s config.clientSecret=TWITTER_API_SECRET</pre> </div> </div> </li> </ol> </div> <h4 id="configuring-a-github-identity-provider" class="discrete">Configuring a GitHub identity provider</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Use <code>github</code> as the <code>providerId</code>.</p> </li> <li> <p>Provide the <code>config</code> attributes <code>clientId</code> and <code>clientSecret</code>. You can find these attributes in the GitHub Developer Application Settings page for your application. See the <a href="#_github">GitHub identity broker</a> page for more information.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create identity-provider/instances -r demorealm -s alias=github -s providerId=github -s enabled=true -s 'config.useJwksUrl="true"' -s config.clientId=GITHUB_CLIENT_ID -s config.clientSecret=GITHUB_CLIENT_SECRET</pre> </div> </div> </li> </ol> </div> <h4 id="configuring-a-linkedin-identity-provider" class="discrete">Configuring a LinkedIn identity provider</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Use <code>linkedin</code> as the <code>providerId</code>.</p> </li> <li> <p>Provide the <code>config</code> attributes <code>clientId</code> and <code>clientSecret</code>. You can find these attributes in the LinkedIn Developer Console application page for your application. See the <a href="#_linkedin">LinkedIn identity broker</a> page for more information.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create identity-provider/instances -r demorealm -s alias=linkedin -s providerId=linkedin -s enabled=true -s 'config.useJwksUrl="true"' -s config.clientId=LINKEDIN_CLIENT_ID -s config.clientSecret=LINKEDIN_CLIENT_SECRET</pre> </div> </div> </li> </ol> </div> <h4 id="configuring-a-microsoft-live-identity-provider" class="discrete">Configuring a Microsoft Live identity provider</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Use <code>microsoft</code> as the <code>providerId</code>.</p> </li> <li> <p>Provide the <code>config</code> attributes <code>clientId</code> and <code>clientSecret</code>. You can find these attributes in the Microsoft Application Registration Portal page for your application. See the <a href="#_microsoft">Microsoft identity broker</a> page for more information.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create identity-provider/instances -r demorealm -s alias=microsoft -s providerId=microsoft -s enabled=true -s 'config.useJwksUrl="true"' -s config.clientId=MICROSOFT_APP_ID -s config.clientSecret=MICROSOFT_PASSWORD</pre> </div> </div> </li> </ol> </div> <h4 id="configuring-a-stack-overflow-identity-provider" class="discrete">Configuring a Stack Overflow identity provider</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Use <code>stackoverflow</code> command as the <code>providerId</code>.</p> </li> <li> <p>Provide the <code>config</code> attributes <code>clientId</code>, <code>clientSecret</code>, and <code>key</code>. You can find these attributes in the Stack Apps OAuth page for your application. See the <a href="#_stackoverflow">Stack Overflow identity broker</a> page for more information.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create identity-provider/instances -r demorealm -s alias=stackoverflow -s providerId=stackoverflow -s enabled=true -s 'config.useJwksUrl="true"' -s config.clientId=STACKAPPS_CLIENT_ID -s config.clientSecret=STACKAPPS_CLIENT_SECRET -s config.key=STACKAPPS_KEY</pre> </div> </div> </li> </ol> </div> </div> <div class="sect2"> <h3 id="storage-provider-operations"><a class="anchor" href="#storage-provider-operations"></a>Storage provider operations</h3> <h4 id="configuring-a-kerberos-storage-provider" class="discrete">Configuring a Kerberos storage provider</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Use the <code>create</code> command against the <code>components</code> endpoint.</p> </li> <li> <p>Specify the realm id as a value of the <code>parentId</code> attribute.</p> </li> <li> <p>Specify <code>kerberos</code> as the value of the <code>providerId</code> attribute, and <code>org.keycloak.storage.UserStorageProvider</code> as the value of the <code>providerType</code> attribute.</p> </li> <li> <p>For example:</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create components -r demorealm -s parentId=demorealmId -s id=demokerberos -s name=demokerberos -s providerId=kerberos -s providerType=org.keycloak.storage.UserStorageProvider -s 'config.priority=["0"]' -s 'config.debug=["false"]' -s 'config.allowPasswordAuthentication=["true"]' -s 'config.editMode=["UNSYNCED"]' -s 'config.updateProfileFirstLogin=["true"]' -s 'config.allowKerberosAuthentication=["true"]' -s 'config.kerberosRealm=["KEYCLOAK.ORG"]' -s 'config.keyTab=["http.keytab"]' -s 'config.serverPrincipal=["HTTP/localhost@KEYCLOAK.ORG"]' -s 'config.cachePolicy=["DEFAULT"]'</pre> </div> </div> </li> </ol> </div> <h4 id="configuring-an-ldap-user-storage-provider" class="discrete">Configuring an LDAP user storage provider</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Use the <code>create</code> command against the <code>components</code> endpoint.</p> </li> <li> <p>Specify <code>ldap</code> as the value of the <code>providerId</code> attribute, and <code>org.keycloak.storage.UserStorageProvider</code> as the value of the <code>providerType</code> attribute.</p> </li> <li> <p>Provide the realm ID as the value of the <code>parentId</code> attribute.</p> </li> <li> <p>Use the following example to create a Kerberos-integrated LDAP provider.</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create components -r demorealm -s name=kerberos-ldap-provider -s providerId=ldap -s providerType=org.keycloak.storage.UserStorageProvider -s parentId=3d9c572b-8f33-483f-98a6-8bb421667867 -s 'config.priority=["1"]' -s 'config.fullSyncPeriod=["-1"]' -s 'config.changedSyncPeriod=["-1"]' -s 'config.cachePolicy=["DEFAULT"]' -s config.evictionDay=[] -s config.evictionHour=[] -s config.evictionMinute=[] -s config.maxLifespan=[] -s 'config.batchSizeForSync=["1000"]' -s 'config.editMode=["WRITABLE"]' -s 'config.syncRegistrations=["false"]' -s 'config.vendor=["other"]' -s 'config.usernameLDAPAttribute=["uid"]' -s 'config.rdnLDAPAttribute=["uid"]' -s 'config.uuidLDAPAttribute=["entryUUID"]' -s 'config.userObjectClasses=["inetOrgPerson, organizationalPerson"]' -s 'config.connectionUrl=["ldap://localhost:10389"]' -s 'config.usersDn=["ou=People,dc=keycloak,dc=org"]' -s 'config.authType=["simple"]' -s 'config.bindDn=["uid=admin,ou=system"]' -s 'config.bindCredential=["secret"]' -s 'config.searchScope=["1"]' -s 'config.useTruststoreSpi=["always"]' -s 'config.connectionPooling=["true"]' -s 'config.pagination=["true"]' -s 'config.allowKerberosAuthentication=["true"]' -s 'config.serverPrincipal=["HTTP/localhost@KEYCLOAK.ORG"]' -s 'config.keyTab=["http.keytab"]' -s 'config.kerberosRealm=["KEYCLOAK.ORG"]' -s 'config.debug=["true"]' -s 'config.useKerberosForPasswordAuthentication=["true"]'</pre> </div> </div> </li> </ol> </div> <h4 id="removing-a-user-storage-provider-instance" class="discrete">Removing a user storage provider instance</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Use the storage provider instance&#8217;s <code>id</code> attribute to compose an endpoint URI, such as <code>components/ID</code>.</p> </li> <li> <p>Run the <code>delete</code> command against this endpoint.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh delete components/3d9c572b-8f33-483f-98a6-8bb421667867 -r demorealm</pre> </div> </div> </li> </ol> </div> <h4 id="triggering-synchronization-of-all-users-for-a-specific-user-storage-provider" class="discrete">Triggering synchronization of all users for a specific user storage provider</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Use the storage provider&#8217;s <code>id</code> attribute to compose an endpoint URI, such as <code>user-storage/ID_OF_USER_STORAGE_INSTANCE/sync</code>.</p> </li> <li> <p>Add the <code>action=triggerFullSync</code> query parameter.</p> </li> <li> <p>Run the <code>create</code> command.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create user-storage/b7c63d02-b62a-4fc1-977c-947d6a09e1ea/sync?action=triggerFullSync</pre> </div> </div> </li> </ol> </div> <h4 id="triggering-synchronization-of-changed-users-for-a-specific-user-storage-provider" class="discrete">Triggering synchronization of changed users for a specific user storage provider</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Use the storage provider&#8217;s <code>id</code> attribute to compose an endpoint URI, such as <code>user-storage/ID_OF_USER_STORAGE_INSTANCE/sync</code>.</p> </li> <li> <p>Add the <code>action=triggerChangedUsersSync</code> query parameter.</p> </li> <li> <p>Run the <code>create</code> command.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create user-storage/b7c63d02-b62a-4fc1-977c-947d6a09e1ea/sync?action=triggerChangedUsersSync</pre> </div> </div> </li> </ol> </div> <h4 id="test-ldap-user-storage-connectivity" class="discrete">Test LDAP user storage connectivity</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Run the <code>get</code> command on the <code>testLDAPConnection</code> endpoint.</p> </li> <li> <p>Provide query parameters <code>bindCredential</code>, <code>bindDn</code>, <code>connectionUrl</code>, and <code>useTruststoreSpi</code>.</p> </li> <li> <p>Set the <code>action</code> query parameter to <code>testConnection</code>.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create testLDAPConnection -s action=testConnection -s bindCredential=secret -s bindDn=uid=admin,ou=system -s connectionUrl=ldap://localhost:10389 -s useTruststoreSpi=always</pre> </div> </div> </li> </ol> </div> <h4 id="test-ldap-user-storage-authentication" class="discrete">Test LDAP user storage authentication</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Run the <code>get</code> command on the <code>testLDAPConnection</code> endpoint.</p> </li> <li> <p>Provide the query parameters <code>bindCredential</code>, <code>bindDn</code>, <code>connectionUrl</code>, and <code>useTruststoreSpi</code>.</p> </li> <li> <p>Set the <code>action</code> query parameter to <code>testAuthentication</code>.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create testLDAPConnection -s action=testAuthentication -s bindCredential=secret -s bindDn=uid=admin,ou=system -s connectionUrl=ldap://localhost:10389 -s useTruststoreSpi=always</pre> </div> </div> </li> </ol> </div> </div> <div class="sect2"> <h3 id="adding-mappers"><a class="anchor" href="#adding-mappers"></a>Adding mappers</h3> <h4 id="adding-a-hard-coded-role-ldap-mapper" class="discrete">Adding a hard-coded role LDAP mapper</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Run the <code>create</code> command on the <code>components</code> endpoint.</p> </li> <li> <p>Set the <code>providerType</code> attribute to <code>org.keycloak.storage.ldap.mappers.LDAPStorageMapper</code>.</p> </li> <li> <p>Set the <code>parentId</code> attribute to the ID of the LDAP provider instance.</p> </li> <li> <p>Set the <code>providerId</code> attribute to <code>hardcoded-ldap-role-mapper</code>. Ensure you provide a value of <code>role</code> configuration parameter.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create components -r demorealm -s name=hardcoded-ldap-role-mapper -s providerId=hardcoded-ldap-role-mapper -s providerType=org.keycloak.storage.ldap.mappers.LDAPStorageMapper -s parentId=b7c63d02-b62a-4fc1-977c-947d6a09e1ea -s 'config.role=["realm-management.create-client"]'</pre> </div> </div> </li> </ol> </div> <h4 id="adding-an-ms-active-directory-mapper" class="discrete">Adding an MS Active Directory mapper</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Run the <code>create</code> command on the <code>components</code> endpoint.</p> </li> <li> <p>Set the <code>providerType</code> attribute to <code>org.keycloak.storage.ldap.mappers.LDAPStorageMapper</code>.</p> </li> <li> <p>Set the <code>parentId</code> attribute to the ID of the LDAP provider instance.</p> </li> <li> <p>Set the <code>providerId</code> attribute to <code>msad-user-account-control-mapper</code>.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create components -r demorealm -s name=msad-user-account-control-mapper -s providerId=msad-user-account-control-mapper -s providerType=org.keycloak.storage.ldap.mappers.LDAPStorageMapper -s parentId=b7c63d02-b62a-4fc1-977c-947d6a09e1ea</pre> </div> </div> </li> </ol> </div> <h4 id="adding-a-user-attribute-ldap-mapper" class="discrete">Adding a user attribute LDAP mapper</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Run the <code>create</code> command on the <code>components</code> endpoint.</p> </li> <li> <p>Set the <code>providerType</code> attribute to <code>org.keycloak.storage.ldap.mappers.LDAPStorageMapper</code>.</p> </li> <li> <p>Set the <code>parentId</code> attribute to the ID of the LDAP provider instance.</p> </li> <li> <p>Set the <code>providerId</code> attribute to <code>user-attribute-ldap-mapper</code>.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create components -r demorealm -s name=user-attribute-ldap-mapper -s providerId=user-attribute-ldap-mapper -s providerType=org.keycloak.storage.ldap.mappers.LDAPStorageMapper -s parentId=b7c63d02-b62a-4fc1-977c-947d6a09e1ea -s 'config."user.model.attribute"=["email"]' -s 'config."ldap.attribute"=["mail"]' -s 'config."read.only"=["false"]' -s 'config."always.read.value.from.ldap"=["false"]' -s 'config."is.mandatory.in.ldap"=["false"]'</pre> </div> </div> </li> </ol> </div> <h4 id="adding-a-group-ldap-mapper" class="discrete">Adding a group LDAP mapper</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Run the <code>create</code> command on the <code>components</code> endpoint.</p> </li> <li> <p>Set the <code>providerType</code> attribute to <code>org.keycloak.storage.ldap.mappers.LDAPStorageMapper</code>.</p> </li> <li> <p>Set the <code>parentId</code> attribute to the ID of the LDAP provider instance.</p> </li> <li> <p>Set the <code>providerId</code> attribute to <code>group-ldap-mapper</code>.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create components -r demorealm -s name=group-ldap-mapper -s providerId=group-ldap-mapper -s providerType=org.keycloak.storage.ldap.mappers.LDAPStorageMapper -s parentId=b7c63d02-b62a-4fc1-977c-947d6a09e1ea -s 'config."groups.dn"=[]' -s 'config."group.name.ldap.attribute"=["cn"]' -s 'config."group.object.classes"=["groupOfNames"]' -s 'config."preserve.group.inheritance"=["true"]' -s 'config."membership.ldap.attribute"=["member"]' -s 'config."membership.attribute.type"=["DN"]' -s 'config."groups.ldap.filter"=[]' -s 'config.mode=["LDAP_ONLY"]' -s 'config."user.roles.retrieve.strategy"=["LOAD_GROUPS_BY_MEMBER_ATTRIBUTE"]' -s 'config."mapped.group.attributes"=["admins-group"]' -s 'config."drop.non.existing.groups.during.sync"=["false"]' -s 'config.roles=["admins"]' -s 'config.groups=["admins-group"]' -s 'config.group=[]' -s 'config.preserve=["true"]' -s 'config.membership=["member"]'</pre> </div> </div> </li> </ol> </div> <h4 id="adding-a-full-name-ldap-mapper" class="discrete">Adding a full name LDAP mapper</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Run the <code>create</code> command on the <code>components</code> endpoint.</p> </li> <li> <p>Set the <code>providerType</code> attribute to <code>org.keycloak.storage.ldap.mappers.LDAPStorageMapper</code>.</p> </li> <li> <p>Set the <code>parentId</code> attribute to the ID of the LDAP provider instance.</p> </li> <li> <p>Set the <code>providerId</code> attribute to <code>full-name-ldap-mapper</code>.</p> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create components -r demorealm -s name=full-name-ldap-mapper -s providerId=full-name-ldap-mapper -s providerType=org.keycloak.storage.ldap.mappers.LDAPStorageMapper -s parentId=b7c63d02-b62a-4fc1-977c-947d6a09e1ea -s 'config."ldap.full.name.attribute"=["cn"]' -s 'config."read.only"=["false"]' -s 'config."write.only"=["true"]'</pre> </div> </div> </li> </ol> </div> </div> <div class="sect2"> <h3 id="authentication-operations"><a class="anchor" href="#authentication-operations"></a>Authentication operations</h3> <h4 id="setting-a-password-policy" class="discrete">Setting a password policy</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Set the realm&#8217;s <code>passwordPolicy</code> attribute to an enumeration expression that includes the specific policy provider ID and optional configuration.</p> </li> <li> <p>Use the following example to set a password policy to default values. The default values include:</p> <div class="ulist"> <ul> <li> <p>210,000 hashing iterations</p> </li> <li> <p>at least one special character</p> </li> <li> <p>at least one uppercase character</p> </li> <li> <p>at least one digit character</p> </li> <li> <p>not be equal to a user&#8217;s <code>username</code></p> </li> <li> <p>be at least eight characters long</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh update realms/demorealm -s 'passwordPolicy="hashIterations and specialChars and upperCase and digits and notUsername and length"'</pre> </div> </div> </li> </ul> </div> </li> <li> <p>To use values different from defaults, pass the configuration in brackets.</p> </li> <li> <p>Use the following example to set a password policy to:</p> <div class="ulist"> <ul> <li> <p>300,000 hash iterations</p> </li> <li> <p>at least two special characters</p> </li> <li> <p>at least two uppercase characters</p> </li> <li> <p>at least two lowercase characters</p> </li> <li> <p>at least two digits</p> </li> <li> <p>be at least nine characters long</p> </li> <li> <p>not be equal to a user&#8217;s <code>username</code></p> </li> <li> <p>not repeat for at least four changes back</p> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh update realms/demorealm -s 'passwordPolicy="hashIterations(300000) and specialChars(2) and upperCase(2) and lowerCase(2) and digits(2) and length(9) and notUsername and passwordHistory(4)"'</pre> </div> </div> </li> </ul> </div> </li> </ol> </div> <h4 id="obtaining-the-current-password-policy" class="discrete">Obtaining the current password policy</h4> <div class="paragraph"> <p>You can get the current realm configuration by filtering all output except for the <code>passwordPolicy</code> attribute.</p> </div> <div class="paragraph"> <p>For example, display <code>passwordPolicy</code> for <code>demorealm</code>.</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get realms/demorealm --fields passwordPolicy</pre> </div> </div> <h4 id="listing-authentication-flows" class="discrete">Listing authentication flows</h4> <div class="paragraph"> <p>Run the <code>get</code> command on the <code>authentication/flows</code> endpoint.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get authentication/flows -r demorealm</pre> </div> </div> <h4 id="getting-a-specific-authentication-flow" class="discrete">Getting a specific authentication flow</h4> <div class="paragraph"> <p>Run the <code>get</code> command on the <code>authentication/flows/FLOW_ID</code> endpoint.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get authentication/flows/febfd772-e1a1-42fb-b8ae-00c0566fafb8 -r demorealm</pre> </div> </div> <h4 id="listing-executions-for-a-flow" class="discrete">Listing executions for a flow</h4> <div class="paragraph"> <p>Run the <code>get</code> command on the <code>authentication/flows/FLOW_ALIAS/executions</code> endpoint.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh get authentication/flows/Copy%20of%20browser/executions -r demorealm</pre> </div> </div> <h4 id="adding-configuration-to-an-execution" class="discrete">Adding configuration to an execution</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Get execution for a flow.</p> </li> <li> <p>Note the ID of the flow.</p> </li> <li> <p>Run the <code>create</code> command on the <code>authentication/executions/{executionId}/config</code> endpoint.</p> </li> </ol> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm.sh create "authentication/executions/a3147129-c402-4760-86d9-3f2345e401c7/config" -r demorealm -b '{"config":{"x509-cert-auth.mapping-source-selection":"Match SubjectDN using regular expression","x509-cert-auth.regular-expression":"(.*?)(?:$)","x509-cert-auth.mapper-selection":"Custom Attribute Mapper","x509-cert-auth.mapper-selection.user-attribute-name":"usercertificate","x509-cert-auth.crl-checking-enabled":"","x509-cert-auth.crldp-checking-enabled":false,"x509-cert-auth.crl-relative-path":"crl.pem","x509-cert-auth.ocsp-checking-enabled":"","x509-cert-auth.ocsp-responder-uri":"","x509-cert-auth.keyusage":"","x509-cert-auth.extendedkeyusage":"","x509-cert-auth.confirmation-page-disallowed":""},"alias":"my_otp_config"}'</pre> </div> </div> <h4 id="getting-configuration-for-an-execution" class="discrete">Getting configuration for an execution</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Get execution for a flow.</p> </li> <li> <p>Note its <code>authenticationConfig</code> attribute, which contains the config ID.</p> </li> <li> <p>Run the <code>get</code> command on the <code>authentication/config/ID</code> endpoint.</p> </li> </ol> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm get "authentication/config/dd91611a-d25c-421a-87e2-227c18421833" -r demorealm</pre> </div> </div> <h4 id="updating-configuration-for-an-execution" class="discrete">Updating configuration for an execution</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Get the execution for the flow.</p> </li> <li> <p>Get the flow&#8217;s <code>authenticationConfig</code> attribute.</p> </li> <li> <p>Note the config ID from the attribute.</p> </li> <li> <p>Run the <code>update</code> command on the <code>authentication/config/ID</code> endpoint.</p> </li> </ol> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm update "authentication/config/dd91611a-d25c-421a-87e2-227c18421833" -r demorealm -b '{"id":"dd91611a-d25c-421a-87e2-227c18421833","alias":"my_otp_config","config":{"x509-cert-auth.extendedkeyusage":"","x509-cert-auth.mapper-selection.user-attribute-name":"usercertificate","x509-cert-auth.ocsp-responder-uri":"","x509-cert-auth.regular-expression":"(.*?)(?:$)","x509-cert-auth.crl-checking-enabled":"true","x509-cert-auth.confirmation-page-disallowed":"","x509-cert-auth.keyusage":"","x509-cert-auth.mapper-selection":"Custom Attribute Mapper","x509-cert-auth.crl-relative-path":"crl.pem","x509-cert-auth.crldp-checking-enabled":"false","x509-cert-auth.mapping-source-selection":"Match SubjectDN using regular expression","x509-cert-auth.ocsp-checking-enabled":""}}'</pre> </div> </div> <h4 id="deleting-configuration-for-an-execution" class="discrete">Deleting configuration for an execution</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>Get execution for a flow.</p> </li> <li> <p>Get the flows <code>authenticationConfig</code> attribute.</p> </li> <li> <p>Note the config ID from the attribute.</p> </li> <li> <p>Run the <code>delete</code> command on the <code>authentication/config/ID</code> endpoint.</p> </li> </ol> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap">$ kcadm delete "authentication/config/dd91611a-d25c-421a-87e2-227c18421833" -r demorealm</pre> </div> </div> </div> </div> </div> </div> <div id="footer"> <div id="footer-text"> Last updated 2024-11-22 05:31:19 UTC </div> </div> <script src="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.4.2/tocbot.js"></script> <script> const oldtoc = document.getElementById('toctitle').nextElementSibling; const newtoc = document.createElement('div'); newtoc.setAttribute('id', 'tocbot'); newtoc.setAttribute('class', 'js-toc'); oldtoc.parentNode.replaceChild(newtoc, oldtoc); tocbot.init({ contentSelector: '#content', headingSelector: 'h2, h3, h4', smoothScroll: false }); const handleTocOnResize = function() { const width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; if (width < 768) { tocbot.refresh({ contentSelector: '#content', headingSelector: 'h2, h3, h4', collapseDepth: 6, activeLinkClass: 'ignoreactive', throttleTimeout: 1000, smoothScroll: false }); } else { tocbot.refresh({ contentSelector: '#content', headingSelector: 'h2, h3, h4', smoothScroll: false }); } }; window.addEventListener('resize', handleTocOnResize); handleTocOnResize(); </script> </body> </html>

Pages: 1 2 3 4 5 6 7 8 9 10