CINXE.COM

Upgrading 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>Upgrading 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>Upgrading Guide</h1> <div id="toc" class="toc2"> <div id="toctitle">Table of Contents</div> <ul class="sectlevel1"> <li><a href="#intro">Upgrading Keycloak</a></li> <li><a href="#migration-changes">Migration Changes</a> <ul class="sectlevel2"> <li><a href="#migrating-to-26-0-0">Migrating to 26.0.0</a> <ul class="sectlevel3"> <li><a href="#infinispan-marshalling-changes">Infinispan marshalling changes</a></li> <li><a href="#operator-no-longer-defaults-to-proxypassthrough">Operator no longer defaults to proxy=passthrough</a></li> <li><a href="#new-method-in-clusterprovider-api">New method in <code>ClusterProvider</code> API</a></li> <li><a href="#group-related-events-no-longer-fired-when-removing-a-realm">Group-related events no longer fired when removing a realm</a></li> <li><a href="#automatic-redirect-from-root-to-relative-path">Automatic redirect from root to relative path</a></li> <li><a href="#operator-scheduling-defaults">Operator scheduling defaults</a></li> <li><a href="#operators-default-cpu-and-memory-limitsrequests">Operator&#8217;s default CPU and memory limits/requests</a></li> <li><a href="#deprecations-in-keycloak-common-module">Deprecations in <code>keycloak-common</code> module</a></li> <li><a href="#consistent-usage-of-utf-8-charset-for-url-encoding">Consistent usage of UTF-8 charset for URL encoding</a></li> <li><a href="#configuring-the-ldap-connection-pool">Configuring the LDAP Connection Pool</a></li> <li><a href="#custom-footer-in-login-theme">Custom Footer in Login Theme</a></li> <li><a href="#persisting-revoked-access-tokens-across-restarts">Persisting revoked access tokens across restarts</a></li> <li><a href="#highly-available-multi-site-deployments">Highly available multi-site deployments</a></li> <li><a href="#external-infinispan-in-a-single-site-setup">External Infinispan in a single-site setup</a></li> <li><a href="#admin-bootstrapping-and-recovery">Admin Bootstrapping and Recovery</a></li> <li><a href="#application-initiated-required-action-redirect-now-contains-kc_action-parameter">Application Initiated Required Action redirect now contains kc_action Parameter</a></li> <li><a href="#deprecations-in-keycloak-services-module">Deprecations in <code>keycloak-services</code> module</a></li> <li><a href="#identity-providers-no-longer-available-from-the-realm-representation">Identity Providers no longer available from the realm representation</a></li> <li><a href="#cli-import-placeholder-replacement">CLI import placeholder replacement</a></li> <li><a href="#new-java-api-to-search-realms-by-name">New Java API to search realms by name</a></li> <li><a href="#keystore-and-trust-store-default-format-change">Keystore and trust store default format change</a></li> <li><a href="#improving-performance-for-selection-of-identity-providers">Improving performance for selection of identity providers</a></li> <li><a href="#removal-of-gelf-logging-handler">Removal of GELF logging handler</a></li> <li><a href="#paths-for-common-theme-resources-have-changed">Paths for <code>common</code> theme resources have changed</a></li> <li><a href="#additional-datasources-now-require-using-xa">Additional datasources now require using XA</a></li> <li><a href="#hostname-v1-feature-removed">Hostname v1 feature removed</a></li> <li><a href="#proxy-option-removed">Proxy option removed</a></li> <li><a href="#all-user-sessions-are-persisted-by-default">All user sessions are persisted by default</a></li> <li><a href="#grace-period-for-idle-sessions-removed-when-persistent-sessions-are-enabled">Grace period for idle sessions removed when persistent sessions are enabled</a></li> <li><a href="#support-for-legacy-redirect_uri-parameter-and-spi-options-has-been-removed">Support for legacy <code>redirect_uri</code> parameter and SPI options has been removed</a></li> <li><a href="#additional-validations-on-the-optimized-startup-option">Additional validations on the <code>--optimized</code> startup option</a></li> <li><a href="#adapter-and-misc-bom-files-are-removed">Adapter and misc BOM files are removed</a></li> <li><a href="#keycloak-test-helper-is-removed">keycloak-test-helper is removed</a></li> <li><a href="#jee-admin-client-is-removed">JEE admin-client is removed</a></li> <li><a href="#new-generalized-event-types-for-credentials">New generalized event types for credentials</a></li> <li><a href="#import-realm-option-can-import-the-master-realm"><code>--import-realm</code> option can import the master realm</a></li> <li><a href="#bouncycastle-fips-updated">BouncyCastle FIPS updated</a></li> <li><a href="#setorcreatechild-method-removed-from-javascript-admin-client"><code>setOrCreateChild()</code> method removed from JavaScript Admin Client</a></li> <li><a href="#keycloak-js">Keycloak JS</a></li> <li><a href="#stricter-startup-behavior-for-build-time-options">Stricter startup behavior for build-time options</a></li> <li><a href="#features-renamed">Features renamed</a></li> </ul> </li> <li><a href="#migrating-to-25-0-3">Migrating to 25.0.3</a> <ul class="sectlevel3"> <li><a href="#concurrent-login-requests-are-blocked-by-default-when-brute-force-is-enabled">Concurrent login requests are blocked by default when brute force is enabled</a></li> </ul> </li> <li><a href="#migrating-to-25-0-2">Migrating to 25.0.2</a> <ul class="sectlevel3"> <li><a href="#improving-performance-for-deletion-of-user-consents">Improving performance for deletion of user consents</a></li> </ul> </li> <li><a href="#migrating-to-25-0-0">Migrating to 25.0.0</a> <ul class="sectlevel3"> <li><a href="#new-hostname-options">New Hostname options</a></li> <li><a href="#persistent-user-sessions">Persistent user sessions</a></li> <li><a href="#metrics-for-embedded-caches-enabled-by-default">Metrics for embedded caches enabled by default</a></li> <li><a href="#metrics-for-http-endpoints-enabled-by-default">Metrics for HTTP endpoints enabled by default</a></li> <li><a href="#argon2-password-hashing">Argon2 password hashing</a></li> <li><a href="#limiting-memory-usage-when-consuming-http-responses">Limiting memory usage when consuming HTTP responses</a></li> <li><a href="#hostname-verification-policy">Hostname Verification Policy</a></li> <li><a href="#addressed-you-are-already-logged-in-for-expired-authentication-sessions">Addressed 'You are already logged in' for expired authentication sessions</a></li> <li><a href="#removed-a-model-module">Removed a model module</a></li> <li><a href="#xa-transaction-changes">XA Transaction Changes</a></li> <li><a href="#removed-offline-session-preloading">Removed offline session preloading</a></li> <li><a href="#specify-cache-options-at-runtime">Specify <code>cache</code> options at runtime</a></li> <li><a href="#kcadm-and-kcreg-changes">kcadm and kcreg changes</a></li> <li><a href="#removing-custom-user-attribute-indexes">Removing custom user attribute indexes</a></li> <li><a href="#new-default-client-scope-basic">New default client scope <code>basic</code></a></li> <li><a href="#removed-session_state-claim">Removed <code>session_state</code> claim</a></li> <li><a href="#sub-claim-is-added-to-access-token-via-protocol-mapper"><code>sub</code> claim is added to access token via protocol mapper</a></li> <li><a href="#nonce-claim-is-only-added-to-the-id-token">Nonce claim is only added to the ID token</a></li> <li><a href="#changed-userid-for-events-related-to-refresh-token">Changed <code>userId</code> for events related to refresh token</a></li> <li><a href="#using-older-javascript-adapter">Using older javascript adapter</a></li> <li><a href="#default-http-pool-max-threads-reduced">Default <code>http-pool-max-threads</code> reduced</a></li> <li><a href="#management-port-for-metrics-and-health-endpoints">Management port for metrics and health endpoints</a></li> <li><a href="#escaping-slashes-in-group-paths">Escaping slashes in group paths</a></li> <li><a href="#change-to-class-environmentdependentproviderfactory">Change to class <code>EnvironmentDependentProviderFactory</code></a></li> <li><a href="#removal-of-the-deprecated-linkedin-provider">Removal of the deprecated LinkedIn provider</a></li> <li><a href="#improved-performance-of-findgrantedresources-and-findgrantedownerresources-queries">Improved performance of <code>findGrantedResources</code> and <code>findGrantedOwnerResources</code> queries</a></li> <li><a href="#removing-deprecated-methods-from-accesstoken-idtoken-and-jsonwebtoken-classes">Removing deprecated methods from <code>AccessToken</code>, <code>IDToken</code>, and <code>JsonWebToken</code> classes</a></li> <li><a href="#method-getexp-added-to-singleuseobjectkeymodel">Method <code>getExp</code> added to <code>SingleUseObjectKeyModel</code></a></li> <li><a href="#method-encode-deprecated-on-passwordhashprovider">Method encode deprecated on PasswordHashProvider</a></li> <li><a href="#collectionutil-intesection-method-removed">CollectionUtil intesection method removed</a></li> <li><a href="#resteasy-util-class-is-deprecated">Resteasy util class is deprecated</a></li> <li><a href="#small-changes-in-session-lifespan-and-idle-calculations">Small changes in session lifespan and idle calculations</a></li> <li><a href="#external-infinispan-requirements">External Infinispan requirements</a></li> <li><a href="#oracle-database-driver-not-part-of-the-distribution">Oracle Database driver not part of the distribution</a></li> <li><a href="#deprecated-theme-variables">Deprecated theme variables</a></li> <li><a href="#methods-to-get-and-set-current-refresh-token-in-client-session-are-now-deprecated">Methods to get and set current refresh token in client session are now deprecated</a></li> </ul> </li> <li><a href="#migrating-to-24-0-4">Migrating to 24.0.4</a> <ul class="sectlevel3"> <li><a href="#partial-update-to-user-attributes-when-updating-users-through-the-admin-user-api-is-no-longer-supported">Partial update to user attributes when updating users through the Admin User API is no longer supported</a></li> </ul> </li> <li><a href="#migrating-to-24-0-3">Migrating to 24.0.3</a> <ul class="sectlevel3"> <li><a href="#changes-to-the-org-keycloak-userprofile-userprofiledecorator-interface">Changes to the <code>org.keycloak.userprofile.UserProfileDecorator</code> interface</a></li> <li><a href="#changes-in-redirect-uri-verification-when-using-wildcards">Changes in redirect URI verification when using wildcards</a></li> <li><a href="#deprecated-account-rest-endpoint-for-removing-credential">Deprecated Account REST endpoint for removing credential</a></li> </ul> </li> <li><a href="#migrating-to-24-0-2">Migrating to 24.0.2</a> <ul class="sectlevel3"> <li><a href="#changes-to-password-hashing">Changes to Password Hashing</a></li> </ul> </li> <li><a href="#migrating-to-24-0-0">Migrating to 24.0.0</a> <ul class="sectlevel3"> <li><a href="#changes-to-the-welcome-theme">Changes to the Welcome theme</a></li> <li><a href="#changes-to-the-account-console-theme-customization">Changes to the Account Console theme customization</a></li> <li><a href="#keycloak-js-imports-might-need-to-be-updated">Keycloak JS imports might need to be updated</a></li> <li><a href="#features-changes">Features Changes</a></li> <li><a href="#user-profile-changes">User Profile Changes</a></li> <li><a href="#truststore-changes">Truststore Changes</a></li> <li><a href="#deprecated-proxy-option">Deprecated <code>--proxy</code> option</a></li> <li><a href="#changes-to-the-user-representation-in-both-admin-api-and-account-contexts">Changes to the user representation in both Admin API and Account contexts</a></li> <li><a href="#https-client-auth-is-a-build-time-option"><code>https-client-auth</code> is a build time option</a></li> <li><a href="#sequential-loading-of-offline-sessions-and-remote-sessions">Sequential loading of offline sessions and remote sessions</a></li> <li><a href="#deprecated-offline-session-preloading">Deprecated offline session preloading</a></li> <li><a href="#infinispan-metrics-use-labels-for-cache-manager-and-cache-names">Infinispan metrics use labels for cache manager and cache names</a></li> <li><a href="#user-attribute-value-length-extension">User attribute value length extension</a></li> <li><a href="#the-admin-send-verify-email-api-now-uses-the-same-email-verification-template">The Admin send-verify-email API now uses the same email verification template</a></li> <li><a href="#removal-of-the-deprecated-mode-for-saml-encryption">Removal of the deprecated mode for SAML encryption</a></li> <li><a href="#changes-to-password-hashing-2">Changes to Password Hashing</a></li> <li><a href="#operator-referenced-resource-polling">Operator Referenced Resource Polling</a></li> <li><a href="#renaming-jpa-provider-configuration-options-for-migration">Renaming JPA provider configuration options for migration</a></li> <li><a href="#renaming-model-modules">Renaming model modules</a></li> <li><a href="#temporary-lockout-log-replaced-with-event">Temporary lockout log replaced with event</a></li> <li><a href="#operator-customization-property-keys">Operator Customization Property Keys</a></li> <li><a href="#keycloak-cr-resources-options">Keycloak CR resources options</a></li> <li><a href="#updates-to-cookies">Updates to cookies</a></li> <li><a href="#internal-algorithm-changed-from-hs256-to-hs512">Internal algorithm changed from HS256 to HS512</a></li> <li><a href="#different-jvm-memory-settings-when-running-in-a-container">Different JVM memory settings when running in a container</a></li> <li><a href="#gelf-log-handler-has-been-deprecated">GELF log handler has been deprecated</a></li> </ul> </li> <li><a href="#migrating-to-23-0-5">Migrating to 23.0.5</a> <ul class="sectlevel3"> <li><a href="#changes-in-jboss-logging-event-messages">Changes in jboss-logging event messages</a></li> </ul> </li> <li><a href="#migrating-to-23-0-4">Migrating to 23.0.4</a> <ul class="sectlevel3"> <li><a href="#fix-handling-of-groups-getsubgroups-briefrepresentation-parameter">Fix handling of Groups.getSubGroups briefRepresentation parameter</a></li> </ul> </li> <li><a href="#migrating-to-23-0-2">Migrating to 23.0.2</a> <ul class="sectlevel3"> <li><a href="#valid-redirect-uris-for-clients-are-always-compared-with-exact-string-matching">Valid redirect URIs for clients are always compared with exact string matching</a></li> <li><a href="#operator-secrets-store-secret">Operator -secrets-store Secret</a></li> </ul> </li> <li><a href="#migrating-to-23-0-0">Migrating to 23.0.0</a> <ul class="sectlevel3"> <li><a href="#added-iss-parameter-to-oauth-2-0openid-connect-authentication-response">Added iss parameter to OAuth 2.0/OpenID Connect Authentication Response</a></li> <li><a href="#wildcard-characters-handling">Wildcard characters handling</a></li> <li><a href="#language-files-for-themes-default-to-utf-8-encoding">Language files for themes default to UTF-8 encoding</a></li> <li><a href="#changes-to-the-value-format-of-claims-mapped-by-the-realm-and-client-role-mappers">Changes to the value format of claims mapped by the realm and client role mappers</a></li> <li><a href="#changes-to-password-fields-in-login-ui">Changes to password fields in Login UI</a></li> <li><a href="#default-keycloak-cr-hostname">Default Keycloak CR Hostname</a></li> <li><a href="#the-deprecated-auto-build-cli-option-was-removed">The deprecated <code>auto-build</code> CLI option was removed</a></li> <li><a href="#kc-sh-and-shell-metacharacters">kc.sh and shell metacharacters</a></li> <li><a href="#removed-registrationprofile-form-action">Removed RegistrationProfile form action</a></li> <li><a href="#deprecated-methods-from-data-providers-and-models">Deprecated methods from data providers and models</a></li> <li><a href="#groupprovider-changes"><code>GroupProvider</code> changes</a></li> <li><a href="#grouprepresentation-changes"><code>GroupRepresentation</code> changes</a></li> <li><a href="#new-endpoint-for-group-admin-api">New endpoint for Group Admin API</a></li> <li><a href="#resteeasy-reactive">RESTEeasy Reactive</a></li> <li><a href="#partial-export-requires-manage-realm-permission">Partial export requires manage-realm permission</a></li> <li><a href="#removal-of-the-options-to-trim-the-events-details-length">Removal of the options to trim the event&#8217;s details length</a></li> <li><a href="#user-profile-updates">User Profile updates</a></li> <li><a href="#removal-of-the-map-store">Removal of the Map Store</a></li> <li><a href="#removed-namespaces-from-our-translations">Removed namespaces from our translations</a></li> </ul> </li> <li><a href="#migrating-to-22-0-4">Migrating to 22.0.4</a> <ul class="sectlevel3"> <li><a href="#a-new-parameter-for-specify-max-length-of-email-local-part">A new parameter for specify max length of email local part</a></li> </ul> </li> <li><a href="#migrating-to-22-0-2">Migrating to 22.0.2</a> <ul class="sectlevel3"> <li><a href="#never-expires-option-removed-from-client-advanced-settings-combos">Never expires option removed from client advanced settings combos</a></li> <li><a href="#new-linkedin-openid-connect-social-provider">New LinkedIn OpenID Connect social provider</a></li> </ul> </li> <li><a href="#migrating-to-22-0-0">Migrating to 22.0.0</a> <ul class="sectlevel3"> <li><a href="#transition-from-java-ee-to-jakarta-ee">Transition from Java EE to Jakarta EE</a></li> <li><a href="#upgrade-to-quarkus-3">Upgrade to Quarkus 3</a></li> <li><a href="#upgrade-to-hibernate-orm-6">Upgrade to Hibernate ORM 6</a></li> <li><a href="#legacy-promise-api-removed-from-keycloak-js-adapter">Legacy Promise API removed from Keycloak JS adapter</a></li> <li><a href="#export-and-import-perform-an-automatic-build">Export and Import perform an automatic build</a></li> <li><a href="#renamed-keycloak-admin-client-artifacts">Renamed Keycloak Admin client artifacts</a></li> <li><a href="#passthrough-proxy-mode-changes">Passthrough proxy mode changes</a></li> <li><a href="#consistent-fallback-message-resolving-for-all-themes">Consistent fallback message resolving for all themes</a></li> <li><a href="#userqueryprovider-changes"><code>UserQueryProvider</code> changes</a></li> <li><a href="#ldapstorageprovider-search-changes"><code>LDAPStorageProvider</code> search changes</a></li> <li><a href="#deprecation-of-keycloak-openid-connect-adapters">Deprecation of Keycloak OpenID Connect Adapters</a></li> <li><a href="#deprecation-of-keycloak-jee-saml-adapter">Deprecation of Keycloak JEE SAML Adapter</a></li> <li><a href="#changes-for-openshift-integration-feature">Changes for openshift-integration feature</a></li> <li><a href="#removing-third-party-dependencies">Removing third party dependencies</a></li> <li><a href="#context-and-dependency-injection-no-longer-enabled-to-jax-rs-resources">Context and dependency injection no longer enabled to JAX-RS Resources</a></li> <li><a href="#upgrading-your-custom-jax-rs-resources">Upgrading your custom JAX-RS resources</a></li> <li><a href="#deprecated-methods-from-data-providers-and-models-2">Deprecated methods from data providers and models</a></li> <li><a href="#multiple-keycloak-instances">Multiple Keycloak instances</a></li> <li><a href="#k8s-keycloak-orgv2alpha1-changes">k8s.keycloak.org/v2alpha1 changes</a></li> <li><a href="#keycloak-supports-ipv4ipv6-dual-stack">Keycloak supports IPv4/IPv6 dual stack</a></li> </ul> </li> <li><a href="#migrating-to-21-1-0">Migrating to 21.1.0</a> <ul class="sectlevel3"> <li><a href="#javascript-engine-available-by-default-on-the-classpath">Javascript engine available by default on the classpath</a></li> <li><a href="#change-of-the-default-client-id-mapper-of-service-account-client">Change of the default Client ID mapper of Service Account Client</a></li> <li><a href="#keycloak-js-adapter-must-be-instantiated-with-the-new-operator">Keycloak JS adapter must be instantiated with the <code>new</code> operator</a></li> </ul> </li> <li><a href="#migrating-to-21-0-2">Migrating to 21.0.2</a> <ul class="sectlevel3"> <li><a href="#terms-and-conditions-user-attribute-migration">Terms and Conditions user attribute migration</a></li> </ul> </li> <li><a href="#migrating-to-21-0-0">Migrating to 21.0.0</a> <ul class="sectlevel3"> <li><a href="#keycloak-uses-micrometer-for-metrics">Keycloak uses Micrometer for metrics</a></li> <li><a href="#deprecated-rsa_sha1-and-dsa_sha1-algorithms-for-saml">Deprecated RSA_SHA1 and DSA_SHA1 algorithms for SAML</a></li> <li><a href="#saml-sp-metadata-changes">SAML SP metadata changes</a></li> <li><a href="#deprecated-methods-from-user-session-provider-were-removed">Deprecated methods from user session provider were removed</a></li> <li><a href="#custom-themes-using-old-admin-console-wont-work">Custom themes using old admin console won&#8217;t work</a></li> <li><a href="#curl-has-been-removed-from-the-container">Curl has been removed from the container</a></li> </ul> </li> <li><a href="#migrating-to-20-0-0">Migrating to 20.0.0</a> <ul class="sectlevel3"> <li><a href="#resteasy-version-update">RESTEasy Version Update</a></li> <li><a href="#h2-version-update">H2 Version Update</a></li> <li><a href="#breaking-changes-in-the-new-version-of-keycloak-operator">Breaking changes in the new version of Keycloak Operator</a></li> <li><a href="#olm-channel-was-changed-to-fast">OLM channel was changed to fast</a></li> <li><a href="#deprecated-methods-from-data-providers-and-models-were-removed">Deprecated methods from data providers and models were removed</a></li> </ul> </li> <li><a href="#migrating-to-19-0-2">Migrating to 19.0.2</a> <ul class="sectlevel3"> <li><a href="#openid-connect-logout-prompt">OpenID Connect Logout Prompt</a></li> <li><a href="#deploying-scripts-through-saml-javascript-protocol-mapper">Deploying scripts through SAML javascript protocol mapper</a></li> <li><a href="#userinfo-endpoint-changes">UserInfo Endpoint Changes</a></li> </ul> </li> <li><a href="#migrating-to-19-0-0">Migrating to 19.0.0</a> <ul class="sectlevel3"> <li><a href="#new-admin-console-is-now-the-default-console">New Admin Console is now the default console</a></li> <li><a href="#changes-to-the-server-configuration-and-startup">Changes to the server configuration and startup</a></li> <li><a href="#potentially-breaking-changes-to-the-health-endpoints">Potentially breaking changes to the health endpoints</a></li> <li><a href="#changes-using-gelf-centralized-log-management">Changes using GELF / centralized log management</a></li> <li><a href="#changes-affecting-developers">Changes affecting developers</a></li> <li><a href="#deprecated-poddisruptionbudget-in-the-legacy-keycloak-operator">Deprecated <code>podDisruptionBudget</code> in the legacy Keycloak Operator</a></li> <li><a href="#deployment-changes-in-the-new-keycloak-operator">Deployment changes in the new Keycloak Operator</a></li> </ul> </li> <li><a href="#migrating-to-18-0-0">Migrating to 18.0.0</a> <ul class="sectlevel3"> <li><a href="#step-up-authentication">Step-up authentication</a></li> <li><a href="#openid-connect-logout">OpenID Connect Logout</a></li> <li><a href="#removal-of-the-upload-scripts-feature">Removal of the <code>upload-scripts</code> feature</a></li> <li><a href="#account-console-patternfly-upgrade">Account console Patternfly upgrade</a></li> <li><a href="#quarkus-distribution-split-metrics-enabled-option-into-health-enabled-and-metrics-enabled">Quarkus distribution: Split metrics-enabled option into health-enabled and metrics-enabled</a></li> </ul> </li> <li><a href="#migrating-to-17-0-0">Migrating to 17.0.0</a> <ul class="sectlevel3"> <li><a href="#default-distribution-is-now-powered-by-quarkus">Default distribution is now powered by Quarkus</a></li> <li><a href="#migrating-from-the-preview-quarkus-distribution">Migrating from the preview Quarkus distribution</a></li> <li><a href="#client-policies-migration-client-scopes">Client Policies Migration : client-scopes</a></li> <li><a href="#liquibase-upgraded-to-version-4-6-2">Liquibase upgraded to version 4.6.2</a></li> </ul> </li> <li><a href="#migrating-to-16-0-0">Migrating to 16.0.0</a> <ul class="sectlevel3"> <li><a href="#wildfly-25-upgrade">WildFly 25 upgrade</a></li> <li><a href="#proxy-environment-variables">Proxy environment variables</a></li> <li><a href="#deprecated-features-in-the-keycloak-operator">Deprecated features in the Keycloak Operator</a></li> <li><a href="#keycloak-operator-examples-including-unsupported-metrics-extension">Keycloak Operator examples including unsupported Metrics extension</a></li> </ul> </li> <li><a href="#migrating-to-14-0-0">Migrating to 14.0.0</a> <ul class="sectlevel3"> <li><a href="#client-policies-migration">Client policies migration</a></li> </ul> </li> <li><a href="#migrating-to-13-0-0">Migrating to 13.0.0</a> <ul class="sectlevel3"> <li><a href="#manual-migration-step-needed">Manual migration step needed</a></li> <li><a href="#upgrade-to-wildfly-23">Upgrade to Wildfly 23</a></li> <li><a href="#upgrade-to-wildfly-22">Upgrade to Wildfly 22</a></li> </ul> </li> <li><a href="#migrating-to-12-0-2">Migrating to 12.0.2</a> <ul class="sectlevel3"> <li><a href="#read-only-attributes">Read-only attributes</a></li> <li><a href="#valid-request-uris">Valid Request URIs</a></li> </ul> </li> <li><a href="#migrating-to-13-0-0-2">Migrating to 13.0.0</a> <ul class="sectlevel3"> <li><a href="#upgrade-to-wildfly-22-2">Upgrade to Wildfly 22</a></li> </ul> </li> <li><a href="#migrating-to-12-0-0">Migrating to 12.0.0</a> <ul class="sectlevel3"> <li><a href="#upgrade-to-wildfly-21">Upgrade to Wildfly 21</a></li> <li><a href="#skip-creation-of-user-session-for-the-docker-protocol-authentication">Skip creation of user session for the Docker protocol authentication</a></li> <li><a href="#upgrade-to-patternfly-4">Upgrade to PatternFly 4</a></li> <li><a href="#client-credentials-grant-without-refresh-token-by-default">Client Credentials Grant without refresh token by default</a></li> </ul> </li> <li><a href="#migrating-to-11-0-0">Migrating to 11.0.0</a> <ul class="sectlevel3"> <li><a href="#upgrade-to-wildfly-20">Upgrade to Wildfly 20</a></li> <li><a href="#ldap-no-import-bugfix">LDAP no-import bugfix</a></li> <li><a href="#usermodel-changes">UserModel changes</a></li> <li><a href="#instagram-idp-migrated-to-new-the-api">Instagram IdP migrated to new the API</a></li> <li><a href="#non-standard-token-introspection-endpoint-removed">Non-standard token introspection endpoint removed</a></li> </ul> </li> <li><a href="#migrating-to-9-0-1">Migrating to 9.0.1</a> <ul class="sectlevel3"> <li><a href="#legacy-promise-in-javascript-adapter">Legacy promise in JavaScript adapter</a></li> <li><a href="#duplicated-top-level-groups">Duplicated top level groups</a></li> </ul> </li> <li><a href="#migrating-to-9-0-0">Migrating to 9.0.0</a> <ul class="sectlevel3"> <li><a href="#improved-handling-of-user-locale">Improved handling of user locale</a></li> <li><a href="#deprecated-methods-in-token-representation-java-classes">Deprecated methods in token representation Java classes</a></li> </ul> </li> <li><a href="#migrating-to-8-0-2">Migrating to 8.0.2</a> <ul class="sectlevel3"> <li><a href="#more-authentication-flows-changes">More authentication flows changes</a></li> </ul> </li> <li><a href="#migrating-to-8-0-0">Migrating to 8.0.0</a> <ul class="sectlevel3"> <li><a href="#new-default-hostname-provider">New default Hostname provider</a></li> <li><a href="#upgrade-to-wildfly-18">Upgrade to Wildfly 18</a></li> <li><a href="#deploying-scripts-to-the-server">Deploying scripts to the server</a></li> <li><a href="#client-credentials-in-the-javascript-adapter">Client credentials in the JavaScript adapter</a></li> <li><a href="#authentication-flows-changes">Authentication flows changes</a></li> <li><a href="#user-credentials-changes">User credentials changes</a></li> </ul> </li> <li><a href="#migrating-to-7-0-0">Migrating to 7.0.0</a> <ul class="sectlevel3"> <li><a href="#upgrade-to-wildfly-17">Upgrade to Wildfly 17</a></li> </ul> </li> <li><a href="#migrating-to-6-0-0">Migrating to 6.0.0</a> <ul class="sectlevel3"> <li><a href="#upgrade-to-wildfly-16">Upgrade to Wildfly 16</a></li> <li><a href="#new-optional-client-scope">New optional client scope</a></li> <li><a href="#ability-to-propagate-promptnone-to-default-idp">Ability to propagate prompt=none to default IDP</a></li> </ul> </li> <li><a href="#migrating-to-5-0-0">Migrating to 5.0.0</a> <ul class="sectlevel3"> <li><a href="#upgrade-to-wildfly-15">Upgrade to Wildfly 15</a></li> </ul> </li> <li><a href="#migrating-to-4-8-2">Migrating to 4.8.2</a> <ul class="sectlevel3"> <li><a href="#google-identity-provider-updated-to-use-google-sign-in-authentication-system">Google Identity Provider updated to use Google Sign-in authentication system</a></li> <li><a href="#linkedin-social-broker-updated-to-version-2-of-linkedin-apis">LinkedIn social broker updated to Version 2 of LinkedIn APIs</a></li> </ul> </li> <li><a href="#migrating-to-4-6-0">Migrating to 4.6.0</a> <ul class="sectlevel3"> <li><a href="#new-default-client-scopes">New default client scopes</a></li> <li><a href="#javascript-adapter-promise">JavaScript adapter promise</a></li> <li><a href="#microsoft-identity-provider-updated-to-use-the-microsoft-graph-api">Microsoft Identity Provider updated to use the Microsoft Graph API</a></li> <li><a href="#upgrade-to-wildfly-14">Upgrade to Wildfly 14</a></li> </ul> </li> <li><a href="#migrating-to-4-4-0">Migrating to 4.4.0</a> <ul class="sectlevel3"> <li><a href="#upgrade-to-wildfly-13">Upgrade to Wildfly 13</a></li> </ul> </li> <li><a href="#migration-to-4-3-0">Migration to 4.3.0</a> <ul class="sectlevel3"> <li><a href="#hostname-configuration">Hostname configuration</a></li> </ul> </li> <li><a href="#migrating-to-4-0-0">Migrating to 4.0.0</a> <ul class="sectlevel3"> <li><a href="#client-templates-changed-to-client-scopes">Client Templates changed to Client Scopes</a></li> <li><a href="#changes-to-authorization-services">Changes to Authorization Services</a></li> </ul> </li> <li><a href="#migrating-to-3-4-2">Migrating to 3.4.2</a> <ul class="sectlevel3"> <li><a href="#added-session_state-parameter-to-openid-connect-authentication-response">Added session_state parameter to OpenID Connect Authentication Response</a></li> </ul> </li> <li><a href="#migrating-to-3-2-0">Migrating to 3.2.0</a> <ul class="sectlevel3"> <li><a href="#new-password-hashing-algorithms">New password hashing algorithms</a></li> <li><a href="#id-token-requires-scopeopenid">ID Token requires scope=openid</a></li> <li><a href="#authentication-sessions-and-action-tokens">Authentication sessions and Action tokens</a></li> </ul> </li> <li><a href="#migrating-to-2-5-1">Migrating to 2.5.1</a> <ul class="sectlevel3"> <li><a href="#migration-of-old-offline-tokens">Migration of old offline tokens</a></li> </ul> </li> <li><a href="#migrating-to-2-5-0">Migrating to 2.5.0</a> <ul class="sectlevel3"> <li><a href="#changes-to-the-infinispan-caches">Changes to the Infinispan caches</a></li> </ul> </li> <li><a href="#migrating-to-2-4-0">Migrating to 2.4.0</a> <ul class="sectlevel3"> <li><a href="#server-spi-split-into-server-spi-and-sever-spi-private">Server SPI split into Server SPI and Sever SPI Private</a></li> <li><a href="#key-encryption-algorithm-in-saml-assertions">Key encryption algorithm in SAML assertions</a></li> <li><a href="#infinispan-caches-realms-and-users-are-always-local">Infinispan caches realms and users are always local</a></li> </ul> </li> <li><a href="#migrating-to-2-3-0">Migrating to 2.3.0</a> <ul class="sectlevel3"> <li><a href="#default-max-results-on-paginated-endpoints">Default max results on paginated endpoints</a></li> <li><a href="#realm-public-key-adapter-property-not-recommended"><code>realm-public-key</code> adapter property not recommended</a></li> <li><a href="#added-infinispan-cache-keys">Added Infinispan cache <code>keys</code></a></li> </ul> </li> <li><a href="#migrating-to-2-2-0">Migrating to 2.2.0</a> <ul class="sectlevel3"> <li><a href="#databaseschema-property-deprecated"><code>databaseSchema</code> property <strong>deprecated</strong></a></li> <li><a href="#changes-in-clients-valid-redirect-uris">Changes in Client&#8217;s Valid Redirect URIs</a></li> <li><a href="#authenticate-by-default-removed-from-identity-providers">Authenticate by default removed from Identity Providers</a></li> </ul> </li> <li><a href="#migrating-to-2-0-0">Migrating to 2.0.0</a> <ul class="sectlevel3"> <li><a href="#upgrading-from-1-0-0-final-no-longer-supported">Upgrading from 1.0.0.Final no longer supported</a></li> </ul> </li> <li><a href="#migrating-to-1-9-5">Migrating to 1.9.5</a> <ul class="sectlevel3"> <li><a href="#default-password-hashing-interval-increased-to-20k">Default password hashing interval increased to 20K</a></li> </ul> </li> <li><a href="#migrating-to-1-9-3">Migrating to 1.9.3</a> <ul class="sectlevel3"> <li><a href="#add-user-script-renamed">Add User script renamed</a></li> </ul> </li> <li><a href="#migrating-to-1-9-2">Migrating to 1.9.2</a> <ul class="sectlevel3"> <li><a href="#adapter-option-auth-server-url-for-backend-requests-removed">Adapter option auth-server-url-for-backend-requests removed</a></li> </ul> </li> <li><a href="#migrating-to-1-9-0">Migrating to 1.9.0</a> <ul class="sectlevel3"> <li><a href="#themes-and-providers-directory-moved">Themes and providers directory moved</a></li> <li><a href="#adapter-subsystems-only-bring-in-dependencies-if-keycloak-is-on">Adapter subsystems only bring in dependencies if Keycloak is on</a></li> <li><a href="#client-registration-service-endpoints-moved">Client Registration service endpoints moved</a></li> <li><a href="#session-state-parameter-in-authentication-response-renamed">Session state parameter in authentication response renamed</a></li> <li><a href="#deprecated-openid-connect-endpoints">Deprecated OpenID Connect endpoints</a></li> <li><a href="#updates-to-theme-templates">Updates to theme templates</a></li> <li><a href="#module-and-source-code-reorganization">Module and source code reorganization</a></li> <li><a href="#for-adapters-session-id-changed-after-login">For adapters, session id changed after login</a></li> <li><a href="#saml-sp-client-adapter-changes">SAML SP Client adapter changes</a></li> </ul> </li> <li><a href="#migrating-to-1-8-0">Migrating to 1.8.0</a> <ul class="sectlevel3"> <li><a href="#admin-account">Admin account</a></li> <li><a href="#oauth2-token-introspection">OAuth2 token introspection</a></li> </ul> </li> <li><a href="#migrating-to-1-7-0-cr1">Migrating to 1.7.0.CR1</a> <ul class="sectlevel3"> <li><a href="#direct-access-grants-disabled-by-default-for-clients">Direct access grants disabled by default for clients</a></li> <li><a href="#option-update-profile-on-first-login-moved-from-identity-provider-to-review-profile-authenticator">Option 'Update Profile On First Login' moved from Identity provider to Review Profile authenticator</a></li> <li><a href="#element-form-error-page-in-web-xml-not-supported-anymore">Element 'form-error-page' in web.xml not supported anymore</a></li> <li><a href="#identityprovidermapper-changes">IdentityProviderMapper changes</a></li> </ul> </li> <li><a href="#migrating-to-1-6-0-final">Migrating to 1.6.0.Final</a> <ul class="sectlevel3"> <li><a href="#option-that-refresh-tokens-are-not-reusable-anymore">Option that refresh tokens are not reusable anymore</a></li> <li><a href="#some-packages-renamed">Some packages renamed</a></li> <li><a href="#persisting-user-sessions">Persisting user sessions</a></li> </ul> </li> <li><a href="#migrating-to-1-5-0-final">Migrating to 1.5.0.Final</a> <ul class="sectlevel3"> <li><a href="#realm-and-user-cache-providers">Realm and User cache providers</a></li> <li><a href="#uses-session-providers">Uses Session providers</a></li> <li><a href="#contact-details-removed-from-registration-and-account-management">Contact details removed from registration and account management</a></li> </ul> </li> <li><a href="#migrating-to-1-3-0-final">Migrating to 1.3.0.Final</a> <ul class="sectlevel3"> <li><a href="#direct-grant-api-always-enabled">Direct Grant API always enabled</a></li> <li><a href="#database-changed">Database changed</a></li> <li><a href="#userfederationprovider-changed">UserFederationProvider changed</a></li> <li><a href="#wildfly-9-0-0-final">WildFly 9.0.0.Final</a></li> <li><a href="#wildfly-jboss-eap-and-jboss-as7-adapters">WildFly, JBoss EAP and JBoss AS7 adapters</a></li> </ul> </li> <li><a href="#migrating-from-1-2-0-beta1-to-1-2-0-rc1">Migrating from 1.2.0.Beta1 to 1.2.0.RC1</a> <ul class="sectlevel3"> <li><a href="#distribution-changes">Distribution changes</a></li> <li><a href="#database-changed-2">Database changed</a></li> <li><a href="#application-and-oauth-client-merge">Application and OAuth client merge</a></li> </ul> </li> <li><a href="#migrating-from-1-1-0-final-to-1-2-0-beta1">Migrating from 1.1.0.Final to 1.2.0.Beta1</a> <ul class="sectlevel3"> <li><a href="#database-changed-3">Database changed</a></li> <li><a href="#iss-in-access-and-id-tokens"><code>iss</code> in access and id tokens</a></li> <li><a href="#openid-connect-endpoints">OpenID Connect endpoints</a></li> <li><a href="#theme-changes">Theme changes</a></li> <li><a href="#claims-changes">Claims changes</a></li> <li><a href="#social-migration-to-identity-brokering">Social migration to identity brokering</a></li> </ul> </li> <li><a href="#migrating-from-1-1-0-beta1-to-1-1-0-beta2">Migrating from 1.1.0.Beta1 to 1.1.0.Beta2</a></li> <li><a href="#migrating-from-1-0-x-final-to-1-1-0-beta1">Migrating from 1.0.x.Final to 1.1.0.Beta1</a></li> <li><a href="#migrating-from-1-0-rc-1-to-rc-2">Migrating from 1.0 RC-1 to RC-2</a></li> <li><a href="#migrating-from-1-0-beta-4-to-rc-1">Migrating from 1.0 Beta 4 to RC-1</a></li> <li><a href="#migrating-from-1-0-beta-1-to-beta-4">Migrating from 1.0 Beta 1 to Beta 4</a></li> <li><a href="#migrating-from-1-0-alpha-4-to-beta-1">Migrating from 1.0 Alpha 4 to Beta 1</a></li> <li><a href="#migrating-from-1-0-alpha-2-to-alpha-3">Migrating from 1.0 Alpha 2 to Alpha 3</a></li> <li><a href="#migrating-from-1-0-alpha-1-to-alpha-2">Migrating from 1.0 Alpha 1 to Alpha 2</a></li> </ul> </li> <li><a href="#_upgrading">Upgrading the Keycloak server</a> <ul class="sectlevel2"> <li><a href="#_prep_migration">Preparing for upgrading</a></li> <li><a href="#_install_new_version">Downloading the Keycloak server</a></li> <li><a href="#_migrate_db">Migrating the database</a> <ul class="sectlevel3"> <li><a href="#automatic-relational-database-migration">Automatic relational database migration</a></li> <li><a href="#manual-relational-database-migration">Manual relational database migration</a></li> </ul> </li> <li><a href="#_migrate_themes">Migrating themes</a> <ul class="sectlevel3"> <li><a href="#migrating-templates">Migrating templates</a></li> <li><a href="#migrating-messages">Migrating messages</a></li> <li><a href="#migrating-styles">Migrating styles</a></li> </ul> </li> </ul> </li> <li><a href="#upgrading-keycloak-adapters">Upgrading Keycloak adapters</a> <ul class="sectlevel2"> <li><a href="#_compatibility_with_older_adapters">Compatibility with older adapters</a></li> <li><a href="#_upgrade_eap_adapter">Upgrading the EAP adapter</a></li> <li><a href="#_upgrade_js_adapter">Upgrading the JavaScript adapter</a></li> <li><a href="#_upgrade_nodejs_adapter">Upgrading the <code>Node.js</code> adapter</a></li> </ul> </li> <li><a href="#upgrading-the-keycloak-client-libraries">Upgrading the Keycloak Client Libraries</a></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>Upgrading</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_admin/">Server Administration</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/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="intro"><a class="anchor" href="#intro"></a>Upgrading Keycloak</h2> <div class="sectionbody"> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/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:%20upgrading/topics/intro.adoc&amp;description=%0A%0AFile:%20upgrading/topics/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="paragraph"> <p>This guide describes how to upgrade Keycloak. Use the following procedures in this order:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Review the migration changes from the previous version of Keycloak.</p> </li> <li> <p>Upgrade the Keycloak server.</p> </li> <li> <p>Upgrade the Keycloak adapters.</p> </li> <li> <p>Upgrade the Keycloak Admin Client.</p> </li> </ol> </div> </div> </div> <div class="sect1"> <h2 id="migration-changes"><a class="anchor" href="#migration-changes"></a>Migration Changes</h2> <div class="sectionbody"> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/changes/changes.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/changes/changes.adoc&amp;description=%0A%0AFile:%20upgrading/topics/changes/changes.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="migrating-to-26-0-0"><a class="anchor" href="#migrating-to-26-0-0"></a>Migrating to 26.0.0</h3> <div class="sect3"> <h4 id="infinispan-marshalling-changes"><a class="anchor" href="#infinispan-marshalling-changes"></a>Infinispan marshalling changes</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/changes/changes-26_0_0.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/changes/changes-26_0_0.adoc&amp;description=%0A%0AFile:%20upgrading/topics/changes/changes-26_0_0.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>Marshalling is the process of converting Java objects into bytes to send them across the network between Keycloak servers. With Keycloak 26, the marshalling library has changed from JBoss Marshalling to Infinispan Protostream. The libraries are not compatible between each other and, it requires some steps to ensure the session data is not lost.</p> </div> <div class="admonitionblock warning"> <table> <tr> <td class="icon"> <i class="fa icon-warning" title="Warning"></i> </td> <td class="content"> JBoss Marshalling and Infinispan Protostream are not compatible with each other and incorrect usage may lead to data loss. Consequently, all caches are cleared when upgrading to this version. </td> </tr> </table> </div> <div class="paragraph"> <p>To prevent losing user sessions upgrade to Keycloak 25 first and enable the persistent sessions feature as outlined in the migration guide for Keycloak 25.</p> </div> </div> <div class="sect3"> <h4 id="operator-no-longer-defaults-to-proxypassthrough"><a class="anchor" href="#operator-no-longer-defaults-to-proxypassthrough"></a>Operator no longer defaults to proxy=passthrough</h4> <div class="paragraph"> <p>The Operator will no longer default to the hostname v1 setting of proxy=passthrough. This allows deployments using hostname v2 for a fixed edge hostname to work as desired without additional options.</p> </div> </div> <div class="sect3"> <h4 id="new-method-in-clusterprovider-api"><a class="anchor" href="#new-method-in-clusterprovider-api"></a>New method in <code>ClusterProvider</code> API</h4> <div class="paragraph"> <p>The following method was added to <code>org.keycloak.cluster.ClusterProvider</code>:</p> </div> <div class="ulist"> <ul> <li> <p><code>void notify(String taskKey, Collection&lt;? extends ClusterEvent&gt; events, boolean ignoreSender, DCNotify dcNotify)</code></p> </li> </ul> </div> <div class="paragraph"> <p>When multiple events are sent to the same <code>taskKey</code>, this method batches events and just perform a single network call. This is an optimization to reduce traffic and network related resources.</p> </div> <div class="paragraph"> <p>In Keycloak 26, the new method has a default implementation to keep backward compatibility with custom implementation. The default implementation performs a single network call per an event, and it will be removed in a future version of Keycloak.</p> </div> </div> <div class="sect3"> <h4 id="group-related-events-no-longer-fired-when-removing-a-realm"><a class="anchor" href="#group-related-events-no-longer-fired-when-removing-a-realm"></a>Group-related events no longer fired when removing a realm</h4> <div class="paragraph"> <p>With the goal of improving the scalability of groups, they are now removed directly from the database when removing a realm. As a consequence, group-related events like the <code>GroupRemovedEvent</code> are no longer fired when removing a realm.</p> </div> <div class="paragraph"> <p>If you have extensions handling any group-related event when a realm is removed, make sure to use the <code>RealmRemovedEvent</code> instead to perform any cleanup or custom processing when a realm, and their groups, are removed.</p> </div> <div class="paragraph"> <p>The <code>GroupProvider</code> interface is also updated with a new <code>preRemove(RealmModel)</code> method to force implementations to properly handle the removal of groups when a realm is removed.</p> </div> </div> <div class="sect3"> <h4 id="automatic-redirect-from-root-to-relative-path"><a class="anchor" href="#automatic-redirect-from-root-to-relative-path"></a>Automatic redirect from root to relative path</h4> <div class="paragraph"> <p>User is automatically redirected to the path where Keycloak is hosted when the <code>http-relative-path</code> property is specified. It means when the relative path is set to <code>/auth</code>, and the user access <code>localhost:8080/</code>, the page is redirected to <code>localhost:8080/auth</code>.</p> </div> <div class="paragraph"> <p>The same applies to the management interface when the <code>http-management-relative-path</code> or <code>http-relative-path</code> property is specified.</p> </div> <div class="paragraph"> <p>It improves user experience as users no longer need to set the relative path to the URL explicitly.</p> </div> </div> <div class="sect3"> <h4 id="operator-scheduling-defaults"><a class="anchor" href="#operator-scheduling-defaults"></a>Operator scheduling defaults</h4> <div class="paragraph"> <p>Keycloak Pods will now have default affinities to prevent multiple instances from the same CR from being deployed on the same node, and all Pods from the same CR will prefer to be in the same zone to prevent stretch cache clusters.</p> </div> </div> <div class="sect3"> <h4 id="operators-default-cpu-and-memory-limitsrequests"><a class="anchor" href="#operators-default-cpu-and-memory-limitsrequests"></a>Operator&#8217;s default CPU and memory limits/requests</h4> <div class="paragraph"> <p>In order to follow the best practices, the default CPU and memory limits/requests for the Operator were introduced. It affects both non-OLM and OLM installs. To override the default values for the OLM install, edit the <code>resources</code> section in the operator&#8217;s <a href="https://github.com/operator-framework/operator-lifecycle-manager/blob/master/doc/design/subscription-config.md#resources">subscription</a>.</p> </div> </div> <div class="sect3"> <h4 id="deprecations-in-keycloak-common-module"><a class="anchor" href="#deprecations-in-keycloak-common-module"></a>Deprecations in <code>keycloak-common</code> module</h4> <div class="paragraph"> <p>The following items have been deprecated for removal in upcoming Keycloak versions with no replacement:</p> </div> <div class="ulist"> <ul> <li> <p><code>org.keycloak.common.util.reflections.Reflections.newInstance(java.lang.Class&lt;T&gt;)</code></p> </li> <li> <p><code>org.keycloak.common.util.reflections.Reflections.newInstance(java.lang.Class&lt;?&gt;, java.lang.String)</code></p> </li> <li> <p><code>org.keycloak.common.util.reflections.SetAccessiblePrivilegedAction</code></p> </li> <li> <p><code>org.keycloak.common.util.reflections.UnSetAccessiblePrivilegedAction</code></p> </li> </ul> </div> </div> <div class="sect3"> <h4 id="consistent-usage-of-utf-8-charset-for-url-encoding"><a class="anchor" href="#consistent-usage-of-utf-8-charset-for-url-encoding"></a>Consistent usage of UTF-8 charset for URL encoding</h4> <div class="paragraph"> <p><code>org.keycloak.common.util.Encode</code> now always uses the <code>UTF-8</code> charset for URL encoding instead relying implicitly on the <code>file.encoding</code> system property.</p> </div> </div> <div class="sect3"> <h4 id="configuring-the-ldap-connection-pool"><a class="anchor" href="#configuring-the-ldap-connection-pool"></a>Configuring the LDAP Connection Pool</h4> <div class="paragraph"> <p>In this release, the LDAP connection pool configuration relies solely on system properties. The main reason is that the LDAP connection pool configuration is a JVM-level configuration rather than specific to an individual realm or LDAP provider instance.</p> </div> <div class="paragraph"> <p>Compared to previous releases, any realm configuration related to the LDAP connection pool will be ignored. If you are migrating from previous versions where any of the following settings are set to your LDAP provider(s), consider using system properties instead:</p> </div> <div class="ulist"> <ul> <li> <p><code>connectionPoolingAuthentication</code></p> </li> <li> <p><code>connectionPoolingInitSize</code></p> </li> <li> <p><code>connectionPoolingMaxSize</code></p> </li> <li> <p><code>connectionPoolingPrefSize</code></p> </li> <li> <p><code>connectionPoolingTimeout</code></p> </li> <li> <p><code>connectionPoolingProtocol</code></p> </li> <li> <p><code>connectionPoolingDebug</code></p> </li> </ul> </div> <div class="paragraph"> <p>For more details, see <a href="https://www.keycloak.org/docs/26.0.6/server_admin/#_ldap_connection_pool">Configuring the connection pool</a>.</p> </div> </div> <div class="sect3"> <h4 id="custom-footer-in-login-theme"><a class="anchor" href="#custom-footer-in-login-theme"></a>Custom Footer in Login Theme</h4> <div class="paragraph"> <p>This release introduced the capability to easily add a custom footer to the login pages for the <code>base/login</code> and <code>keycloak.v2/login</code> theme. In order to use a custom footer, create a <code>footer.ftl</code> file in your custom login theme with the desired content.</p> </div> <div class="paragraph"> <p>For more details, see <a href="https://www.keycloak.org/docs/26.0.6/server_development/#_theme_custom_footer">Adding a custom footer to a login theme</a>.</p> </div> </div> <div class="sect3"> <h4 id="persisting-revoked-access-tokens-across-restarts"><a class="anchor" href="#persisting-revoked-access-tokens-across-restarts"></a>Persisting revoked access tokens across restarts</h4> <div class="paragraph"> <p>In this release, revoked access tokens are written to the database and reloaded when the cluster is restarted by default when using the embedded caches.</p> </div> <div class="paragraph"> <p>To disable this behavior, use the SPI option <code>spi-single-use-object-infinispan-persist-revoked-tokens</code> as outlined in the <a href="https://www.keycloak.org/server/all-provider-config">All provider configuration</a> guide.</p> </div> <div class="paragraph"> <p>The SPI behavior of <code>SingleUseObjectProvider</code> has changed that for revoked tokens only the methods <code>put</code> and <code>contains</code> must be used. This is enforced by default, and can be disabled using the SPI option <code>spi-single-use-object-infinispan-persist-revoked-tokens</code>.</p> </div> </div> <div class="sect3"> <h4 id="highly-available-multi-site-deployments"><a class="anchor" href="#highly-available-multi-site-deployments"></a>Highly available multi-site deployments</h4> <div class="paragraph"> <p>Keycloak 26 introduces significant improvements to the recommended HA multi-site architecture, most notably:</p> </div> <div class="ulist"> <ul> <li> <p>Keycloak deployments are now able to handle user requests simultaneously in both sites. Previous load balancer configurations handling requests only in one site at a time will continue to work.</p> </li> <li> <p>Active monitoring of the connectivity between the sites is now required to the replication between the sites in case of a failure. The blueprints describe a setup with Alertmanager and AWS Lambda.</p> </li> <li> <p>The loadbalancer blueprint has been updated to use the AWS Global Accelerator as this avoids prolonged fail-over times caused by DNS caching by clients.</p> </li> <li> <p>Persistent user sessions are now a requirement of the architecture. Consequently, user sessions will be kept on Keycloak or Infinispan upgrades.</p> </li> <li> <p>External Infinispan request handling has been improved to reduce memory usage and request latency.</p> </li> </ul> </div> <div class="paragraph"> <p>As a consequence of the above changes, the following changes are required to your existing Keycloak deployments.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p><code>distributed-cache</code> definitions provided by a cache configuration file are ignored when the <code>multi-site</code> feature is enabled, so you must configure the connection to the external Infinispan deployment via the <code>cache-remote-*</code> command line arguments or Keycloak CR as outlined in the blueprints. All <code>remote-store</code> configurations must be removed from the cache configuration file.</p> </li> <li> <p>Review your current cache configurations in the external Infinispan and update them with those outlined in the latest version of the Keycloak&#8217;s documentation. While previous versions of the cache configurations only logged warnings when the backup replication between sites failed, the new configurations ensure that the state in both sites stays in sync: When the transfer between the two sites fails, the caller will see an error. Due to that, you need to set up monitoring to disconnect the two sites in case of a site failure. The Keycloak High Availability Guide contains a blueprint on how to set this up.</p> </li> <li> <p>While previous load balancer configurations will continue to work with Keycloak, consider upgrading an existing Route53 configuration to avoid prolonged failover times due to client side DNS caching.</p> </li> <li> <p>If you have updated your cache configuration XML file with remote-store configurations, those will no longer work. Instead, enable the <code>multi-site</code> feature and use the <code>cache-remove-*</code> options.</p> </li> </ol> </div> </div> <div class="sect3"> <h4 id="external-infinispan-in-a-single-site-setup"><a class="anchor" href="#external-infinispan-in-a-single-site-setup"></a>External Infinispan in a single-site setup</h4> <div class="paragraph"> <p>If you are using an external Infinispan in a single-site setup, this was not supported in earlier versions of Keycloak and it is not supported in Keycloak 26. To protect users from using it accidentally via a manual configuration in Keycloak&#8217;s cache XML or via the CLI options, this is now guarded with a feature flag <code>cache-embedded-remote-store</code>. It is marked as experimental and is therefore not supported. Keycloak 26 will not start with such a configuration and show an error instead unless this experimental feature is enabled.</p> </div> <div class="paragraph"> <p>If you have been using an external Infinispan to keep users logged in between restarts and upgrades, use the <code>persistent-user-sessions</code> feature instead which is enabled by default. The external Infinispan is then no longer necessary.</p> </div> <div class="paragraph"> <p>The experimental feature <code>cache-embedded-remote-store</code> <strong>will be removed in a future minor release</strong>.</p> </div> </div> <div class="sect3"> <h4 id="admin-bootstrapping-and-recovery"><a class="anchor" href="#admin-bootstrapping-and-recovery"></a>Admin Bootstrapping and Recovery</h4> <div class="paragraph"> <p>It used to be difficult to regain access to a Keycloak instance when all admin users were locked out. The process required multiple advanced steps, including direct database access and manual changes. In an effort to improve the user experience, Keycloak now provides multiple ways to bootstrap a new admin account, which can be used to recover from such situations.</p> </div> <div class="paragraph"> <p>Consequently, the environment variables <code>KEYCLOAK_ADMIN</code> and <code>KEYCLOAK_ADMIN_PASSWORD</code> have been deprecated. You should use <code>KC_BOOTSTRAP_ADMIN_USERNAME</code> and <code>KC_BOOTSTRAP_ADMIN_PASSWORD</code> instead. These are also general options, so they may be specified via the cli or other config sources, for example <code>--bootstrap-admin-username=admin</code>. For more information, see the new <a href="https://www.keycloak.org/server/bootstrap-admin-recovery">Bootstrap admin and recovery</a> guide.</p> </div> </div> <div class="sect3"> <h4 id="application-initiated-required-action-redirect-now-contains-kc_action-parameter"><a class="anchor" href="#application-initiated-required-action-redirect-now-contains-kc_action-parameter"></a>Application Initiated Required Action redirect now contains kc_action Parameter</h4> <div class="paragraph"> <p>The required action provider name is now returned via the <code>kc_action</code> parameter when redirecting back from an application initiated required action execution. This eases the detection of which required action was executed for a client. The outcome of the execution can be determined via the <code>kc_action_status</code> parameter.</p> </div> <div class="paragraph"> <p>Note: This feature required changes to the Keycloak JS adapter, therefore it is recommended to upgrade to the latest version of the adapter if you want to make use of this feature.</p> </div> </div> <div class="sect3"> <h4 id="deprecations-in-keycloak-services-module"><a class="anchor" href="#deprecations-in-keycloak-services-module"></a>Deprecations in <code>keycloak-services</code> module</h4> <div class="paragraph"> <p>The class <code>UserSessionCrossDCManager</code> is deprecated and planned to be removed in a future version of Keycloak. Read the <code>UserSessionCrossDCManager</code> Javadoc for the alternative methods to use.</p> </div> </div> <div class="sect3"> <h4 id="identity-providers-no-longer-available-from-the-realm-representation"><a class="anchor" href="#identity-providers-no-longer-available-from-the-realm-representation"></a>Identity Providers no longer available from the realm representation</h4> <div class="paragraph"> <p>As part of the improvements around the scalability of realms and organizations when they have many identity providers, the realm representation no longer holds the list of identity providers. However, they are still available from the realm representation when exporting a realm.</p> </div> <div class="paragraph"> <p>To obtain the query the identity providers in a realm, prefer using the <code>/realms/{realm}/identity-provider/instances</code> endpoint. This endpoint supports filters and pagination.</p> </div> </div> <div class="sect3"> <h4 id="cli-import-placeholder-replacement"><a class="anchor" href="#cli-import-placeholder-replacement"></a>CLI import placeholder replacement</h4> <div class="paragraph"> <p>The CLI command <code>kc.[sh|bat] import</code> now has placeholder replacement enabled. Previously placeholder replacement was only enabled for realm import at startup.</p> </div> <div class="paragraph"> <p>If you wish to disable placeholder replacement for the <code>import</code> command, add the system property <code>-Dkeycloak.migration.replace-placeholders=false</code></p> </div> </div> <div class="sect3"> <h4 id="new-java-api-to-search-realms-by-name"><a class="anchor" href="#new-java-api-to-search-realms-by-name"></a>New Java API to search realms by name</h4> <div class="paragraph"> <p>The <code>RealmProvider</code> Java API now contains a new method <code>Stream&lt;RealmModel&gt; getRealmsStream(String search)</code> which allows searching for a realm by name. While there is a default implementation which filters the stream after loading it from the provider, implementations are encouraged to provide this with more efficient implementation.</p> </div> </div> <div class="sect3"> <h4 id="keystore-and-trust-store-default-format-change"><a class="anchor" href="#keystore-and-trust-store-default-format-change"></a>Keystore and trust store default format change</h4> <div class="paragraph"> <p>Keycloak now determines the format of the keystore and trust store based on the file extension. If the file extension is <code>.p12</code>, <code>.pkcs12</code> or <code>.pfx</code>, the format is PKCS12. If the file extension is <code>.jks</code>, <code>.keystore</code> or <code>.truststore</code>, the format is JKS. If the file extension is <code>.pem</code>, <code>.crt</code> or <code>.key</code>, the format is PEM.</p> </div> <div class="paragraph"> <p>You can still override automatic detection by specifying the <code>https-key-store-type</code> and <code>https-trust-store-type</code> explicitly. The same applies to the management interface and its <code>https-management-key-store-type</code>. Restrictions for the FIPS strict mode stay unchanged.</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>spi-truststore-file-*</code> options and the truststore related options <code>https-trust-store-*</code> are deprecated, we strongly recommend to use System Truststore. For more details refer to the relevant <a href="https://www.keycloak.org/server/keycloak-truststore">guide</a>. </td> </tr> </table> </div> </div> <div class="sect3"> <h4 id="improving-performance-for-selection-of-identity-providers"><a class="anchor" href="#improving-performance-for-selection-of-identity-providers"></a>Improving performance for selection of identity providers</h4> <div class="paragraph"> <p>New indexes were added to the <code>IDENTITY_PROVIDER</code> table to improve the performance of queries that fetch the IDPs associated with an organization, and fetch IDPs that are available for login (those that are <code>enabled</code>, not <code>link_only</code>, not marked as <code>hide_on_login</code>).</p> </div> <div class="paragraph"> <p>If the table currently contains more than 300.000 entries, Keycloak will skip the creation of the indexes by default during the automatic schema migration, and will instead log the SQL statements on the console during migration. In this case, the statements must be run manually in the DB after Keycloak&#8217;s startup.</p> </div> <div class="paragraph"> <p>Also, the <code>kc.org</code> and <code>hideOnLoginPage</code> configuration attributes were migrated to the identity provider itself, to allow for more efficient queries when searching for providers. As such, API clients should use the <code>getOrganizationId/setOrganizationId</code> and <code>isHideOnLogin/setHideOnLogin</code> methods in the <code>IdentityProviderRepresentation</code>, and avoid setting these properties using the legacy config attributes that are now deprecated.</p> </div> </div> <div class="sect3"> <h4 id="removal-of-gelf-logging-handler"><a class="anchor" href="#removal-of-gelf-logging-handler"></a>Removal of GELF logging handler</h4> <div class="paragraph"> <p>GELF support has been deprecated for a while now, and with this release it has been finally removed from Keycloak. Other log handlers are available and fully supported to be used as a replacement of GELF, for example Syslog. For details see the <a href="https://www.keycloak.org/server/logging">Logging guide</a>.</p> </div> </div> <div class="sect3"> <h4 id="paths-for-common-theme-resources-have-changed"><a class="anchor" href="#paths-for-common-theme-resources-have-changed"></a>Paths for <code>common</code> theme resources have changed</h4> <div class="paragraph"> <p>Some of the paths for the <code>common</code> resources of the <code>keycloak</code> theme have changed, specifically the resources for third-party libraries. Make sure to update your custom themes accordingly:</p> </div> <div class="ulist"> <ul> <li> <p><code>node_modules/patternfly/dist</code> is now <code>vendor/patternfly-v3</code></p> </li> <li> <p><code>node_modules/@patternfly/patternfly</code> is now <code>vendor/patternfly-v4</code></p> </li> <li> <p><code>node_modules/@patternfly-v5/patternfly</code> is now <code>vendor/patternfly-v5</code></p> </li> <li> <p><code>node_modules/rfc4648/lib</code> is now <code>vendor/rfc4648</code></p> </li> </ul> </div> <div class="paragraph"> <p>Additionally, the following resources have been removed from the <code>common</code> theme:</p> </div> <div class="ulist"> <ul> <li> <p><code>node_modules/alpinejs</code></p> </li> <li> <p><code>node_modules/jquery</code></p> </li> </ul> </div> <div class="paragraph"> <p>If you previously used any of the removed resources in your theme, make sure to add them to your own theme resources instead.</p> </div> </div> <div class="sect3"> <h4 id="additional-datasources-now-require-using-xa"><a class="anchor" href="#additional-datasources-now-require-using-xa"></a>Additional datasources now require using XA</h4> <div class="paragraph"> <p>Keycloak by default does not use XA datasources. However, this is considered unsafe if more than one datasource is used. Starting with this release, you need to use XA datasources if you are adding additional datasources to Keycloak. If the default datasource supports XA, you can do this by setting the <code>--transaction-xa-enabled=true</code> option. For additional datasources, you need to use the <code>quarkus.datasource.&lt;your-datasource-name&gt;.jdbc.transactions=xa</code> option in your <code>quarkus.properties</code> file. At most one datasource can be non-XA. Recovery isn&#8217;t supported when you don&#8217;t have persistent storage for the transaction store.</p> </div> </div> <div class="sect3"> <h4 id="hostname-v1-feature-removed"><a class="anchor" href="#hostname-v1-feature-removed"></a>Hostname v1 feature removed</h4> <div class="paragraph"> <p>The deprecated hostname v1 feature was removed. This feature was deprecated in Keycloak 25 and replaced by hostname v2. If you are still using this feature, you must migrate to hostname v2. For more details, see the <a href="https://www.keycloak.org/server/hostname">Configuring the hostname (v2)</a> and <a href="https://www.keycloak.org/docs/latest/upgrading/#new-hostname-options">the initial migration guide</a>.</p> </div> </div> <div class="sect3"> <h4 id="proxy-option-removed"><a class="anchor" href="#proxy-option-removed"></a>Proxy option removed</h4> <div class="paragraph"> <p>The deprecated <code>proxy</code> option was removed. This option was deprecated in Keycloak 24 and replaced by the <code>proxy-headers</code> option in combination with hostname options as needed. For more details, see <a href="https://www.keycloak.org/server/reverseproxy">using a reverse proxy</a> and <a href="https://www.keycloak.org/docs/latest/upgrading/index.html#deprecated-proxy-option">the initial upgrading guide</a>.</p> </div> </div> <div class="sect3"> <h4 id="all-user-sessions-are-persisted-by-default"><a class="anchor" href="#all-user-sessions-are-persisted-by-default"></a>All user sessions are persisted by default</h4> <div class="paragraph"> <p>Since the database is now the source of truth for user sessions, it is possible to restrict the size of the session caches to reduce memory usage. If you use the default <code>conf/cache-ispn.xml</code> file the caches for storing user and client sessions are by default configured to store only 10000 sessions and one owner for each entry.</p> </div> <div class="paragraph"> <p>Update your custom embedded Infinispan cache configuration file with configuration similar to one shown below for caches <code>sessions</code>, <code>clientSessions</code>, <code>offlineSessions</code>, and <code>offlineClientSessions</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre>&lt;distributed-cache name="sessions" owners="1"&gt; &lt;!-- other configuration --&gt; &lt;memory max-count="10000"/&gt; &lt;/distributed-cache&gt;</pre> </div> </div> <div class="paragraph"> <p>For more details proceed to the <a href="https://www.keycloak.org/server/caching">Configuring distributed caches</a> guide.</p> </div> </div> <div class="sect3"> <h4 id="grace-period-for-idle-sessions-removed-when-persistent-sessions-are-enabled"><a class="anchor" href="#grace-period-for-idle-sessions-removed-when-persistent-sessions-are-enabled"></a>Grace period for idle sessions removed when persistent sessions are enabled</h4> <div class="paragraph"> <p>Previous versions of Keycloak added a grace period of two minutes to idle times of user and client sessions. This was added due to a previous architecture where session refresh times were replicated asynchronously in a cluster. With persistent user sessions, this is no longer necessary, and therefore the grace period is now removed.</p> </div> <div class="paragraph"> <p>To keep the old behavior, update your realm configuration and extend the session and client idle times by two minutes.</p> </div> </div> <div class="sect3"> <h4 id="support-for-legacy-redirect_uri-parameter-and-spi-options-has-been-removed"><a class="anchor" href="#support-for-legacy-redirect_uri-parameter-and-spi-options-has-been-removed"></a>Support for legacy <code>redirect_uri</code> parameter and SPI options has been removed</h4> <div class="paragraph"> <p>Previous versions of Keycloak had supported automatic logout of the user and redirecting to the application by opening logout endpoint URL such as <code>http(s)://example-host/auth/realms/my-realm-name/protocol/openid-connect/logout?redirect_uri=encodedRedirectUri</code>. This functionality was deprecated in Keycloak 18 and has been removed in this version in favor of following the OpenID Connect specification.</p> </div> <div class="paragraph"> <p>As part of this change the following related configuration options for the SPI have been removed:</p> </div> <div class="ulist"> <ul> <li> <p><code>--spi-login-protocol-openid-connect-legacy-logout-redirect-uri</code></p> </li> <li> <p><code>--spi-login-protocol-openid-connect-suppress-logout-confirmation-screen</code></p> </li> </ul> </div> <div class="paragraph"> <p>If you were still making use these options or the <code>redirect_uri</code> parameter for logout you should implement the <a href="https://openid.net/specs/openid-connect-rpinitiated-1_0.html">OpenID Connect RP-Initiated Logout specification</a> instead.</p> </div> </div> <div class="sect3"> <h4 id="additional-validations-on-the-optimized-startup-option"><a class="anchor" href="#additional-validations-on-the-optimized-startup-option"></a>Additional validations on the <code>--optimized</code> startup option</h4> <div class="paragraph"> <p>The <code>--optimized</code> startup option now requires the optimized server image to be built first. This can be achieved either by running <code>kc.sh|bat build</code> first or by any other server commands (like <code>start</code>, <code>export</code>, <code>import</code>) without the <code>--optimized</code> flag.</p> </div> </div> <div class="sect3"> <h4 id="adapter-and-misc-bom-files-are-removed"><a class="anchor" href="#adapter-and-misc-bom-files-are-removed"></a>Adapter and misc BOM files are removed</h4> <div class="paragraph"> <p>The <code>org.keycloak.bom:keycloak-adapter-bom</code> and <code>org.keycloak.bom:keycloak-misc-bom</code> BOM files are removed. The adapter BOM was no longer useful because most of the Java adapters are removed. The misc BOM had contained only one artifact, <code>keycloak-test-helper</code>, and that artifact is also removed in this release.</p> </div> </div> <div class="sect3"> <h4 id="keycloak-test-helper-is-removed"><a class="anchor" href="#keycloak-test-helper-is-removed"></a>keycloak-test-helper is removed</h4> <div class="paragraph"> <p>The maven artifact <code>org.keycloak:keycloak-test-helper</code> is removed in this release. The artifact provided a few helper methods for dealing with a Java admin client. If you use the helper methods, it is possible to fork them into your application if needed.</p> </div> </div> <div class="sect3"> <h4 id="jee-admin-client-is-removed"><a class="anchor" href="#jee-admin-client-is-removed"></a>JEE admin-client is removed</h4> <div class="paragraph"> <p>The JEE admin-client is removed in this release. We still keep supporting Jakarta admin-client.</p> </div> </div> <div class="sect3"> <h4 id="new-generalized-event-types-for-credentials"><a class="anchor" href="#new-generalized-event-types-for-credentials"></a>New generalized event types for credentials</h4> <div class="paragraph"> <p>There are now generalized events for updating (<code>UPDATE_CREDENTIAL</code>) and removing (<code>REMOVE_CREDENTIAL</code>) a credential. The credential type is described in the <code>credential_type</code> attribute of the events. The new event types are supported by the Email Event Listener.</p> </div> <div class="paragraph"> <p>The following event types are now deprecated and will be removed in a future version: <code>UPDATE_PASSWORD</code>, <code>UPDATE_PASSWORD_ERROR</code>, <code>UPDATE_TOTP</code>, <code>UPDATE_TOTP_ERROR</code>, <code>REMOVE_TOTP</code>, <code>REMOVE_TOTP_ERROR</code></p> </div> </div> <div class="sect3"> <h4 id="import-realm-option-can-import-the-master-realm"><a class="anchor" href="#import-realm-option-can-import-the-master-realm"></a><code>--import-realm</code> option can import the master realm</h4> <div class="paragraph"> <p>When running a <code>start</code> or <code>start-dev</code> command with the <code>--import-realm</code> option before the master realm exists, it will be imported if it exists in the import material. The previous behavior was that the master realm was created first, then its import skipped.</p> </div> </div> <div class="sect3"> <h4 id="bouncycastle-fips-updated"><a class="anchor" href="#bouncycastle-fips-updated"></a>BouncyCastle FIPS updated</h4> <div class="paragraph"> <p>Our FIPS 140-2 integration is now tested and supported with version 2 of BouncyCastle FIPS libraries. This version is certified with Java 21. If you use FIPS 140-2 integration, it is recommended to upgrade BouncyCastle FIPS library to the versions mentioned in the latest documentation.</p> </div> <div class="paragraph"> <p>The BouncyCastle FIPS version 2 is certified with FIPS 140-3. So Keycloak can be FIPS 140-3 compliant as long as it is used on the FIPS 140-3 compliant system. This might be the RHEL 9 based system, which itself is compliant with the FIPS 140-3. But note that RHEL 8 based system is only certified for the FIPS 140-2.</p> </div> </div> <div class="sect3"> <h4 id="setorcreatechild-method-removed-from-javascript-admin-client"><a class="anchor" href="#setorcreatechild-method-removed-from-javascript-admin-client"></a><code>setOrCreateChild()</code> method removed from JavaScript Admin Client</h4> <div class="paragraph"> <p>The <code>groups.setOrCreateChild()</code> method has been removed from that JavaScript-based Admin Client. If you are still using this method then use the <code>createChildGroup()</code> or <code>updateChildGroup()</code> methods instead.</p> </div> </div> <div class="sect3"> <h4 id="keycloak-js"><a class="anchor" href="#keycloak-js"></a>Keycloak JS</h4> <div class="paragraph"> <p>This release includes several changes to Keycloak JS library that should be taken into account. The main motivation for these changes is to de-couple the library from the Keycloak server, so that it can be refactored independently, simplifing the code and making it easier to maintain in the future. The changes are as follows:</p> </div> <div class="sect4"> <h5 id="the-library-is-no-longer-served-statically-from-the-server"><a class="anchor" href="#the-library-is-no-longer-served-statically-from-the-server"></a>The library is no longer served statically from the server</h5> <div class="paragraph"> <p>The Keycloak JS library is no longer served statically from the Keycloak server. This means that the following URLs are no longer available:</p> </div> <div class="ulist"> <ul> <li> <p><code>/js/keycloak-authz.js</code></p> </li> <li> <p><code>/js/keycloak-authz.min.js</code></p> </li> <li> <p><code>/js/keycloak.js</code></p> </li> <li> <p><code>/js/keycloak.min.js</code></p> </li> <li> <p><code>/js/{version}/keycloak-authz.js</code></p> </li> <li> <p><code>/js/{version}/keycloak-authz.min.js</code></p> </li> <li> <p><code>/js/{version}/keycloak.js</code></p> </li> <li> <p><code>/js/{version}/keycloak.min.js</code></p> </li> </ul> </div> <div class="paragraph"> <p>Additionally, the <code>keycloakJsUrl</code> property that linked to the library on these URLs has been removed from the the admin console theme. If your custom theme was using this property to include the library, you should update your theme to include the library using a different method.</p> </div> <div class="paragraph"> <p>If you are not already you should include the library in your project using a package manager like <a href="https://nodejs.org/en/learn/getting-started/an-introduction-to-the-npm-package-manager">NPM</a>. The library is available on the NPM registry as <a href="https://www.npmjs.com/package/keycloak-js"><code>keycloak-js</code></a>. You can install it using the following command:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">npm install keycloak-js</code></pre> </div> </div> <div class="paragraph"> <p>Alternatively, the distribution of the server includes a copy of the library in the <code>keycloak-js-26.0.0.tgz</code> archive. You can copy the library from there into your project. If you are using the library directly in the browser without a build, you&#8217;ll need to host the library yourself. A package manager is still the recommended way to include the library in your project, as it will make it easier to update the library in the future.</p> </div> </div> <div class="sect4"> <h5 id="support-for-the-umd-distribution-has-been-removed"><a class="anchor" href="#support-for-the-umd-distribution-has-been-removed"></a>Support for the UMD distribution has been removed</h5> <div class="paragraph"> <p>The UMD distribution <a href="https://github.com/umdjs/umd?tab=readme-ov-file#umd-universal-module-definition">Universal Module Definition</a> of the Keycloak JS library has been removed. This means that the library is no longer exposed as a global variable, and instead must be imported as <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules">a module</a>. This change is in line with modern JavaScript development practices, and allows for a more consitent experience between browsers and build tooling, and generally results in more predictable code with less side-effects.</p> </div> <div class="paragraph"> <p>If you are using a bundler like Vite or Webpack nothing changes, you&#8217;ll have the same experience as before. If you are using the library directly in the browser, you&#8217;ll need to update your code to import the library as a module:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="html"><span class="comment">&lt;!-- Before --&gt;</span> <span class="tag">&lt;script</span> <span class="attribute-name">src</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">/path/to/keycloak.js</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span><span class="tag">&lt;/script&gt;</span> <span class="tag">&lt;script&gt;</span> <span class="inline"> const keycloak = <span class="keyword">new</span> Keycloak();</span> <span class="tag">&lt;/script&gt;</span> <span class="comment">&lt;!-- After --&gt;</span> <span class="tag">&lt;script</span> <span class="attribute-name">type</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">module</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span> <span class="inline"> <span class="reserved">import</span> Keycloak from <span class="string"><span class="delimiter">'</span><span class="content">/path/to/keycloak.js</span><span class="delimiter">'</span></span>; const keycloak = <span class="keyword">new</span> Keycloak();</span> <span class="tag">&lt;/script&gt;</span></code></pre> </div> </div> <div class="paragraph"> <p>You can also opt to use an <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap">import map</a> make the import of the library less verbose:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="html"><span class="tag">&lt;script</span> <span class="attribute-name">type</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">importmap</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span> <span class="inline"> { <span class="key"><span class="delimiter">&quot;</span><span class="content">imports</span><span class="delimiter">&quot;</span></span>: { <span class="key"><span class="delimiter">&quot;</span><span class="content">keycloak-js</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">/path/to/keycloak.js</span><span class="delimiter">&quot;</span></span> } }</span> <span class="tag">&lt;/script&gt;</span> <span class="tag">&lt;script</span> <span class="attribute-name">type</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">module</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span> <span class="inline"> <span class="comment">// The library can now be imported without specifying the full path, providing a similar experience as with a bundler.</span> <span class="reserved">import</span> Keycloak from <span class="string"><span class="delimiter">'</span><span class="content">keycloak-js</span><span class="delimiter">'</span></span>; const keycloak = <span class="keyword">new</span> Keycloak();</span> <span class="tag">&lt;/script&gt;</span></code></pre> </div> </div> <div class="paragraph"> <p>If you are using TypeScript you may need to update your <code>tsconfig.json</code> to be able to resolve the library:</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">compilerOptions</span><span class="delimiter">&quot;</span></span>: { <span class="key"><span class="delimiter">&quot;</span><span class="content">moduleResolution</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">Bundler</span><span class="delimiter">&quot;</span></span> } }</code></pre> </div> </div> </div> <div class="sect4"> <h5 id="the-configuration-for-the-keycloak-instance-is-now-required"><a class="anchor" href="#the-configuration-for-the-keycloak-instance-is-now-required"></a>The configuration for the <code>Keycloak</code> instance is now required</h5> <div class="paragraph"> <p>Previously it was possible to construct a <code>Keycloak</code> instance without passing any configuration. The configuration would then automatically be loaded from the server from a <code>keycloak.json</code> file based on the path of the included <code>keycloak.js</code> script. Since the library is no longer statically served from the server this feature has been removed. You now need to pass the configuration explicitly when constructing a <code>Keycloak</code> instance:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="javascript"><span class="comment">// Before</span> const keycloak = <span class="keyword">new</span> Keycloak(); <span class="comment">// After</span> 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> }); <span class="comment">// Alternatively, you can pass a URL to a `keycloak.json` file.</span> <span class="comment">// Note this is not reccomended as it creates additional network requests, and is prone to change in the future.</span> const keycloak = <span class="keyword">new</span> Keycloak(<span class="string"><span class="delimiter">'</span><span class="content">http://keycloak-server/path/to/keycloak.json</span><span class="delimiter">'</span></span>);</code></pre> </div> </div> </div> <div class="sect4"> <h5 id="methods-for-login-are-now-async"><a class="anchor" href="#methods-for-login-are-now-async"></a>Methods for login are now <code>async</code></h5> <div class="paragraph"> <p>Keycloak JS now utilizes the Web Crypto API for various cryptographic functions. Due to the asynchronous nature of this API the following public methods will now always return a <code>Promise</code>:</p> </div> <div class="ulist"> <ul> <li> <p><code>login()</code></p> </li> <li> <p><code>createLoginUrl()</code></p> </li> <li> <p><code>createRegisterUrl()</code></p> </li> </ul> </div> <div class="paragraph"> <p>Make sure to update your code to <code>await</code> these methods:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="javascript"><span class="comment">// Before</span> keycloak.login(); const loginUrl = keycloak.createLoginUrl(); const registerUrl = keycloak.createRegisterUrl(); <span class="comment">// After</span> await keycloak.login(); const loginUrl = await keycloak.createLoginUrl(); const registerUrl = await keycloak.createRegisterUrl();</code></pre> </div> </div> <div class="paragraph"> <p>Make sure to update your code to <code>await</code> these methods.</p> </div> </div> <div class="sect4"> <h5 id="a-secure-context-is-now-required"><a class="anchor" href="#a-secure-context-is-now-required"></a>A secure context is now required</h5> <div class="paragraph"> <p>Keycloak JS now requires a <a href="https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts">secure context</a> to run. The reason for this is that the library now uses the Web Crypto API for various cryptographic functions. This API is only available in secure contexts, which are contexts that are served over HTTPS, <code>localhost</code> or a <code>.localhost</code> domain. If you are using the library in a non-secure context you&#8217;ll need to update your development environment to use a secure context.</p> </div> </div> </div> <div class="sect3"> <h4 id="stricter-startup-behavior-for-build-time-options"><a class="anchor" href="#stricter-startup-behavior-for-build-time-options"></a>Stricter startup behavior for build-time options</h4> <div class="paragraph"> <p>When the provided build-time options differ at startup from the values persisted in the server image during the last optimized Keycloak build, Keycloak will now fail to start. Previously, a warning message was displayed in such cases.</p> </div> </div> <div class="sect3"> <h4 id="features-renamed"><a class="anchor" href="#features-renamed"></a>Features renamed</h4> <div class="paragraph"> <p>With feature versions the features <code>account3</code>, <code>admin2</code>, and <code>login2</code> have been renamed. When disabling a feature there is no need to use the version, for example the admin console is now disabled with <code>--features-disabled=admin</code>.</p> </div> <div class="paragraph"> <p>To use a specific version of <code>login</code> use <code>--features=login:v1</code>.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-25-0-3"><a class="anchor" href="#migrating-to-25-0-3"></a>Migrating to 25.0.3</h3> <div class="sect3"> <h4 id="concurrent-login-requests-are-blocked-by-default-when-brute-force-is-enabled"><a class="anchor" href="#concurrent-login-requests-are-blocked-by-default-when-brute-force-is-enabled"></a>Concurrent login requests are blocked by default when brute force is enabled</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/changes/changes-25_0_3.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/changes/changes-25_0_3.adoc&amp;description=%0A%0AFile:%20upgrading/topics/changes/changes-25_0_3.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 an attacker launched many login attempts in parallel then the attacker could have more guesses at a password than the brute force protection configuration permits. This was due to the brute force check occurring before the brute force protector has locked the user. To prevent this race the Brute Force Protector now rejects all login attempts that occur while another login is in progress in the same server.</p> </div> <div class="paragraph"> <p>If, for whatever reason, the new feature wants to be disabled there is a startup factory option:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">bin/kc.[sh|bat] start --spi-brute-force-protector-default-brute-force-detector-allow-concurrent-requests=true</code></pre> </div> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-25-0-2"><a class="anchor" href="#migrating-to-25-0-2"></a>Migrating to 25.0.2</h3> <div class="sect3"> <h4 id="improving-performance-for-deletion-of-user-consents"><a class="anchor" href="#improving-performance-for-deletion-of-user-consents"></a>Improving performance for deletion of user consents</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/changes/changes-25_0_2.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/changes/changes-25_0_2.adoc&amp;description=%0A%0AFile:%20upgrading/topics/changes/changes-25_0_2.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 client scope or the full realm are deleted the associated user consents should also be removed. A new index over the table <code>USER_CONSENT_CLIENT_SCOPE</code> has been added to increase the performance.</p> </div> <div class="paragraph"> <p>Note that, if the table contains more than 300.000 entries, by default Keycloak skips the creation of the indexes during the automatic schema migration and logs the SQL statements to the console instead. The statements must be run manually in the DB after Keycloak&#8217;s startup. Check the <a href="https://www.keycloak.org/docs/26.0.6/upgrading/">Upgrading Guide</a> for details on how to configure a different limit.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-25-0-0"><a class="anchor" href="#migrating-to-25-0-0"></a>Migrating to 25.0.0</h3> <div class="sect3"> <h4 id="new-hostname-options"><a class="anchor" href="#new-hostname-options"></a>New Hostname options</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/changes/changes-25_0_0.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/changes/changes-25_0_0.adoc&amp;description=%0A%0AFile:%20upgrading/topics/changes/changes-25_0_0.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>Hostname v2 options are supported by default, as the old hostname options are deprecated and will be removed in the following releases. New options are activated by default, so Keycloak will not recognize the old options.</p> </div> <div class="paragraph"> <p>List of necessary migrations:</p> </div> <table class="tableblock frame-all grid-all fit-content"> <colgroup> <col> <col> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Old options</th> <th class="tableblock halign-left valign-top">New options</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>hostname &lt;hostname&gt;</code><br> <code>hostname-url &lt;url&gt;</code><br> <code>hostname-path &lt;path&gt;</code><br> <code>hostname-port &lt;port&gt;</code></p> </div></div></td> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>hostname &lt;hostname/url&gt;</code></p> </div></div></td> </tr> <tr> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>hostname-admin &lt;hostname&gt;</code><br> <code>hostname-admin-url &lt;url&gt;</code></p> </div></div></td> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>hostname-admin &lt;url&gt;</code></p> </div></div></td> </tr> <tr> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>hostname-strict-backchannel &lt;true/false&gt;</code></p> </div></div></td> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>hostname-backchannel-dynamic &lt;true/false&gt;</code></p> </div></div></td> </tr> </tbody> </table> <div class="paragraph"> <p>As you can see, the <code>*-url</code> suffixes were removed for <code>hostname</code> and <code>hostname-admin</code> options. Option <code>hostname</code> accepts both hostname and URL, but <code>hostname-admin</code> accepts only full URL now.</p> </div> <div class="paragraph"> <p>Additionally, there is no way to set <code>path</code> or <code>port</code> separately. You can achieve it by providing the full URL for the <code>hostname</code> and <code>hostname-admin</code> options.</p> </div> <div class="paragraph"> <p>If the port is not part of the URL, it is dynamically resolved from the incoming request headers.</p> </div> <div class="paragraph"> <p>HTTPS is no longer enforced unless it is part of <code>hostname</code> and <code>hostname-admin</code> URLs. If not specified, the used protocol (<code>http/https</code>) is dynamically resolved from the incoming request. The <code>hostname-strict-https</code> option is removed.</p> </div> <table class="tableblock frame-all grid-all fit-content"> <colgroup> <col> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Removed options</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>hostname-url</code></p> </div></div></td> </tr> <tr> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>hostname-admin-url</code></p> </div></div></td> </tr> <tr> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>hostname-path</code></p> </div></div></td> </tr> <tr> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>hostname-port</code></p> </div></div></td> </tr> <tr> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>hostname-strict-backchannel</code></p> </div></div></td> </tr> <tr> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>hostname-strict-https</code></p> </div></div></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"> In order to use the old hostname options to have more time for migration, turn on the feature <code>hostname:v1</code>, e.g. <code>features=hostname:v1</code>. Be aware, that either <code>hostname:v1</code> or <code>hostname:v2</code> can be enabled, not both at the same time. </td> </tr> </table> </div> <div class="sect4"> <h5 id="examples"><a class="anchor" href="#examples"></a>Examples</h5> <div class="listingblock"> <div class="title">Simplified notation</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash"># Hostname v1 bin/kc.[sh|bat] start --hostname=mykeycloak.org --https-port=8543 --hostname-path=/auth --hostname-strict-https=true # Hostname v2 bin/kc.[sh|bat] start --hostname=https://mykeycloak.org:8543/auth</code></pre> </div> </div> <div class="paragraph"> <p>As you can see in the example, all the parts of a URL can be now specified via single <code>hostname</code> option, which simplifies the hostname setup process. Notice that HTTPS is not enforced by the <code>hostname-strict-https</code> option, but by specifying it in the hostname URL.</p> </div> <div class="listingblock"> <div class="title">Backchannel setting</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash"># Hostname v1 bin/kc.[sh|bat] start --hostname=mykeycloak.org --hostname-strict-backchannel=true # Hostname v2 bin/kc.[sh|bat] start --hostname=mykeycloak.org --hostname-backchannel-dynamic=false</code></pre> </div> </div> <div class="paragraph"> <p>Be aware that there is a change in behavior if the same URL is to be used for both backend and frontend endpoints. Previously, in hostname v1, the backchannel URL was dynamically resolved from request headers. Therefore, to achieve the required results, you had to specify the <code>hostname-strict-backchannel=true</code>.</p> </div> <div class="paragraph"> <p>For hostname v2, the backchannel URLs are already the same as the frontend ones. In order to dynamically resolve it from request headers, you need to set the <code>hostname-backchannel-dynamic=true</code> and provide a full URL for the <code>hostname</code> option.</p> </div> <div class="paragraph"> <p>For more details and more comprehensive scenarios, see <a href="https://www.keycloak.org/server/hostname">Configuring the hostname (v2)</a>.</p> </div> </div> <div class="sect4"> <h5 id="security-admin-console-client-redirect-uris"><a class="anchor" href="#security-admin-console-client-redirect-uris"></a><code>security-admin-console</code> Client Redirect URIs</h5> <div class="paragraph"> <p>The handling of the <code>${authAdminUrl}</code> has changed in hostname v1. Previously with hostname v1 the admin URL was resolved dynamically from the request if the <code>hostname-admin</code> or <code>hostname-admin-url</code> options were not set. With hostname v2 the admin URL will default instead to the frontend URL. If the <code>hostname</code> option is set and <code>hostname-strict</code> is true, this change will prevent redirect URIs with alternative hostnames from working for Clients using the Root URL <code>${authAdminUrl}</code>. You should consider using the <code>hostname-admin</code> option instead of the redirect URIs to allow a single alternative hostname. Alternative hostname redirects should be removed as the <code>security-admin-console</code> Client only needs the default redirect URI of <code>/admin/master/console/*</code> with Root URL of <code>${authAdminUrl}</code>.</p> </div> </div> </div> <div class="sect3"> <h4 id="persistent-user-sessions"><a class="anchor" href="#persistent-user-sessions"></a>Persistent user sessions</h4> <div class="paragraph"> <p>Previous versions of Keycloak stored only offline user and offline client sessions in the databases. The new feature <code>persistent-user-sessions</code> stores online user sessions and online client sessions not only in memory, but also in the database. This will allow a user to stay logged in even if all instances of Keycloak are restarted or upgraded.</p> </div> <div class="sect4"> <h5 id="enabling-persistent-user-sessions"><a class="anchor" href="#enabling-persistent-user-sessions"></a>Enabling persistent user sessions</h5> <div class="paragraph"> <p>The feature is a preview feature and disabled by default. To use it, add the following to your build command:</p> </div> <div class="listingblock"> <div class="content"> <pre>bin/kc.sh build --features=persistent-user-sessions ...</pre> </div> </div> <div class="paragraph"> <p>For more details see the <a href="https://www.keycloak.org/server/features">Enabling and disabling features</a> guide. The <a href="https://www.keycloak.org/high-availability/concepts-memory-and-cpu-sizing">sizing guide</a> contains a new paragraph describing the updated resource requirements when this feature is enabled.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> If this feature is enabled for an existing deployment that is using only the embedded Infinispan for storing sessions, the existing online user and client sessions will not be migrated to the database. It will only affect newly created online user and online client sessions. </td> </tr> </table> </div> <div class="paragraph"> <p>With persistent sessions enabled, the in-memory caches for online user sessions, offline user sessions, online client sessions and offline client sessions are limited to 10000 entries per node by default which will reduce the overall memory usage of Keycloak for larger installations. 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. Once this feature is enabled, expect an increased database utilization on each login, logout and refresh token request.</p> </div> <div class="paragraph"> <p>To configure the cache size in an external Infinispan in a Keycloak multi-site setup, consult the updated <a href="https://www.keycloak.org/high-availability/deploy-infinispan-kubernetes-crossdc">Deploy Infinispan for HA with the Infinispan Operator</a> guide.</p> </div> <div class="paragraph"> <p>With this feature enabled, the options <code>spi-user-sessions-infinispan-offline-session-cache-entry-lifespan-override</code> and <code>spi-user-sessions-infinispan-offline-client-session-cache-entry-lifespan-override</code> are no longer available, as they were previously used to override the time offline sessions were kept in-memory.</p> </div> </div> <div class="sect4"> <h5 id="migrating-user-sessions-during-the-upgrade"><a class="anchor" href="#migrating-user-sessions-during-the-upgrade"></a>Migrating user sessions during the upgrade</h5> <div class="paragraph"> <p>When upgrading from Keycloak 24 or earlier, admins can choose to migrate existing online user and client sessions to persistent sessions. For this to work, those existing sessions need to be stored in either a remote Infinispan or in a database configured as JDBC persistence for Keycloak&#8217;s embedded cache. Migrating in-memory sessions for Keycloak 24 is not supported as all Keycloak instances need to be shut down before the upgrade due to a major version upgrade of the embedded Infinispan.</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>The migration of user sessions only works when the persistent user sessions is enabled when upgrading to Keycloak 25. If you chose to upgrade to 25 without enabling persistent user sessions, there is currently no possibility to trigger the migration of existing sessions at a later point in time.</p> </div> <div class="paragraph"> <p>Enabling this feature later, by a configuration change, can result in an undefined behavior of Keycloak related to sessions if both persisted and non-persisted sessions co-exist. To prevent that, remove all existing online user and client sessions before the first node is started with the feature enabled. This means all Keycloak nodes need to be stopped and, if used, Infinispan remote cache store and embedded Infinispan JDBC persistence need to be cleared.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>To migrate the user sessions during an upgrade of Keycloak, perform the following steps:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Stop all running old instances of Keycloak.</p> </li> <li> <p>Create backups:</p> <div class="openblock"> <div class="content"> <div class="ulist"> <ul> <li> <p>Create a backup Keycloak&#8217;s database.</p> </li> <li> <p>If JDBC persistence is used, create a backup of that database if you want to be able to retry the migration of the sessions.</p> </li> <li> <p>If an external Infinispan is used, create a backup of its data if you want to be able to retry the migration of the sessions.</p> </li> </ul> </div> </div> </div> </li> <li> <p>Start the new instances Keycloak with the persistent user sessions feature enabled.</p> <div class="paragraph"> <p>The first starting node will:</p> </div> <div class="openblock"> <div class="content"> <div class="olist arabic"> <ol class="arabic"> <li> <p>Migrate the database to the schema version 25.</p> </li> <li> <p>Copy all session information from either the remote Infinispan or the JDBC persistence configured for Keycloak&#8217;s embedded cache to the database of Keycloak.</p> <div class="paragraph"> <p>The data will be stored in the tables <code>offline_user_session</code> and <code>offline_client_session</code> with <code>offline_flag</code> set to <code>false</code>.</p> </div> </li> <li> <p>Clear the caches.</p> <div class="paragraph"> <p>This includes clearing the caches of the external Infinispan if one is used, and clearing the JDBC persistence if one is used.</p> </div> </li> </ol> </div> </div> </div> </li> <li> <p>Update the cache configuration XML of Keycloak for caches <code>sessions</code> and <code>clientSessions</code>:</p> <div class="openblock"> <div class="content"> <div class="ulist"> <ul> <li> <p>If JDBC persistence is used, remove the configuration for JDBC persistence.</p> </li> <li> <p>If the remote Infinispan has been used in a single-site setup solely for keeping user sessions across Keycloak restarts, remove the remote Infinispan configuration for those caches.</p> </li> </ul> </div> </div> </div> <div class="admonitionblock tip"> <table> <tr> <td class="icon"> <i class="fa icon-tip" title="Tip"></i> </td> <td class="content"> If the remote Infinispan is used in a multi-site setup, you can reduce the resource consumption by the external Infinispan by configuring the number of entries in memory. Use the settings outlined in <a href="https://www.keycloak.org/high-availability/deploy-infinispan-kubernetes-crossdc">Deploy Infinispan for HA with the Infinispan Operator</a> guide. </td> </tr> </table> </div> </li> <li> <p>Rolling restart of Keycloak to activate the new cache configuration XML.</p> </li> </ol> </div> </div> <div class="sect4"> <h5 id="signing-out-existing-users"><a class="anchor" href="#signing-out-existing-users"></a>Signing out existing users</h5> <div class="paragraph"> <p>In previous versions and when the feature is disabled, a restart of all Keycloak nodes logged out all users. To sign out all online users sessions of a realm with the <code>persistent-user-sessions</code> feature enabled, use the following steps as before:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Log in to the Admin Console.</p> </li> <li> <p>Select the menu entry <strong>Sessions</strong>.</p> </li> <li> <p>Select the action <strong>Sign out all active sessions</strong>.</p> </li> </ol> </div> </div> </div> <div class="sect3"> <h4 id="metrics-for-embedded-caches-enabled-by-default"><a class="anchor" href="#metrics-for-embedded-caches-enabled-by-default"></a>Metrics for embedded caches enabled by default</h4> <div class="paragraph"> <p>Metrics for the embedded caches are now enabled by default. To enable histograms for latencies, set the option <code>cache-metrics-histograms-enabled</code> to <code>true</code>.</p> </div> </div> <div class="sect3"> <h4 id="metrics-for-http-endpoints-enabled-by-default"><a class="anchor" href="#metrics-for-http-endpoints-enabled-by-default"></a>Metrics for HTTP endpoints enabled by default</h4> <div class="paragraph"> <p>The metrics provided by Keycloak now include HTTP server metrics starting with <code>http_server</code>. See below for some examples.</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>http_server_active_requests 1.0 http_server_requests_seconds_count{method="GET",outcome="SUCCESS",status="200",uri="/realms/{realm}/protocol/{protocol}/auth"} 1.0 http_server_requests_seconds_sum{method="GET",outcome="SUCCESS",status="200",uri="/realms/{realm}/protocol/{protocol}/auth"} 0.048717142</code></pre> </div> </div> <div class="paragraph"> <p>Use the new options <code>http-metrics-histograms-enabled</code> and <code>http-metrics-slos</code> to enable default histogram buckets or specific buckets for service level objectives (SLOs). Read more about histograms in the <a href="https://prometheus.io/docs/concepts/metric_types/#histogram">Prometheus documentation about histograms</a> on how to use the additional metrics series provided in <code>http_server_requests_seconds_bucket</code>.</p> </div> </div> <div class="sect3"> <h4 id="argon2-password-hashing"><a class="anchor" href="#argon2-password-hashing"></a>Argon2 password hashing</h4> <div class="paragraph"> <p>In Keycloak 24 release, we had a change in the password hashing algorithm which resulted in an increased CPU usage. To address that, we opted to a different default hashing algorithm Argon2 for non-FIPS environments which brings the CPU usage back to where it was prior to the Keycloak 24 release.</p> </div> <div class="sect4"> <h5 id="expected-improvement-in-overall-cpu-usage-and-temporary-increased-database-activity"><a class="anchor" href="#expected-improvement-in-overall-cpu-usage-and-temporary-increased-database-activity"></a>Expected improvement in overall CPU usage and temporary increased database activity</h5> <div class="paragraph"> <p>The Concepts for sizing CPU and memory resources in the Keycloak High Availability guide have been updated to reflect the new hashing defaults.</p> </div> <div class="paragraph"> <p>After the upgrade, during a password-based login, the user&#8217;s passwords will be re-hashed with the new hash algorithm and hash iterations as a one-off activity and updated in the database. As this clears the user from Keycloak&#8217;s internal cache, you&#8217;ll also see an increased read activity on the database level. This increased database activity will decrease over time as more and more user&#8217;s passwords have been re-hashed.</p> </div> </div> <div class="sect4"> <h5 id="updated-jvm-garbage-collection-settings"><a class="anchor" href="#updated-jvm-garbage-collection-settings"></a>Updated JVM garbage collection settings</h5> <div class="paragraph"> <p>To support the memory intensive nature of Argon2, we have updated the default GC from ParallelGC to G1GC for a better heap utilization. Please monitor the JVM heap utilization closely after this upgrade. Additional tuning may be necessary depending on your specific workload.</p> </div> </div> </div> <div class="sect3"> <h4 id="limiting-memory-usage-when-consuming-http-responses"><a class="anchor" href="#limiting-memory-usage-when-consuming-http-responses"></a>Limiting memory usage when consuming HTTP responses</h4> <div class="paragraph"> <p>In some scenarios like brokering Keycloak uses HTTP to talk to external servers. To avoid a denial of service when those providers send too much data, Keycloak now restricts responses to 10 MB by default.</p> </div> <div class="paragraph"> <p>Users can configure this limit by setting the provider configuration option <code>spi-connections-http-client-default-max-consumed-response-size</code>:</p> </div> <div class="listingblock"> <div class="title">Restricting the consumed responses to 1 MB</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">bin/kc.[sh|bat] --spi-connections-http-client-default-max-consumed-response-size=1000000</code></pre> </div> </div> </div> <div class="sect3"> <h4 id="hostname-verification-policy"><a class="anchor" href="#hostname-verification-policy"></a>Hostname Verification Policy</h4> <div class="paragraph"> <p>The default for <code>spi-truststore-file-hostname-verification-policy</code> and the new <code>tls-hostname-verifier</code> option is now DEFAULT, rather than WILDCARD. The WILDCARD and STRICT option values have been deprecated - you should simply rely upon DEFAULT instead.</p> </div> <div class="paragraph"> <p>Behavior supported by WILDCARD, that is not supported by DEFAULT: * allows wildcards in subdomain names (e.g. *.foo.com) to match anything, including multiple levels (e.g. a.b.foo.com). * allows matching against well known public suffixes - e.g. foo.co.gl may match *.co.gl</p> </div> <div class="paragraph"> <p>Behavior supported by STRICT, that is not supported by DEFAULT: * STRICT uses a small exclusion list for 2 or 3 letter domain names ending in a 2 letter top level (*.XXX.YY) when determining if a wildcard matches. Instead DEFAULT uses a more complete list of public suffix rules and exclusions from <a href="https://publicsuffix.org/list/" class="bare">https://publicsuffix.org/list/</a></p> </div> <div class="paragraph"> <p>It is not expected that you should be relying upon these behaviors from the WILDCARD or STRICT options.</p> </div> </div> <div class="sect3"> <h4 id="addressed-you-are-already-logged-in-for-expired-authentication-sessions"><a class="anchor" href="#addressed-you-are-already-logged-in-for-expired-authentication-sessions"></a>Addressed 'You are already logged in' for expired authentication sessions</h4> <div class="paragraph"> <p>Keycloak now does not display the message <em>You are already logged in</em> to the end user when an authentication session expires and user is already logged-in. Instead it redirects the error about the expired authentication session to the client application, so the client can act on it and restart authentication as described in the <a href="https://www.keycloak.org/docs/26.0.6/server_admin/#_authentication-sessions">Server Administration Guide authentication sessions chapter</a>. You may consider updating your applications to being able to handle this error.</p> </div> </div> <div class="sect3"> <h4 id="removed-a-model-module"><a class="anchor" href="#removed-a-model-module"></a>Removed a model module</h4> <div class="paragraph"> <p>The module <code>org.keycloak:keycloak-model-legacy</code> module was deprecated in a previous release and is removed in this release. Use the <code>org.keycloak:keycloak-model-storage</code> module instead.</p> </div> </div> <div class="sect3"> <h4 id="xa-transaction-changes"><a class="anchor" href="#xa-transaction-changes"></a>XA Transaction Changes</h4> <div class="ulist"> <ul> <li> <p>The option <code>transaction-xa-enabled</code> will default to false, rather than true. If you want XA transaction support you will now need to explicitly set this option to true.</p> </li> <li> <p>XA Transaction recovery support is enabled by default. Transaction logs will be stored at KEYCLOAK_HOME/data/transaction-logs.</p> </li> </ul> </div> </div> <div class="sect3"> <h4 id="removed-offline-session-preloading"><a class="anchor" href="#removed-offline-session-preloading"></a>Removed offline session preloading</h4> <div class="paragraph"> <p>The old behavior to preload offline sessions at startup is now removed after it has been deprecated in the previous release.</p> </div> </div> <div class="sect3"> <h4 id="specify-cache-options-at-runtime"><a class="anchor" href="#specify-cache-options-at-runtime"></a>Specify <code>cache</code> options at runtime</h4> <div class="paragraph"> <p>Options <code>cache</code>, <code>cache-stack</code>, and <code>cache-config-file</code> are no longer build options, and they can be specified only during runtime. This eliminates the need to execute the build phase and rebuild your image due to them. Be aware that they will not be recognized during the <code>build</code> phase, so you need to remove them.</p> </div> </div> <div class="sect3"> <h4 id="kcadm-and-kcreg-changes"><a class="anchor" href="#kcadm-and-kcreg-changes"></a>kcadm and kcreg changes</h4> <div class="paragraph"> <p>How kcadm and kcreg parse and handle options and parameters has changed. Error messages from usage errors, the wrong option or parameter, may be slightly different than previous versions. Also usage errors will have an exit code of 2 instead of 1.</p> </div> </div> <div class="sect3"> <h4 id="removing-custom-user-attribute-indexes"><a class="anchor" href="#removing-custom-user-attribute-indexes"></a>Removing custom user attribute indexes</h4> <div class="paragraph"> <p>When searching for users by user attribute, Keycloak no longer searches for user attribute names forcing lower case comparisons. This means Keycloak&#8217;s native index on the user attribute table will now be used when searching. If you have created your own index based on `lower(name)`to speed up searches, you can now remove it.</p> </div> </div> <div class="sect3"> <h4 id="new-default-client-scope-basic"><a class="anchor" href="#new-default-client-scope-basic"></a>New default client scope <code>basic</code></h4> <div class="paragraph"> <p>The new client scope named <code>basic</code> is added as a realm "default" client scope and hence will be added to all newly created OIDC clients. The client scope is also automatically added to all existing OIDC clients during migration.</p> </div> <div class="paragraph"> <p>This scope contains preconfigured protocol mappers for the following claims:</p> </div> <div class="ulist"> <ul> <li> <p><code>sub</code> (See the details below in the dedicated section)</p> </li> <li> <p><code>auth_time</code></p> </li> </ul> </div> <div class="paragraph"> <p>This provides additional help to reduce the number of claims in a lightweight access token, but also gives the chance to configure claims that were always added automatically.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> In case you already have client scope named <code>basic</code> in some of your realms, then the new client scope <code>basic</code> will not be added to your realm and will not be added to any clients. The migration would be ignored for this particular case. In that case, you either need to make sure to rename your client scope to something different than <code>basic</code> before you migrate to this Keycloak version or you need to manually deal with missing <code>sub</code> and <code>auth_time</code> claims in case you need them in your tokens and you may need to manually add corresponding protocol mappers to some of your client scopes. </td> </tr> </table> </div> </div> <div class="sect3"> <h4 id="removed-session_state-claim"><a class="anchor" href="#removed-session_state-claim"></a>Removed <code>session_state</code> claim</h4> <div class="paragraph"> <p>The <code>session_state</code> claim, which contains the same value as the <code>sid</code> claim, is now removed from all tokens as it is not required according to the OpenID Connect Front-Channel Logout and OpenID Connect Back-Channel Logout specifications. The <code>session_state</code> claim remains present in the Access Token Response in accordance with OpenID Connect Session Management specification.</p> </div> <div class="paragraph"> <p>Note that the <code>setSessionState()</code> method is also removed from the <code>IDToken</code> class in favor of the <code>setSessionId()</code> method, and the <code>getSessionState()</code> method is now deprecated.</p> </div> <div class="paragraph"> <p>A new <code>Session State (session_state)</code> mapper is also included and can be assigned to client scopes (for instance <code>basic</code> client scope) to revert to the old behavior.</p> </div> <div class="paragraph"> <p>If an old version of the JS adapter is used, the <code>Session State (session_state)</code> mapper should also be used by using client scopes as described above.</p> </div> </div> <div class="sect3"> <h4 id="sub-claim-is-added-to-access-token-via-protocol-mapper"><a class="anchor" href="#sub-claim-is-added-to-access-token-via-protocol-mapper"></a><code>sub</code> claim is added to access token via protocol mapper</h4> <div class="paragraph"> <p>The <code>sub</code> claim, which was always added to the access token, is now added by default but using a new <code>Subject (sub)</code> protocol mapper.</p> </div> <div class="paragraph"> <p>The <code>Subject (sub)</code> mapper is configured by default in the <code>basic</code> client scope. Therefore, no extra configuration is required after upgrading to this version.</p> </div> <div class="paragraph"> <p>If you are using the <code>Pairwise subject identifier</code> mapper to map a <code>sub</code> claim for an access token, you can consider disabling or removing the <code>Subject (sub)</code> mapper, however it is not strictly needed as the <code>Subject (sub)</code> protocol mapper is executed before the <code>Pairwise subject identifier</code> mapper and hence the <code>pairwise</code> value will override the value added by <code>Subject (sub)</code> mapper. This may apply also to other custom protocol mapper implementations, which override the <code>sub</code> claim, as the <code>Subject (sub)</code> mapper is currently executed as first protocol mapper.</p> </div> <div class="paragraph"> <p>You can use the <code>Subject (sub)</code> mapper to configure the <code>sub</code> claim only for access token, lightweight access token, and introspection response. IDToken and Userinfo always contain <code>sub</code> claim.</p> </div> <div class="paragraph"> <p>The mapper has no effects for service accounts, because no user session exists, and the <code>sub</code> claim is always added to the access token.</p> </div> </div> <div class="sect3"> <h4 id="nonce-claim-is-only-added-to-the-id-token"><a class="anchor" href="#nonce-claim-is-only-added-to-the-id-token"></a>Nonce claim is only added to the ID token</h4> <div class="paragraph"> <p>The nonce claim is now only added to the ID token strictly following the OpenID Connect Core 1.0 specification. As indicated in the specification, the claim is compulsory inside the <a href="https://openid.net/specs/openid-connect-core-1_0.html#IDToken">ID token</a> when the same parameter was sent in the authorization request. The specification also recommends to not add the <code>nonce</code> after a <a href="https://openid.net/specs/openid-connect-core-1_0.html#RefreshTokenResponse">refresh request</a>. Previously, the claim was set to all the tokens (Access, Refresh and ID) in all the responses (refresh included).</p> </div> <div class="paragraph"> <p>A new <code>Nonce backwards compatible</code> mapper is also included in the software that can be assigned to client scopes to revert to the old behavior. For example, the JS adapter checked the returned <code>nonce</code> claim in all the tokens before fixing issue <a href="https://github.com/keycloak/keycloak/issues/26651">#26651</a> in version 24.0.0. Therefore, if an old version of the JS adapter is used, the mapper should be added to the required clients by using client scopes.</p> </div> </div> <div class="sect3"> <h4 id="changed-userid-for-events-related-to-refresh-token"><a class="anchor" href="#changed-userid-for-events-related-to-refresh-token"></a>Changed <code>userId</code> for events related to refresh token</h4> <div class="paragraph"> <p>The <code>userId</code> in the <code>REFRESH_TOKEN</code> event is now always taken from user session instead of <code>sub</code> claim in the refresh token. The <code>userId</code> in the <code>REFRESH_TOKEN_ERROR</code> event is now always null. The reason for this change is that the value of the <code>sub</code> claim in the refresh token may be null with the introduction of the optional <code>sub</code> claim or even different from the real user id when using pairwise subject identifiers or other ways to override the <code>sub</code> claim.</p> </div> <div class="paragraph"> <p>However a <code>refresh_token_sub</code> detail is now added as backwards compatibility to have info about the user in the case of missing userId in the <code>REFRESH_TOKEN_ERROR</code> event.</p> </div> </div> <div class="sect3"> <h4 id="using-older-javascript-adapter"><a class="anchor" href="#using-older-javascript-adapter"></a>Using older javascript adapter</h4> <div class="paragraph"> <p>If you use the latest Keycloak server with older versions of the javascript adapter in your applications, you may be affected by the token changes mentioned above as previous versions of javascript adapter rely on the claims, which were added by Keycloak, but not supported by the OIDC specification. This includes:</p> </div> <div class="ulist"> <ul> <li> <p>Adding the <code>Session State (session_state)</code> mapper in case of using the Keycloak Javascript adapter 24.0.3 or older</p> </li> <li> <p>Adding the <code>Nonce backwards compatible</code> mapper in case of using a Keycloak Javascript adapter that is older than Keycloak 24</p> </li> </ul> </div> <div class="paragraph"> <p>You can add the protocol mappers directly to the corresponding client or to some client scope, which can be used by your client applications relying on older versions of the Keycloak Javascript adapter. Some more details are in the previous sections dedicated to <code>session_state</code> and <code>nonce</code> claims.</p> </div> </div> <div class="sect3"> <h4 id="default-http-pool-max-threads-reduced"><a class="anchor" href="#default-http-pool-max-threads-reduced"></a>Default <code>http-pool-max-threads</code> reduced</h4> <div class="paragraph"> <p><code>http-pool-max-threads</code> if left unset will default to the greater of 50 or 4 x (available processors). Previously it defaulted to the greater of 200 or 8 x (available processors). Reducing the number or task threads for most usage scenarios will result in slightly higher performance due to less context switching among active threads.</p> </div> </div> <div class="sect3"> <h4 id="management-port-for-metrics-and-health-endpoints"><a class="anchor" href="#management-port-for-metrics-and-health-endpoints"></a>Management port for metrics and health endpoints</h4> <div class="paragraph"> <p>The <code>/health</code> and <code>/metrics</code> endpoints are accessible on the management port <code>9000</code>, which is turned on by default. That means these endpoints are no longer exposed to the standard Keycloak ports <code>8080</code> and <code>8443</code>.</p> </div> <div class="paragraph"> <p>In order to reflect the old behavior, use the property <code>--legacy-observability-interface=true</code>, which will not expose these endpoints on the management port. However, this property is deprecated and will be removed in future releases, so it is recommended not to use it.</p> </div> <div class="paragraph"> <p>The management interface uses a different HTTP server than the default Keycloak HTTP server, and it is possible to configure them separately. Beware, if no values are supplied for the management interface properties, they are inherited from the default Keycloak HTTP server.</p> </div> <div class="paragraph"> <p>For more details, see <a href="https://www.keycloak.org/server/management-interface">Configuring the Management Interface</a>.</p> </div> </div> <div class="sect3"> <h4 id="escaping-slashes-in-group-paths"><a class="anchor" href="#escaping-slashes-in-group-paths"></a>Escaping slashes in group paths</h4> <div class="paragraph"> <p>Keycloak has never escaped slashes in the group paths. Because of that, a group named <code>group/slash</code> child of <code>top</code> uses the full path <code>/top/group/slash</code>, which is clearly misleading. Starting with this version, the server can be started to perform escaping of those slashes in the name:</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 escape char is the tilde character <code>~</code>. The previous example results in the path <code>/top/group~/slash</code>. The escape marks the last slash is part of the name and not a hierarchy separator.</p> </div> <div class="paragraph"> <p>The escaping is currently disabled by default because it represents a change in behavior. Nevertheless enabling escaping is recommended and it can be the default in future versions.</p> </div> </div> <div class="sect3"> <h4 id="change-to-class-environmentdependentproviderfactory"><a class="anchor" href="#change-to-class-environmentdependentproviderfactory"></a>Change to class <code>EnvironmentDependentProviderFactory</code></h4> <div class="paragraph"> <p>The method <code>EnvironmentDependentProviderFactory.isSupported()</code> was deprecated for several releases and has now been removed.</p> </div> <div class="paragraph"> <p>Instead, implement <code>isSupported(Config.Scope config)</code>.</p> </div> </div> <div class="sect3"> <h4 id="removal-of-the-deprecated-linkedin-provider"><a class="anchor" href="#removal-of-the-deprecated-linkedin-provider"></a>Removal of the deprecated LinkedIn provider</h4> <div class="paragraph"> <p>In version 22.0.2 the OAuh 2.0 social provider for LinkedIn was replaced by a new OpenId Connect implementation. The legacy provider was deprecated but not removed, just in case it was still functional in some existing realms. Keycloak 25.0.0 is definitely removing the old provider and its associated <code>linkedin-oauth</code> feature. From now on, the default <code>LinkedIn</code> social provider is the only option available.</p> </div> </div> <div class="sect3"> <h4 id="improved-performance-of-findgrantedresources-and-findgrantedownerresources-queries"><a class="anchor" href="#improved-performance-of-findgrantedresources-and-findgrantedownerresources-queries"></a>Improved performance of <code>findGrantedResources</code> and <code>findGrantedOwnerResources</code> queries</h4> <div class="paragraph"> <p>These queries performed poorly when the <code>RESOURCE_SERVER_RESOURCE</code> and <code>RESOURCE_SERVER_PERM_TICKET</code> tables had over 100k entries and users were granted access to over 1k resources. The queries were simplified and new indexes for the <code>requester</code> and <code>owner</code> columns were introduced.</p> </div> <div class="paragraph"> <p>The new indexes are both applied to the <code>RESOURCE_SERVER_PERM_TICKET</code> table. If the table currently contains more than 300.000 entries, Keycloak will skip the creation of the indexes by default during the automatic schema migration, and will instead log the SQL statements on the console during migration. In this case, the statements must be run manually in the DB after Keycloak&#8217;s startup.</p> </div> <div class="paragraph"> <p>See the <a href="https://www.keycloak.org/docs/26.0.6/upgrading/">Upgrading Guide</a> for details on how to configure a different limit.</p> </div> </div> <div class="sect3"> <h4 id="removing-deprecated-methods-from-accesstoken-idtoken-and-jsonwebtoken-classes"><a class="anchor" href="#removing-deprecated-methods-from-accesstoken-idtoken-and-jsonwebtoken-classes"></a>Removing deprecated methods from <code>AccessToken</code>, <code>IDToken</code>, and <code>JsonWebToken</code> classes</h4> <div class="paragraph"> <p>The following methods were removed from the <code>AccessToken</code> class:</p> </div> <div class="ulist"> <ul> <li> <p><code>expiration</code>. Use the <code>exp</code> method instead.</p> </li> <li> <p><code>notBefore</code>. Use the <code>nbf</code> method instead.</p> </li> <li> <p><code>issuedAt</code>. Use the <code>iat</code> method instead.</p> </li> </ul> </div> <div class="paragraph"> <p>The following methods were removed from the <code>IDToken</code> class:</p> </div> <div class="ulist"> <ul> <li> <p><code>getAuthTime</code> and <code>setAuthTime</code>. Use the <code>getAuth_time</code> and <code>setAuth_time</code> methods, respectively.</p> </li> <li> <p><code>notBefore</code>. Use the <code>nbf</code> method instead.</p> </li> <li> <p><code>issuedAt</code>. Use the <code>iat</code> method instead.</p> </li> <li> <p><code>setSessionState</code>. Use the <code>setSessionId</code> method instead (See the details above in the section about <code>session_state</code> claim)</p> </li> </ul> </div> <div class="paragraph"> <p>The following methods were removed from the <code>JsonWebToken</code> class:</p> </div> <div class="ulist"> <ul> <li> <p><code>expiration</code>. Use the <code>exp</code> method instead.</p> </li> <li> <p><code>notBefore</code>. Use the <code>nbf</code> method instead.</p> </li> <li> <p><code>issuedAt</code>. Use the <code>iat</code> method instead.</p> </li> </ul> </div> <div class="paragraph"> <p>You should also expect both <code>exp</code> and <code>nbf</code> claims not set in tokens as they are optional. Previously, these claims were being set with a value of <code>0</code> what does not make mush sense because their value should be a valid <code>NumericDate</code>.</p> </div> </div> <div class="sect3"> <h4 id="method-getexp-added-to-singleuseobjectkeymodel"><a class="anchor" href="#method-getexp-added-to-singleuseobjectkeymodel"></a>Method <code>getExp</code> added to <code>SingleUseObjectKeyModel</code></h4> <div class="paragraph"> <p>As a consequence of the removal of deprecated methods from <code>AccessToken</code>, <code>IDToken</code>, and <code>JsonWebToken</code>, the <code>SingleUseObjectKeyModel</code> also changed to keep consistency with the method names related to expiration values.</p> </div> <div class="paragraph"> <p>The previous <code>getExpiration</code> method is now deprecated and you should prefer using new newly introduced <code>getExp</code> method to avoid overflow after 2038.</p> </div> </div> <div class="sect3"> <h4 id="method-encode-deprecated-on-passwordhashprovider"><a class="anchor" href="#method-encode-deprecated-on-passwordhashprovider"></a>Method encode deprecated on PasswordHashProvider</h4> <div class="paragraph"> <p>Method <code>String encode(String rawPassword, int iterations)</code> on the interface <code>org.keycloak.credential.hash.PasswordHashProvider</code> is deprecated. The method will be removed in one of the future Keycloak releases. It might be Keycloak 27 release.</p> </div> </div> <div class="sect3"> <h4 id="collectionutil-intesection-method-removed"><a class="anchor" href="#collectionutil-intesection-method-removed"></a>CollectionUtil intesection method removed</h4> <div class="paragraph"> <p>The method <code>org.keycloak.common.util.CollectionUtil.intersection</code> has been removed. You should use the 'java.util.Collection.retainAll' instead on an existing collection.</p> </div> </div> <div class="sect3"> <h4 id="resteasy-util-class-is-deprecated"><a class="anchor" href="#resteasy-util-class-is-deprecated"></a>Resteasy util class is deprecated</h4> <div class="paragraph"> <p><code>org.keycloak.common.util.Resteasy</code> has been deprecated. You should use the <code>org.keycloak.util.KeycloakSessionUtil</code> to obtain the <code>KeycloakSession</code> instead.</p> </div> <div class="paragraph"> <p>It is highly recommended to avoid obtaining the <code>KeycloakSession</code> by means other than when creating your custom provider.</p> </div> </div> <div class="sect3"> <h4 id="small-changes-in-session-lifespan-and-idle-calculations"><a class="anchor" href="#small-changes-in-session-lifespan-and-idle-calculations"></a>Small changes in session lifespan and idle calculations</h4> <div class="paragraph"> <p>In previous versions the session max lifespan and idle timeout calculation was slightly different when validating if a session was still valid. Since now that validation uses the same code than the rest of the project.</p> </div> <div class="paragraph"> <p>If the session is using the remember me feature, the idle timeout and max lifespan are the maximum value between the common SSO and the remember me configuration values.</p> </div> </div> <div class="sect3"> <h4 id="external-infinispan-requirements"><a class="anchor" href="#external-infinispan-requirements"></a>External Infinispan requirements</h4> <div class="paragraph"> <p>Keycloak now requires a Infinispan server version of at least 15.0.0 for external Infinispan deployments. An external Infinispan deployment is supported for multi-site setups as outlined in the HA guide.</p> </div> </div> <div class="sect3"> <h4 id="oracle-database-driver-not-part-of-the-distribution"><a class="anchor" href="#oracle-database-driver-not-part-of-the-distribution"></a>Oracle Database driver not part of the distribution</h4> <div class="paragraph"> <p>The Oracle Database JDBC driver is no longer part of the Keycloak distribution. If you wish to use Oracle DB, you must manually install a version of the Oracle Driver that is compatible with your specific environment. Instructions for this process can be found in the <a href="https://www.keycloak.org/server/db">Configuring the database</a> guide.</p> </div> </div> <div class="sect3"> <h4 id="deprecated-theme-variables"><a class="anchor" href="#deprecated-theme-variables"></a>Deprecated theme variables</h4> <div class="paragraph"> <p>The following variables were deprecated in the Admin theme and will be removed in a future version:</p> </div> <div class="ulist"> <ul> <li> <p><code>authServerUrl</code>. Use <code>serverBaseUrl</code> instead.</p> </li> <li> <p><code>authUrl</code>. Use <code>adminBaseUrl</code> instead.</p> </li> </ul> </div> <div class="paragraph"> <p>The following variables were deprecated in the Account theme and will be removed in a future version:</p> </div> <div class="ulist"> <ul> <li> <p><code>authServerUrl</code>. Use <code>serverBaseUrl</code> instead, note <code>serverBaseUrl</code> does not include trailing slash.</p> </li> <li> <p><code>authUrl</code>. Use <code>serverBaseUrl</code> instead, note <code>serverBaseUrl</code> does not include trailing slash.</p> </li> </ul> </div> </div> <div class="sect3"> <h4 id="methods-to-get-and-set-current-refresh-token-in-client-session-are-now-deprecated"><a class="anchor" href="#methods-to-get-and-set-current-refresh-token-in-client-session-are-now-deprecated"></a>Methods to get and set current refresh token in client session are now deprecated</h4> <div class="paragraph"> <p>The methods <code>String getCurrentRefreshToken()</code>, <code>void setCurrentRefreshToken(String currentRefreshToken)</code>, <code>int getCurrentRefreshTokenUseCount()</code>, and <code>void setCurrentRefreshTokenUseCount(int currentRefreshTokenUseCount)</code> in the interface <code>org.keycloak.models.AuthenticatedClientSessionModel</code> are deprecated. They have been replaced by similar methods that require an identifier as a parameter such as <code>getRefreshToken(String reuseId)</code> to manage multiple refresh tokens within a client session. The methods will be removed in one of the future Keycloak releases. It might be Keycloak 27 release.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-24-0-4"><a class="anchor" href="#migrating-to-24-0-4"></a>Migrating to 24.0.4</h3> <div class="sect3"> <h4 id="partial-update-to-user-attributes-when-updating-users-through-the-admin-user-api-is-no-longer-supported"><a class="anchor" href="#partial-update-to-user-attributes-when-updating-users-through-the-admin-user-api-is-no-longer-supported"></a>Partial update to user attributes when updating users through the Admin User API is no longer supported</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/changes/changes-24_0_4.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/changes/changes-24_0_4.adoc&amp;description=%0A%0AFile:%20upgrading/topics/changes/changes-24_0_4.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 updating user attributes through the Admin User API, you cannot execute partial updates when updating the user attributes, including the root attributes like <code>username</code>, <code>email</code>, <code>firstName</code>, and <code>lastName</code>.</p> </div> <div class="paragraph"> <p>If you are updating user attributes through the Admin User API without passing all the attributes that the administrator has write permissions, the missing attributes will be removed. On the other hand, if an attribute is marked as read-only for administrators, not sending the attribute won&#8217;t remove it.</p> </div> <div class="paragraph"> <p>See the <a href="https://www.keycloak.org/docs/26.0.6/server_admin/#user-profile">User Profile Documentation</a> for the details about the user profile settings.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-24-0-3"><a class="anchor" href="#migrating-to-24-0-3"></a>Migrating to 24.0.3</h3> <div class="sect3"> <h4 id="changes-to-the-org-keycloak-userprofile-userprofiledecorator-interface"><a class="anchor" href="#changes-to-the-org-keycloak-userprofile-userprofiledecorator-interface"></a>Changes to the <code>org.keycloak.userprofile.UserProfileDecorator</code> interface</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/changes/changes-24_0_3.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/changes/changes-24_0_3.adoc&amp;description=%0A%0AFile:%20upgrading/topics/changes/changes-24_0_3.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 properly support multiple user storage providers within a realm, the <code>org.keycloak.userprofile.UserProfileDecorator</code> interface has changed.</p> </div> <div class="paragraph"> <p>The <code>decorateUserProfile</code> method is no longer invoked when parsing the user profile configuration for the first time (and caching it), but every time a user is being managed through the user profile provider. As a result, the method changed its contract to:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java"><span class="predefined-type">List</span>&lt;AttributeMetadata&gt; decorateUserProfile(<span class="predefined-type">String</span> providerId, UserProfileMetadata metadata)</code></pre> </div> </div> <div class="paragraph"> <p>Differently than the previous contract and behavior, this method is only invoked for the user storage provider from where the user was loaded from.</p> </div> </div> <div class="sect3"> <h4 id="changes-in-redirect-uri-verification-when-using-wildcards"><a class="anchor" href="#changes-in-redirect-uri-verification-when-using-wildcards"></a>Changes in redirect URI verification when using wildcards</h4> <div class="paragraph"> <p>Because of security concerns, the redirect URI verification now performs a exact string matching (no wildcard involved) if the passed redirect uri contains a <code>userinfo</code> part or its <code>path</code> accesses parent directory (<code>/../</code>).</p> </div> <div class="paragraph"> <p>The full wildcard <code>*</code> can still be used as a valid redirect in development for http(s) URIs with those characteristics. In production environments a exact valid redirect URI without wildcard needs to be configured for any URI of that type.</p> </div> <div class="paragraph"> <p>Please note that wildcard valid redirect URIs are not recommended for production and not covered by the OAuth 2.0 specification.</p> </div> </div> <div class="sect3"> <h4 id="deprecated-account-rest-endpoint-for-removing-credential"><a class="anchor" href="#deprecated-account-rest-endpoint-for-removing-credential"></a>Deprecated Account REST endpoint for removing credential</h4> <div class="paragraph"> <p>The Account REST endpoint for removing the credential of the user is deprecated. Starting at this version, the Account Console no longer uses this endpoint. It is replaced by the <code>Delete Credential</code> application-initiated action, which is triggered by the Account Console when a user want to remove the credential of a user.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-24-0-2"><a class="anchor" href="#migrating-to-24-0-2"></a>Migrating to 24.0.2</h3> <div class="sect3"> <h4 id="changes-to-password-hashing"><a class="anchor" href="#changes-to-password-hashing"></a>Changes to Password Hashing</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/changes/changes-24_0_2.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/changes/changes-24_0_2.adoc&amp;description=%0A%0AFile:%20upgrading/topics/changes/changes-24_0_2.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 release notes for Keycloak 24.0.0 have been updated with corrected description of the expected performance impact for the change, as well as sizing guide.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-24-0-0"><a class="anchor" href="#migrating-to-24-0-0"></a>Migrating to 24.0.0</h3> <div class="sect3"> <h4 id="changes-to-the-welcome-theme"><a class="anchor" href="#changes-to-the-welcome-theme"></a>Changes to the Welcome theme</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/changes/changes-24_0_0.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/changes/changes-24_0_0.adoc&amp;description=%0A%0AFile:%20upgrading/topics/changes/changes-24_0_0.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 'welcome' theme has has been updated to use a new layout and now uses PatternFly 5, rather than PatternFly 3. If you are extending the theme, or providing your own, you may need to update it as follows:</p> </div> <div class="sect4"> <h5 id="migrate-from-patternfly-3-to-patternfly-5"><a class="anchor" href="#migrate-from-patternfly-3-to-patternfly-5"></a>Migrate from PatternFly 3 to PatternFly 5</h5> <div class="paragraph"> <p>The welcome theme was one of the more outdated themes in Keycloak. It was originally based on PatternFly 3, but has now been updated to use PatternFly 5, skipping a major version in the process. If your custom theme extends the built-in theme, you will need to update it to use PatternFly 5 syntax. Consult the <a href="https://www.patternfly.org/get-started/develop/">PatternFly 5 documentation</a> for details.</p> </div> <div class="paragraph"> <p>If you are still using PatternFly 3 in your own custom theme (not extending the built-in one), you can continue to use it, but PatternFly 3 support will be removed in a future release, so you should consider migrating to PatternFly 5 as soon as possible.</p> </div> </div> <div class="sect4"> <h5 id="automatic-redirect-to-the-admin-console"><a class="anchor" href="#automatic-redirect-to-the-admin-console"></a>Automatic redirect to the Admin Console</h5> <div class="paragraph"> <p>If the Admin Console is enabled, the welcome page will automatically redirect to it if the administrative user already exists. This behavior can be modified by setting the <code>redirectToAdmin</code> in your <code>theme.properties</code> file. By default, the property is set to <code>false</code>, unless you are extending the built-in theme, in which case, the property is set to <code>true</code>.</p> </div> </div> <div class="sect4"> <h5 id="the-documentationurl-and-displaycommunitylinks-properties-have-been-removed"><a class="anchor" href="#the-documentationurl-and-displaycommunitylinks-properties-have-been-removed"></a>The <code>documentationUrl</code> and <code>displayCommunityLinks</code> properties have been removed.</h5> <div class="paragraph"> <p>These properties were previously used for navigational elements that are now no longer present. If you are extending the built-in theme, you will need to remove these properties from your <code>theme.properties</code> file, as they no longer have any effect.</p> </div> </div> <div class="sect4"> <h5 id="assets-are-now-loaded-from-common-resources"><a class="anchor" href="#assets-are-now-loaded-from-common-resources"></a>Assets are now loaded from 'common' resources</h5> <div class="paragraph"> <p>Images such as the background, logo and favicon are now loaded from the 'common' resources, rather than the theme resources. This change means that if you are extending the built-in theme, and are overwriting these images, you will need to move them to the 'common' resources of your theme, and update your <code>theme.properties</code> file to include the new paths:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="properties"># This defaults to 'common/keycloak' if not set. import=common/your-theme-name</code></pre> </div> </div> </div> </div> <div class="sect3"> <h4 id="changes-to-the-account-console-theme-customization"><a class="anchor" href="#changes-to-the-account-console-theme-customization"></a>Changes to the Account Console theme customization</h4> <div class="paragraph"> <p>If you were previously extending the now deprecated version 2 of the Account Console theme, you will need to update your theme to use the new version 3 of the Account Console theme. The new version of the Account Console theme comes with some changes in regards to how it is customized. To start with a clean slate, you can follow the new <a href="https://github.com/keycloak/keycloak-quickstarts/tree/release/24.0/extension/extend-account-console">customization quickstart</a>.</p> </div> <div class="paragraph"> <p>To move your custom theme start by changing the <code>parent</code> to the new theme:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="properties"># Before parent=keycloak.v2 # After parent=keycloak.v3</code></pre> </div> </div> <div class="paragraph"> <p>If you have any custom React components, you will import React directly, rather than using a relative path:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="js"><span class="comment">// Before</span> <span class="reserved">import</span> * as React from <span class="string"><span class="delimiter">&quot;</span><span class="content">../../../../common/keycloak/web_modules/react.js</span><span class="delimiter">&quot;</span></span>; <span class="comment">// After</span> <span class="reserved">import</span> React from <span class="string"><span class="delimiter">&quot;</span><span class="content">react</span><span class="delimiter">&quot;</span></span>;</code></pre> </div> </div> <div class="paragraph"> <p>If you are using <code>content.json</code> to customize the theme there are some changes to the structure of the file, specifically:</p> </div> <div class="ulist"> <ul> <li> <p>The <code>content</code> property has been renamed to <code>children</code>.</p> </li> <li> <p>The <code>id</code>, <code>icon</code> and <code>componentName</code> properties have been removed, as <code>modulePath</code> provides the same functionality.</p> </li> </ul> </div> </div> <div class="sect3"> <h4 id="keycloak-js-imports-might-need-to-be-updated"><a class="anchor" href="#keycloak-js-imports-might-need-to-be-updated"></a>Keycloak JS imports might need to be updated</h4> <div class="paragraph"> <p>If you are loading Keycloak JS directly from the Keycloak server, this section can be safely ignored. If you are loading Keycloak JS from the NPM package and are using a bundler like Webpack, Vite, and so on, you might need to make some changes to your code. The Keycloak JS package now uses the <a href="https://webpack.js.org/guides/package-exports/"><code>exports</code> field</a> in the package.json file. This means that you might have to change your imports:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="js"><span class="comment">// Before</span> <span class="reserved">import</span> Keycloak from <span class="string"><span class="delimiter">'</span><span class="content">keycloak-js/dist/keycloak.js</span><span class="delimiter">'</span></span>; <span class="reserved">import</span> AuthZ from <span class="string"><span class="delimiter">'</span><span class="content">keycloak-js/dist/keycloak-authz.js</span><span class="delimiter">'</span></span>; <span class="comment">// After</span> <span class="reserved">import</span> Keycloak from <span class="string"><span class="delimiter">'</span><span class="content">keycloak-js</span><span class="delimiter">'</span></span>; <span class="reserved">import</span> AuthZ from <span class="string"><span class="delimiter">'</span><span class="content">keycloak-js/authz</span><span class="delimiter">'</span></span>;</code></pre> </div> </div> </div> <div class="sect3"> <h4 id="features-changes"><a class="anchor" href="#features-changes"></a>Features Changes</h4> <div class="paragraph"> <p>It is no longer allowed to have the same feature in both the <code>--features</code> and <code>--features-disabled</code> list. The feature should appear in only one list.</p> </div> <div class="paragraph"> <p>The usage of unversioned feature names, such as <code>docker</code>, in the <code>--features</code> list will allow for the most supported / latest feature version to be enabled for you. If you need more predictable behavior across releases, reference the particular version you want instead, such as <code>docker:v1</code>.</p> </div> </div> <div class="sect3"> <h4 id="user-profile-changes"><a class="anchor" href="#user-profile-changes"></a>User Profile Changes</h4> <div class="sect4"> <h5 id="user-profile-enabled-by-default"><a class="anchor" href="#user-profile-enabled-by-default"></a>User profile enabled by default</h5> <div class="paragraph"> <p>The user profile feature is now enabled by default. The `declarative-user-profile`feature is no longer available, because the user profile is assumed to be enabled. Therefore, the <strong>User Profile Enabled</strong> switch is removed from the <strong>Realm Settings</strong> and replaced by <strong>Unmanaged attributes</strong>. When migrating from previous version, the behavior is as follows:</p> </div> <div class="ulist"> <ul> <li> <p>For the deployments where <strong>User Profile Enabled</strong> was set to <strong>ON</strong>, <strong>Unmanaged attributes</strong> will be set to <strong>OFF</strong> after the upgrade. As a result, only user attributes supported explicitly by user profile will be allowed.</p> </li> <li> <p>For the deployments where the <strong>User Profile Enabled</strong> was set to <strong>OFF</strong> (which was also the default settings for the deployments with <code>declarative-user-profile</code> feature disabled, which was the default), <strong>Unmanaged attributes</strong> will be set to <strong>ON</strong>` after the upgrade. As a result, the behavior should be basically the same as in previous versions with the user profile disabled. The <strong>Attributes</strong> tab will remain in the user details part of the Admin Console. Also users can now set arbitrary attributes through UI pages such as the registration page and update profile page as long as a particular custom theme supports it. The custom themes should work as before as well. However, consider updating your themes to use the user-profile and maybe even remove your custom themes if those themes were need to add custom attributes. See the subsequent section on themes. Also, consider toggling <strong>Unmanaged attributes</strong> to <strong>OFF</strong> or enable this switch only for administrators so that you can rely on mainly on using managed attributes.</p> </li> </ul> </div> <div class="paragraph"> <p>See the <a href="https://www.keycloak.org/docs/26.0.6/server_admin/#user-profile">User Profile Documentation</a> for the details about the <strong>Unmanaged attributes</strong>.</p> </div> </div> <div class="sect4"> <h5 id="default-validations"><a class="anchor" href="#default-validations"></a>Default validations</h5> <div class="paragraph"> <p>Default user profile configuration comes with a set of default validations for the basic predefined fields. Those validations were not present in previous versions when the <code>declarative-user-profile</code> feature was disabled by default. If you have issues due to backward compatibility, you can change the default validators according to your needs. The default validators are as follows:</p> </div> <div class="ulist"> <ul> <li> <p>The`username`, <code>email</code>, <code>firstName</code> and <code>lastName</code> attributes have a maximum length of 255 characters. These validations were indirectly present in previous versions as well because of the database constraint on the table <code>USER_ENTITY</code> for those fields with a maximum length of 255 characters. However, when using user storage providers, it might be possible before to use longer values.</p> </li> <li> <p>The <code>username</code> attribute has a minimum length of three characters. Username has also <code>username-prohibited-characters</code> and <code>up-username-not-idn-homograph</code> validator by default, which were not present in previous versions. See the <a href="https://www.keycloak.org/docs/26.0.6/server_admin/#user-profile">Validation section of the User Profile Documentation</a> for the details about those attributes. Note that username is not editable by default unless you have the realm switch <code>Edit username enabled</code>. This change means that existing users with incorrect usernames should still work and they will not be enforced to update their usernames. But new users will be enforced to use correct usernames during their registration or creation by the admin REST API.</p> </li> <li> <p>The <code>firstName</code> and <code>lastName</code> attributes have the <code>person-name-prohibited-characters</code> validator on them, which were not present in previous versions. See the <a href="https://www.keycloak.org/docs/26.0.6/server_admin/#user-profile">Validation section of the User Profile Documentation</a> for the details about those attributes. Note that both first name and last name are editable by default, so users, who already have such incorrect first/last name from a previous version will be forced to update them when updating their user profiles.</p> </li> </ul> </div> </div> <div class="sect4"> <h5 id="user-attribute-names-with-strange-characters"><a class="anchor" href="#user-attribute-names-with-strange-characters"></a>User attribute names with strange characters</h5> <div class="paragraph"> <p>In previous versions, you could create a user with attribute names such as <code>some:attribute</code> or <code>some/attribute</code>. The user profile intentionally does not allow you to create attributes with such strange names in the user profile configuration. So you may need to configure <code>Unmanaged attributes</code> for your realm and enable unmanaged attributes for administrators (ideally) or for end users (if really needed). Although it is strongly preferred to avoid using such attribute names.</p> </div> </div> <div class="sect4"> <h5 id="verify-profile-required-action-enabled-by-default"><a class="anchor" href="#verify-profile-required-action-enabled-by-default"></a>Verify Profile required action enabled by default</h5> <div class="paragraph"> <p>The <code>verify-profile</code> required action is enabled by default for new realms. However, when you migrate from a previous version, your existing realms will have the same state of this <code>verify-profile</code> action as before, which usually means disabled as it was disabled by default in previous versions. For the details about this required action, see the <a href="https://www.keycloak.org/docs/26.0.6/server_admin/#user-profile">User Profile Documentation</a>.</p> </div> </div> <div class="sect4"> <h5 id="breaking-changes-to-the-user-profile-spi"><a class="anchor" href="#breaking-changes-to-the-user-profile-spi"></a>Breaking changes to the User Profile SPI</h5> <div class="paragraph"> <p>If you are using the User Profile SPI in your extension, you might be impacted by the API changes introduced in this release.</p> </div> <div class="paragraph"> <p>The <code>org.keycloak.userprofile.Attributes</code> interface includes the following changes:</p> </div> <div class="ulist"> <ul> <li> <p>Method <code>getValues</code> was renamed to <code>get</code> to make it more aligned with the same operation from a regular Java <code>Map</code></p> </li> <li> <p>Method <code>isRootAttribute</code> was moved to the utility class <code>org.keycloak.userprofile.UserProfileUtil.isRootAttribute</code></p> </li> <li> <p>Method <code>getFirstValue</code> was renamed to <code>getFirst</code> to make it less verbose</p> </li> <li> <p>Method <code>getReadable(boolean)</code> was removed and now all attributes (including root attributes) are returned whenever they have read rights.</p> </li> </ul> </div> </div> <div class="sect4"> <h5 id="changes-to-freemarker-templates-to-render-pages-based-on-the-user-profile-and-realm"><a class="anchor" href="#changes-to-freemarker-templates-to-render-pages-based-on-the-user-profile-and-realm"></a>Changes to Freemarker templates to render pages based on the user profile and realm</h5> <div class="paragraph"> <p>In this release, the following templates were updated to make it possible to dynamically render attributes based on the user profile configuration set to a realm:</p> </div> <div class="ulist"> <ul> <li> <p><code>login-update-profile.ftl</code></p> </li> <li> <p><code>register.ftl</code></p> </li> <li> <p><code>update-email.ftl</code></p> </li> </ul> </div> <div class="paragraph"> <p>These templates are responsible for rendering the update profile (when the <strong>Update Profile</strong> required action is enabled for a user), the registration, and the update email (when the <strong>UPDATE_EMAIL</strong> feature is enabled) pages, respectively.</p> </div> <div class="paragraph"> <p>If you use a custom theme to change these templates, they will function as expected because only the content is updated. However, we recommend you to take a look at how to configure a <a href="https://www.keycloak.org/docs/26.0.6/server_admin/#user-profile">{declarative user profile}</a> and possibly avoid changing the built-in templates by using all the capabilities provided by this feature.</p> </div> <div class="paragraph"> <p>Also, the templates used by the <code>declarative-user-profile</code> feature to render the pages for the same flows are longer necessary and removed in this release:</p> </div> <div class="ulist"> <ul> <li> <p><code>update-user-profile.ftl</code></p> </li> <li> <p><code>register-user-profile.ftl</code></p> </li> </ul> </div> <div class="paragraph"> <p>If you were using the <code>declarative-user-profile</code> feature in a previous release with customizations to the above templates, update the <code>login-update-profile.ftl</code> and <code>register.ftl</code> accordingly.</p> </div> </div> <div class="sect4"> <h5 id="new-freemarker-template-for-the-update-profile-page-at-first-login-through-a-broker"><a class="anchor" href="#new-freemarker-template-for-the-update-profile-page-at-first-login-through-a-broker"></a>New Freemarker template for the update profile page at first login through a broker</h5> <div class="paragraph"> <p>In this release, the server will render the update profile page when the user is authenticating through a broker for the first time using the <code>idp-review-user-profile.ftl</code> template.</p> </div> <div class="paragraph"> <p>In previous releases, the template used to update the profile during the first broker login flow was the <code>login-update-profile.ftl</code>, the same used to update the profile when users are authenticating to a realm.</p> </div> <div class="paragraph"> <p>By using separate templates for each flow, a more clear distinction exist as to which flow a template is actually used rather than sharing a same template, and potentially introduce unexpected changes and behavior that should only affect pages for a specific flow.</p> </div> <div class="paragraph"> <p>If you have customizations to the <code>login-update-profile.ftl</code> template to customize how users update their profiles when authenticating through a broker, make sure to move your changes to the new template.</p> </div> </div> </div> <div class="sect3"> <h4 id="truststore-changes"><a class="anchor" href="#truststore-changes"></a>Truststore Changes</h4> <div class="paragraph"> <p>The <code>spi-truststore-file-*</code> options and the truststore related options <code>https-trust-store-*</code> are deprecated. Therefore, use the new default location for truststore material, <code>conf/truststores</code>, or specify your desired paths by using the <code>truststore-paths</code> option. For details, see the relevant <a href="https://www.keycloak.org/server/keycloak-truststore">guide</a>.</p> </div> <div class="paragraph"> <p>The <code>tls-hostname-verifier</code> property should be used instead of the <code>spi-truststore-file-hostname-verification-policy</code> property.</p> </div> <div class="paragraph"> <p>A collateral effect of the changes is that now the truststore provider is always configured with some certificates (at least the default java trusted certificates are present). This new behavior can affect other parts of Keycloak.</p> </div> <div class="paragraph"> <p>For example, <strong>webauthn</strong> registration can fail if <strong>attestation conveyance</strong> was configured to <strong>Direct</strong> validation. Previously, if the truststore provider was not configured the incoming certificate was not validated. But now this validation is always performed. The registration fails with <code>invalid cert path</code> error as the certificate chain sent by the dongle is not trusted by Keycloak. The Certificate Authorities of the authenticator need to be present in the truststore provider to correctly perform the attestation.</p> </div> </div> <div class="sect3"> <h4 id="deprecated-proxy-option"><a class="anchor" href="#deprecated-proxy-option"></a>Deprecated <code>--proxy</code> option</h4> <div class="paragraph"> <p>The <code>--proxy</code> option has been deprecated and will be removed in a future release. The following table explains how the deprecated option maps to supported options.</p> </div> <table class="tableblock frame-all grid-all fit-content"> <colgroup> <col> <col> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Deprecated usage</th> <th class="tableblock halign-left valign-top">New usage</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>kc.sh</code> (no <code>proxy</code> option set)</p> </div></div></td> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>kc.sh</code></p> </div></div></td> </tr> <tr> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>kc.sh --proxy none</code></p> </div></div></td> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>kc.sh</code></p> </div></div></td> </tr> <tr> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>kc.sh --proxy edge</code></p> </div></div></td> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>kc.sh --proxy-headers forwarded|xforwarded --http-enabled true</code></p> </div></div></td> </tr> <tr> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>kc.sh --proxy passthrough</code></p> </div></div></td> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>kc.sh --hostname-port 80|443</code> (depending if HTTPS is used)</p> </div></div></td> </tr> <tr> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>kc.sh --proxy reencrypt</code></p> </div></div></td> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>kc.sh --proxy-headers forwarded|xforwarded</code></p> </div></div></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"> For hardened security, the <code>--proxy-headers</code> option does not allow selecting both <code>forwarded</code> and <code>xforwarded</code> values at the same time (as it was the case before for <code>--proxy edge</code> and <code>--proxy reencrypt</code>). </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"> When using the proxy headers option, make sure your reverse proxy properly sets and overwrites the <code>Forwarded</code> or <code>X-Forwarded-*</code> headers respectively. To set these headers, consult the documentation for your reverse proxy. Misconfiguration will leave Keycloak exposed to security vulnerabilities. </td> </tr> </table> </div> <div class="paragraph"> <p>You can also set the proxy headers when using the Operator:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="yaml"><span class="key">apiVersion</span>: <span class="string"><span class="content">k8s.keycloak.org/v2alpha1</span></span> <span class="key">kind</span>: <span class="string"><span class="content">Keycloak</span></span> <span class="key">metadata</span>: <span class="key">name</span>: <span class="string"><span class="content">example-kc</span></span> <span class="key">spec</span>: <span class="error">...</span> <span class="key">proxy</span>: <span class="key">headers</span>: <span class="string"><span class="content">forwarded|xforwarded</span></span></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"> If the <code>proxy.headers</code> field is not specified, the Operator falls back to the previous behavior by implicitly setting <code>proxy=passthrough</code> by default. This results in deprecation warnings in the server log. This fallback will be removed in a future release. </td> </tr> </table> </div> </div> <div class="sect3"> <h4 id="changes-to-the-user-representation-in-both-admin-api-and-account-contexts"><a class="anchor" href="#changes-to-the-user-representation-in-both-admin-api-and-account-contexts"></a>Changes to the user representation in both Admin API and Account contexts</h4> <div class="paragraph"> <p>Both <code>org.keycloak.representations.idm.UserRepresentation</code> and <code>org.keycloak.representations.account.UserRepresentation</code> representation classes have changed so that the root user attributes (such as <code>username</code>, <code>email</code>, <code>firstName</code>, <code>lastName</code>, and <code>locale</code>) have a consistent representation when fetching or sending the representation payload to the Admin and Account APIS, respectively.</p> </div> <div class="paragraph"> <p>The <code>username</code>, <code>email</code>, <code>firstName</code>, <code>lastName</code>, and <code>locale</code> attributes were moved to a new <code>org.keycloak.representations.idm.AbstractUserRepresentation</code> base class.</p> </div> <div class="paragraph"> <p>Also the <code>getAttributes</code> method is targeted for representing only custom attributes, so you should not expect any root attribute in the map returned by this method. This method is mainly targeted for clients when updating or fetching any custom attribute for a give user.</p> </div> <div class="paragraph"> <p>In order to resolve all the attributes including the root attributes, a new <code>getRawAttributes</code> method was added so that the resulting map also includes the root attributes. However, this method is not available from the representation payload and it is targeted to be used by the server when managing user profiles.</p> </div> </div> <div class="sect3"> <h4 id="https-client-auth-is-a-build-time-option"><a class="anchor" href="#https-client-auth-is-a-build-time-option"></a><code>https-client-auth</code> is a build time option</h4> <div class="paragraph"> <p>Option <code>https-client-auth</code> had been treated as a run time option, however this is not supported by Quarkus. The option needs to be handled at build time instead.</p> </div> </div> <div class="sect3"> <h4 id="sequential-loading-of-offline-sessions-and-remote-sessions"><a class="anchor" href="#sequential-loading-of-offline-sessions-and-remote-sessions"></a>Sequential loading of offline sessions and remote sessions</h4> <div class="paragraph"> <p>Starting with this release, the first member of a Keycloak cluster will load remote sessions sequentially instead of in parallel. If offline session preloading is enabled, those will be loaded sequentially as well.</p> </div> <div class="paragraph"> <p>The previous code led to high resource-consumption across the cluster at startup and was challenging to analyze in production environments and could lead to complex failure scenarios if a node was restarted during loading. Therefore, it was changed to sequential session loading.</p> </div> <div class="paragraph"> <p>For offline sessions, the default in this and previous versions of Keycloak is to load those sessions on demand, which scales better with a lot of offline sessions than the attempt to preload them in parallel. Setups that use this default setup are not affected by the change of the loading strategy for offline sessions. Setups that have offline session preloading enabled should migrate to a setup where offline-session preloading is disabled.</p> </div> </div> <div class="sect3"> <h4 id="deprecated-offline-session-preloading"><a class="anchor" href="#deprecated-offline-session-preloading"></a>Deprecated offline session preloading</h4> <div class="paragraph"> <p>The default behavior of Keycloak is to load offline sessions on demand. The old behavior to preload them at startup is now deprecated, as preloading them at startup does not scale well with a growing number of sessions, and increases Keycloak memory usage. The old behavior will be removed in a future release.</p> </div> <div class="paragraph"> <p>To re-enable old behavior while it is deprecated and not removed yet, use the feature flag and the SPI option as shown below:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">bin/kc.[sh|bat] start --features-enabled offline-session-preloading --spi-user-sessions-infinispan-preload-offline-sessions-from-database=true</code></pre> </div> </div> <div class="paragraph"> <p>The API of <code>UserSessionProvider</code> deprecated the method <code>getOfflineUserSessionByBrokerSessionId(RealmModel realm, String brokerSessionId)</code>. Instead of this method, use <code>getOfflineUserSessionByBrokerUserIdStream(RealmModel, String brokerUserId)</code> to first get the sessions of a user, and then filter by the broker session ID as needed.</p> </div> </div> <div class="sect3"> <h4 id="infinispan-metrics-use-labels-for-cache-manager-and-cache-names"><a class="anchor" href="#infinispan-metrics-use-labels-for-cache-manager-and-cache-names"></a>Infinispan metrics use labels for cache manager and cache names</h4> <div class="paragraph"> <p>When enabling metrics for Keycloak&#8217;s embedded caches, the metrics now use labels for the cache manager and the cache names.</p> </div> <div class="listingblock"> <div class="title">Old metric example without labels</div> <div class="content"> <pre>vendor_cache_manager_keycloak_cache_sessions_statistics_approximate_entries_in_memory{cache="sessions",node="..."}</pre> </div> </div> <div class="listingblock"> <div class="title">New metric example with labels</div> <div class="content"> <pre>vendor_statistics_approximate_entries_in_memory{cache="sessions",cache_manager="keycloak",node="..."}</pre> </div> </div> <div class="paragraph"> <p>To revert the change for an installation, use a custom Infinispan XML configuration and change the configuration as follows:</p> </div> <div class="listingblock"> <div class="content"> <pre>&lt;metrics names-as-tags="false" /&gt;</pre> </div> </div> </div> <div class="sect3"> <h4 id="user-attribute-value-length-extension"><a class="anchor" href="#user-attribute-value-length-extension"></a>User attribute value length extension</h4> <div class="paragraph"> <p>As of this release, Keycloak supports storing and searching by user attribute values longer than 255 characters, which was previously a limitation.</p> </div> <div class="paragraph"> <p>In setups where users are allowed to update attributes, for example, via the account console, prevent denial of service attacks by adding validations. Ensure that no unmanaged attributes are allowed and all editable attributes have a validation that limits the input length.</p> </div> <div class="paragraph"> <p>For unmanaged attributes, the maximum length is 2048 characters. For managed attributes, the default maximum length is 2048 characters. Administrator can change this by adding a validator of type <code>length</code>.</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. Using longer attributes increases the memory that is consumed by the cache. 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 class="paragraph"> <p>This change adds new indexes on the tables <code>USER_ATTRIBUTE</code> and <code>FED_USER_ATTRIBUTE</code>. If those tables contain more than 300000 entries, Keycloak will skip the index creation by default during the automatic schema migration and instead log the SQL statement on the console during migration to be applied manually after Keycloak&#8217;s startup. See the <a href="https://www.keycloak.org/docs/26.0.6/upgrading/">Upgrading Guide</a> for details on how to configure a different limit.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> The newly added indexes <code>USER_ATTR_LONG_VALUES_LOWER_CASE</code> and <code>FED_USER_ATTR_LONG_VALUES_LOWER_CASE</code> may exceed the maximum limit of 30 characters set by Oracle, in case the database is running in compatibility mode. Since Oracle version 12.2, there is a support for longer index names. </td> </tr> </table> </div> <div class="sect4"> <h5 id="additional-migration-steps-for-ldap"><a class="anchor" href="#additional-migration-steps-for-ldap"></a>Additional migration steps for LDAP</h5> <div class="paragraph"> <p>This is for installations that match all the following criteria:</p> </div> <div class="ulist"> <ul> <li> <p>User attributes in the LDAP directory are larger than 2048 characters or binary attributes that are larger than 1500 bytes.</p> </li> <li> <p>The attributes are changed by admins or users via the admin console, the APIs or the account console.</p> </li> </ul> </div> <div class="paragraph"> <p>To be able to enable changing those attributes via UI and REST APIs, perform the following steps:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Declare the attributes identified above as managed attributes in the user profile of the realm.</p> </li> <li> <p>Define a <code>length</code> validator for each attribute added in the previous step specifying the desired minimum and maximum length of the attribute value. For binary values, add 33 percent to the expected binary length to count in the overhead for Keycloak&#8217;s internal base64 encoding of binary values.</p> </li> </ol> </div> </div> <div class="sect4"> <h5 id="additional-migration-steps-for-custom-user-storage-providers"><a class="anchor" href="#additional-migration-steps-for-custom-user-storage-providers"></a>Additional migration steps for custom user storage providers</h5> <div class="paragraph"> <p>This is for installations that match all the following criteria:</p> </div> <div class="ulist"> <ul> <li> <p>Running MariaDB or MySQL as a database for Keycloak.</p> </li> <li> <p>Entries in table <code>FED_USER_ATTRIBUTE</code> with contents in the <code>VALUE</code> column that are larger than 2048 characters. This table is used for custom user providers which have federation enabled.</p> </li> <li> <p>The long attributes are changed by admins or users via the admin console or the account console.</p> </li> </ul> </div> <div class="paragraph"> <p>To be able to enable changing those attributes via UI and REST APIs, perform the following steps:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Declare the attributes identified above as managed attributes in the user profile of the realm.</p> </li> <li> <p>Define a <code>length</code> validator for each attribute added in the previous step specifying the desired minimum and maximum length of the attribute value.</p> </li> </ol> </div> </div> </div> <div class="sect3"> <h4 id="the-admin-send-verify-email-api-now-uses-the-same-email-verification-template"><a class="anchor" href="#the-admin-send-verify-email-api-now-uses-the-same-email-verification-template"></a>The Admin send-verify-email API now uses the same email verification template</h4> <div class="listingblock"> <div class="content"> <pre>PUT /admin/realms/{realm}/users/{id}/send-verify-email</pre> </div> </div> <div class="paragraph"> <p>In this release, the API will use the <code>email-verification.ftl</code> template instead of <code>executeActions.ftl</code>.</p> </div> <div class="listingblock"> <div class="title">Before upgrading</div> <div class="content"> <pre>Perform the following action(s): Verify Email</pre> </div> </div> <div class="listingblock"> <div class="title">After upgrading</div> <div class="content"> <pre>Confirm validity of e-mail address email@example.org.</pre> </div> </div> <div class="paragraph"> <p>If you have customized the <code>executeActions.ftl</code> template to modify how users verify their email using this API, ensure that you transfer your modifications to the new template.</p> </div> <div class="paragraph"> <p>A new parameter called <code>lifespan</code> will be introduced to allow overriding of the default lifespan value (12 hours).</p> </div> <div class="paragraph"> <p>If you prefer the previous behavior, use the <code>execute-actions-email</code> API as follows.</p> </div> <div class="listingblock"> <div class="content"> <pre>PUT /admin/realms/{realm}/users/{id}/execute-actions-email ["VERIFY_EMAIL"]</pre> </div> </div> </div> <div class="sect3"> <h4 id="removal-of-the-deprecated-mode-for-saml-encryption"><a class="anchor" href="#removal-of-the-deprecated-mode-for-saml-encryption"></a>Removal of the deprecated mode for SAML encryption</h4> <div class="paragraph"> <p>The compatibility mode for SAML encryption introduced in version 21 is now removed. The system property <code>keycloak.saml.deprecated.encryption</code> is not managed anymore by the server. The clients which still used the old signing key for encryption should update it from the new IDP configuration metadata.</p> </div> </div> <div class="sect3"> <h4 id="changes-to-password-hashing-2"><a class="anchor" href="#changes-to-password-hashing-2"></a>Changes to Password Hashing</h4> <div class="paragraph"> <p>In this release, we adapted the password hashing defaults to match the <a href="https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2">OWASP recommendations for Password Storage</a>.</p> </div> <div class="paragraph"> <p>As part of this change, the default password hashing provider has changed from <code>pbkdf2-sha256</code> to <code>pbkdf2-sha512</code>. Also, the number of default hash iterations for <code>pbkdf2</code> based password hashing algorithms changed as follows:</p> </div> <table class="tableblock frame-all grid-all fit-content"> <colgroup> <col> <col> <col> <col> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Provider ID</th> <th class="tableblock halign-left valign-top">Algorithm</th> <th class="tableblock halign-right valign-top">Old Iterations</th> <th class="tableblock halign-right valign-top">New Iterations</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>pbkdf2</code></p> </div></div></td> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>PBKDF2WithHmacSHA1</code></p> </div></div></td> <td class="tableblock halign-right valign-top"><div class="content"><div class="paragraph"> <p>20.000</p> </div></div></td> <td class="tableblock halign-right valign-top"><div class="content"><div class="paragraph"> <p>1.300.000</p> </div></div></td> </tr> <tr> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>pbkdf2-sha256</code></p> </div></div></td> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>PBKDF2WithHmacSHA256</code></p> </div></div></td> <td class="tableblock halign-right valign-top"><div class="content"><div class="paragraph"> <p>27.500</p> </div></div></td> <td class="tableblock halign-right valign-top"><div class="content"><div class="paragraph"> <p>600.000</p> </div></div></td> </tr> <tr> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>pbkdf2-sha512</code></p> </div></div></td> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>PBKDF2WithHmacSHA512</code></p> </div></div></td> <td class="tableblock halign-right valign-top"><div class="content"><div class="paragraph"> <p>30.000</p> </div></div></td> <td class="tableblock halign-right valign-top"><div class="content"><div class="paragraph"> <p>210.000</p> </div></div></td> </tr> </tbody> </table> <div class="paragraph"> <p>If a realm does not explicitly configure a password policy with <code>hashAlgorithm</code> and <code>hashIterations</code>, then the new configuration will take effect on the next password based login, or when a user password is created or updated.</p> </div> <div class="sect4"> <h5 id="performance-of-new-password-hashing-configuration"><a class="anchor" href="#performance-of-new-password-hashing-configuration"></a>Performance of new password hashing configuration</h5> <div class="paragraph"> <p>Tests on a machine with an Intel i9-8950HK CPU (12) @ 4.800GHz yielded the following &#8960; time differences for hashing 1000 passwords (averages from 3 runs). Note that the average duration for the <code>PBKDF2WithHmacSHA1</code> was computed with a lower number of passwords due to the long runtime.</p> </div> <table class="tableblock frame-all grid-all fit-content"> <colgroup> <col> <col> <col> <col> <col> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Provider ID</th> <th class="tableblock halign-left valign-top">Algorithm</th> <th class="tableblock halign-right valign-top">Old duration</th> <th class="tableblock halign-right valign-top">New duration</th> <th class="tableblock halign-right valign-top">Difference</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>pbkdf2</code></p> </div></div></td> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>PBKDF2WithHmacSHA1</code></p> </div></div></td> <td class="tableblock halign-right valign-top"><div class="content"><div class="paragraph"> <p>122ms</p> </div></div></td> <td class="tableblock halign-right valign-top"><div class="content"><div class="paragraph"> <p>3.114ms</p> </div></div></td> <td class="tableblock halign-right valign-top"><div class="content"><div class="paragraph"> <p>+2.992ms</p> </div></div></td> </tr> <tr> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>pbkdf2-sha256</code></p> </div></div></td> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>PBKDF2WithHmacSHA256</code></p> </div></div></td> <td class="tableblock halign-right valign-top"><div class="content"><div class="paragraph"> <p>20ms</p> </div></div></td> <td class="tableblock halign-right valign-top"><div class="content"><div class="paragraph"> <p>451ms</p> </div></div></td> <td class="tableblock halign-right valign-top"><div class="content"><div class="paragraph"> <p>+431ms</p> </div></div></td> </tr> <tr> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>pbkdf2-sha512</code></p> </div></div></td> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p><code>PBKDF2WithHmacSHA512</code></p> </div></div></td> <td class="tableblock halign-right valign-top"><div class="content"><div class="paragraph"> <p>33ms</p> </div></div></td> <td class="tableblock halign-right valign-top"><div class="content"><div class="paragraph"> <p>224ms</p> </div></div></td> <td class="tableblock halign-right valign-top"><div class="content"><div class="paragraph"> <p>+191ms</p> </div></div></td> </tr> </tbody> </table> <div class="paragraph"> <p>Users of the <code>pbkdf2</code> provider might need to explicitly reduce the number of hash iterations to regain acceptable performance. This can be done by configuring the hash iterations explicitly in the password policy of the realm.</p> </div> </div> <div class="sect4"> <h5 id="expected-increased-overall-cpu-usage-and-temporary-increased-database-activity"><a class="anchor" href="#expected-increased-overall-cpu-usage-and-temporary-increased-database-activity"></a>Expected increased overall CPU usage and temporary increased database activity</h5> <div class="paragraph"> <p>The Concepts for sizing CPU and memory resources in the Keycloak High Availability guide have been updated to reflect the new hashing defaults. The CPU usage per password-based login in our tests increased by the factor of five, which includes both the changed password hashing and unchanged TLS connection handling. The overall CPU increase should be around the factor of two to three due to the averaging effect of Keycloak&#8217;s other activities like refreshing access tokens and client credential grants. Still, this depends on the unique workload of an installation.</p> </div> <div class="paragraph"> <p>After the upgrade, during a password-based login, the user&#8217;s passwords will be re-hashed with the new hash algorithm and hash iterations as a one-off activity and updated in the database. As this clears the user from Keycloak&#8217;s internal cache, you will also see an increased read activity on the database level. This increased database activity will decrease over time as more and more user&#8217;s passwords have been re-hashed.</p> </div> </div> <div class="sect4"> <h5 id="how-to-keep-using-the-old-pbkdf2-sha256-password-hashing"><a class="anchor" href="#how-to-keep-using-the-old-pbkdf2-sha256-password-hashing"></a>How to keep using the old pbkdf2-sha256 password hashing?</h5> <div class="paragraph"> <p>To keep the old password hashing for a realm, specify <code>hashAlgorithm</code> and <code>hashIterations</code> explicitly in the realm password policy.</p> </div> <div class="ulist"> <ul> <li> <p><code>Hashing Algorithm: pbkdf2-sha256</code></p> </li> <li> <p><code>Hashing Iterations: 27500</code></p> </li> </ul> </div> </div> </div> <div class="sect3"> <h4 id="operator-referenced-resource-polling"><a class="anchor" href="#operator-referenced-resource-polling"></a>Operator Referenced Resource Polling</h4> <div class="paragraph"> <p>Secrets and ConfigMaps referenced via the Keycloak CR will now be polled for changes, rather than watched via the api server. It may take around 1 minute for changes to be detected.</p> </div> <div class="paragraph"> <p>This was done so to not require label manipulation on those resources. After upgrading if any Secret still has the operator.keycloak.org/component label, it may be removed or ignored.</p> </div> </div> <div class="sect3"> <h4 id="renaming-jpa-provider-configuration-options-for-migration"><a class="anchor" href="#renaming-jpa-provider-configuration-options-for-migration"></a>Renaming JPA provider configuration options for migration</h4> <div class="paragraph"> <p>After removal of the Map Store the following configuration options were renamed:</p> </div> <div class="ulist"> <ul> <li> <p><code>spi-connections-jpa-legacy-initialize-empty</code> to <code>spi-connections-jpa-quarkus-initialize-empty</code></p> </li> <li> <p><code>spi-connections-jpa-legacy-migration-export</code> to <code>spi-connections-jpa-quarkus-migration-export</code></p> </li> <li> <p><code>spi-connections-jpa-legacy-migration-strategy</code> to <code>spi-connections-jpa-quarkus-migration-strategy</code></p> </li> </ul> </div> </div> <div class="sect3"> <h4 id="renaming-model-modules"><a class="anchor" href="#renaming-model-modules"></a>Renaming model modules</h4> <div class="paragraph"> <p>After removal of the Map Store the following modules were renamed:</p> </div> <div class="ulist"> <ul> <li> <p><code>org.keycloak:keycloak-model-legacy-private</code> to <code>org.keycloak:keycloak-model-storage-private</code></p> </li> <li> <p><code>org.keycloak:keycloak-model-legacy-services</code> to <code>org.keycloak:keycloak-model-storage-services</code></p> </li> </ul> </div> <div class="paragraph"> <p>and <code>org.keycloak:keycloak-model-legacy</code> module was deprecated and will be removed in the next release in favour of <code>org.keycloak:keycloak-model-storage</code> module.</p> </div> </div> <div class="sect3"> <h4 id="temporary-lockout-log-replaced-with-event"><a class="anchor" href="#temporary-lockout-log-replaced-with-event"></a>Temporary lockout log replaced with event</h4> <div class="paragraph"> <p>There is now a new event <code>USER_DISABLED_BY_TEMPORARY_LOCKOUT</code> when a user is temporarily locked out by the brute force protector. The log with ID <code>KC-SERVICES0053</code> has been removed as the new event offers the information in a structured form.</p> </div> <div class="paragraph"> <p>As it is a success event, the new event is logged by default at the <code>DEBUG</code> level. Use the setting <code>spi-events-listener-jboss-logging-success-level</code> as described in the <a href="https://www.keycloak.org/docs/26.0.6/server_admin/#event-listener">Event listener chapter in the Server Administration Guide</a> to change the log level of all success events.</p> </div> <div class="paragraph"> <p>To trigger custom actions or custom log entries, write a custom event listener as described in the Event Listener SPI in the <a href="https://www.keycloak.org/docs/26.0.6/server_development/">Server Developer Guide</a>.</p> </div> </div> <div class="sect3"> <h4 id="operator-customization-property-keys"><a class="anchor" href="#operator-customization-property-keys"></a>Operator Customization Property Keys</h4> <div class="paragraph"> <p>The property keys used by the operator for advanced configuration have changed from <code>operator.keycloak</code> to <code>kc.operator.keycloak</code>.</p> </div> </div> <div class="sect3"> <h4 id="keycloak-cr-resources-options"><a class="anchor" href="#keycloak-cr-resources-options"></a>Keycloak CR resources options</h4> <div class="paragraph"> <p>When no <code>resources</code> options are specified in the Keycloak CR and KeycloakRealmImport CR, default values are used. The default <code>requests</code> memory for Keycloak deployment and the realm import Job is set to <code>1700MiB</code>, and the <code>limits</code> memory is set to <code>2GiB</code>.</p> </div> </div> <div class="sect3"> <h4 id="updates-to-cookies"><a class="anchor" href="#updates-to-cookies"></a>Updates to cookies</h4> <div class="paragraph"> <p>As part of refactoring cookie handling in Keycloak there are some changes to how cookies are set:</p> </div> <div class="ulist"> <ul> <li> <p>All cookies will now have the secure attribute set if the request is through a secure context</p> </li> <li> <p><code>WELCOME_STATE_CHECKER</code> cookies now set <code>SameSite=Strict</code></p> </li> </ul> </div> <div class="paragraph"> <p>For custom extensions there may be some changes needed:</p> </div> <div class="ulist"> <ul> <li> <p><code>LocaleSelectorProvider.KEYCLOAK_LOCALE</code> is deprecated as cookies are now managed through the CookieProvider</p> </li> <li> <p><code>HttpResponse.setWriteCookiesOnTransactionComplete</code> has been removed</p> </li> <li> <p><code>HttpCookie</code> is deprecated, please use <code>NewCookie.Builder</code> instead</p> </li> <li> <p><code>ServerCookie</code> is deprecated, please use <code>NewCookie.Builder</code> instead</p> </li> </ul> </div> </div> <div class="sect3"> <h4 id="internal-algorithm-changed-from-hs256-to-hs512"><a class="anchor" href="#internal-algorithm-changed-from-hs256-to-hs512"></a>Internal algorithm changed from HS256 to HS512</h4> <div class="paragraph"> <p>The algorithm that Keycloak uses to sign internal tokens (a JWT which is consumed by Keycloak itself, for example a refresh or action token) is being changed from <code>HS256</code> to the more secure <code>HS512</code>. A new key provider named <code>hmac-generated-hs512</code> is now added for realms. Note that in migrated realms the old <code>hmac-generated</code> provider and the old <code>HS256</code> key are maintained and still validate tokens issued before the upgrade. The <code>HS256</code> provider can be manually deleted when no more old tokens exist following the <a href="https://www.keycloak.org/docs/26.0.6/server_admin/#rotating-keys">rotating keys guidelines</a>.</p> </div> </div> <div class="sect3"> <h4 id="different-jvm-memory-settings-when-running-in-a-container"><a class="anchor" href="#different-jvm-memory-settings-when-running-in-a-container"></a>Different JVM memory settings when running in a container</h4> <div class="paragraph"> <p>The JVM options <code>-Xms</code> and <code>-Xmx</code> were replaced by <code>-XX:InitialRAMPercentage</code> and <code>-XX:MaxRAMPercentage</code> when running in a container. Instead of the static maximum heap size settings, Keycloak specifies the maximum as 70% of the total container memory.</p> </div> <div class="paragraph"> <p>As the heap size is dynamically calculated based on the total container memory, you should <strong>always set the memory limit</strong> for the container.</p> </div> <div class="admonitionblock warning"> <table> <tr> <td class="icon"> <i class="fa icon-warning" title="Warning"></i> </td> <td class="content"> If the memory limit is not set, the memory consumption rapidly increases as the maximum heap size grows up to 70% of the total container memory. </td> </tr> </table> </div> <div class="paragraph"> <p>For more details, see the <a href="https://www.keycloak.org/server/containers#_specifying_different_memory_settings">Running Keycloak in a container</a> guide.</p> </div> </div> <div class="sect3"> <h4 id="gelf-log-handler-has-been-deprecated"><a class="anchor" href="#gelf-log-handler-has-been-deprecated"></a>GELF log handler has been deprecated</h4> <div class="paragraph"> <p>With sunsetting of the <a href="https://github.com/mp911de/logstash-gelf">underlying library</a> providing integration with GELF, Keycloak will no longer support the GELF log handler out-of-the-box. This feature will be removed in a future release. If you require an external log management, consider using file log parsing.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-23-0-5"><a class="anchor" href="#migrating-to-23-0-5"></a>Migrating to 23.0.5</h3> <div class="sect3"> <h4 id="changes-in-jboss-logging-event-messages"><a class="anchor" href="#changes-in-jboss-logging-event-messages"></a>Changes in jboss-logging event messages</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/changes/changes-23_0_5.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/changes/changes-23_0_5.adoc&amp;description=%0A%0AFile:%20upgrading/topics/changes/changes-23_0_5.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>Because of issue <a href="https://github.com/keycloak/keycloak/issues/25078">#25078</a>, the <code>jboss-logging</code> message values are now quoted (character <code>"</code> by default) and sanitized to prevent any line break. There are two new options in the provider (<code>spi-events-listener-jboss-logging-sanitize</code> and <code>spi-events-listener-jboss-logging-quotes</code>) that allow you to customize the new behavior. For example, to avoid both sanitization and quoting, the server can be started in this manner:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>./kc.sh start --spi-events-listener-jboss-logging-sanitize=false --spi-events-listener-jboss-logging-quotes=none ...</code></pre> </div> </div> <div class="paragraph"> <p>For more information about the options, see <a href="https://www.keycloak.org/server/all-provider-config#_jboss_logging">all provider configuration guide</a>.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-23-0-4"><a class="anchor" href="#migrating-to-23-0-4"></a>Migrating to 23.0.4</h3> <div class="sect3"> <h4 id="fix-handling-of-groups-getsubgroups-briefrepresentation-parameter"><a class="anchor" href="#fix-handling-of-groups-getsubgroups-briefrepresentation-parameter"></a>Fix handling of Groups.getSubGroups briefRepresentation parameter</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/changes/changes-23_0_4.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/changes/changes-23_0_4.adoc&amp;description=%0A%0AFile:%20upgrading/topics/changes/changes-23_0_4.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>Version 23.0.0 introduced a new endpoint getSubGroups ("children") on the Groups resource, where the meaning of the parameter briefRepresentation meant the retrieval of full representations of the sub groups. The meaning is now changed to return the brief representation.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-23-0-2"><a class="anchor" href="#migrating-to-23-0-2"></a>Migrating to 23.0.2</h3> <div class="sect3"> <h4 id="valid-redirect-uris-for-clients-are-always-compared-with-exact-string-matching"><a class="anchor" href="#valid-redirect-uris-for-clients-are-always-compared-with-exact-string-matching"></a>Valid redirect URIs for clients are always compared with exact string matching</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/changes/changes-23_0_2.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/changes/changes-23_0_2.adoc&amp;description=%0A%0AFile:%20upgrading/topics/changes/changes-23_0_2.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>Version 1.8.0 introduced a lower-case for the hostname and scheme when comparing a redirect URI with the specified valid redirects for a client. Unfortunately it did not fully work in all the protocols, and, for example, the host was lower-cased for <code>http</code> but not for <code>https</code>. As <a href="https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics#name-protecting-redirect-based-f">OAuth 2.0 Security Best Current Practice</a> advises to compare URIs using exact string matching, Keycloak will follow the recommendation and for now on valid redirects are compared with exact case even for the hostname and scheme.</p> </div> <div class="paragraph"> <p>For realms relying on the old behavior, the valid redirect URIs for their clients should now hold separate entries for each URI that should be recognized by the server.</p> </div> <div class="paragraph"> <p>Although it introduces more steps and verbosity when configuring clients, the new behavior enables more secure deployments as pattern-based checks are frequently the cause of security issues. These issues are due to how they are implemented and how they are configured.</p> </div> </div> <div class="sect3"> <h4 id="operator-secrets-store-secret"><a class="anchor" href="#operator-secrets-store-secret"></a>Operator -secrets-store Secret</h4> <div class="paragraph"> <p>Older versions of the operator created a Secret to track watched Secrets. Newer versions of the operator no longer use the -secrets-store Secret, so it may be deleted.</p> </div> <div class="paragraph"> <p>If you are on 23.0.0 or 23.0.1 and see "org.keycloak.operator.controllers.KeycloakAdminSecretDependentResource &#8594; java.lang.IllegalStateException: More than 1 secondary resource related to primary" in the operator log then either delete the -secrets-store Secret, or upgrade to 23.0.2 where this is no longer an issue.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-23-0-0"><a class="anchor" href="#migrating-to-23-0-0"></a>Migrating to 23.0.0</h3> <div class="sect3"> <h4 id="added-iss-parameter-to-oauth-2-0openid-connect-authentication-response"><a class="anchor" href="#added-iss-parameter-to-oauth-2-0openid-connect-authentication-response"></a>Added iss parameter to OAuth 2.0/OpenID Connect Authentication Response</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/changes/changes-23_0_0.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/changes/changes-23_0_0.adoc&amp;description=%0A%0AFile:%20upgrading/topics/changes/changes-23_0_0.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>RFC 9207 OAuth 2.0 Authorization Server Issuer Identification specification adds the parameter <code>iss</code> in the OAuth 2.0/OpenID Connect Authentication Response for realizing secure authorization responses.</p> </div> <div class="paragraph"> <p>In past releases, we did not have this parameter, but now Keycloak adds this parameter by default, as required by the specification.</p> </div> <div class="paragraph"> <p>However, some OpenID Connect / OAuth2 adapters, and especially older Keycloak adapters, may have issues with this new parameter.</p> </div> <div class="paragraph"> <p>For example, the parameter will be always present in the browser URL after successful authentication to the client application. In these cases, it may be useful to disable adding the <code>iss</code> parameter to the authentication response. This can be done for the particular client in the Keycloak Admin Console, in client details in the section with <code>OpenID Connect Compatibility Modes</code>, described in <a href="#_compatibility_with_older_adapters">Compatibility with older adapters</a>. Dedicated <code>Exclude Issuer From Authentication Response</code> switch exists, which can be turned on to prevent adding the <code>iss</code> parameter to the authentication response.</p> </div> </div> <div class="sect3"> <h4 id="wildcard-characters-handling"><a class="anchor" href="#wildcard-characters-handling"></a>Wildcard characters handling</h4> <div class="paragraph"> <p>JPA allows wildcards <code>%</code> and <code>_</code> when searching, while other providers like LDAP allow only <code>*</code>. As <code>*</code> is a natural wildcard character in LDAP, it works in all places, while with JPA it only worked at the beginning and the end of the search string. Starting with this release the only wildcard character is <code>*</code> which work consistently across all providers in all places in the search string. All special characters in a specific provider like <code>%</code> and <code>_</code> for JPA are escaped. For exact search, with added quotes such as <code>"w*ord"</code>, the behavior remains the same as in previous releases.</p> </div> </div> <div class="sect3"> <h4 id="language-files-for-themes-default-to-utf-8-encoding"><a class="anchor" href="#language-files-for-themes-default-to-utf-8-encoding"></a>Language files for themes default to UTF-8 encoding</h4> <div class="paragraph"> <p>This release now follows the standard mechanisms of Java and later, which assumes resource bundle files to be encoded in UTF-8.</p> </div> <div class="paragraph"> <p>Previous versions of Keycloak supported specifying the encoding in the first line with a comment like <code># encoding: UTF-8</code>, which is no longer supported and is ignored.</p> </div> <div class="paragraph"> <p>Message properties files for themes are now read in UTF-8 encoding, with an automatic fallback to ISO-8859-1 encoding. If you are using a different encoding, convert the files to UTF-8.</p> </div> </div> <div class="sect3"> <h4 id="changes-to-the-value-format-of-claims-mapped-by-the-realm-and-client-role-mappers"><a class="anchor" href="#changes-to-the-value-format-of-claims-mapped-by-the-realm-and-client-role-mappers"></a>Changes to the value format of claims mapped by the realm and client role mappers</h4> <div class="paragraph"> <p>Before this release, both realm (<code>User Realm Role</code>) and client (<code>User Client Role</code>) protocol mappers were mapping a stringfied JSON array when the <code>Multivalued</code> setting was disabled.</p> </div> <div class="paragraph"> <p>However, the <code>Multivalued</code> setting indicates whether the claim should be mapped as a list or, if disabled, only a single value from the same list of values.</p> </div> <div class="paragraph"> <p>In this release, the role and client mappers now map to a single value from the effective roles of a user when they are marked as single-valued (<code>Multivalued</code> disabled).</p> </div> </div> <div class="sect3"> <h4 id="changes-to-password-fields-in-login-ui"><a class="anchor" href="#changes-to-password-fields-in-login-ui"></a>Changes to password fields in Login UI</h4> <div class="paragraph"> <p>In this version we want to introduce a toggle to hide/show password inputs.</p> </div> <div class="ulist"> <div class="title">Affected pages:</div> <ul> <li> <p>login.ftl</p> </li> <li> <p>login-password.ftl</p> </li> <li> <p>login-update-password.ftl</p> </li> <li> <p>register.ftl</p> </li> <li> <p>register-user-profile.ftl</p> </li> </ul> </div> <div class="paragraph"> <p>In general all <code>&lt;input type="password" name="password" /&gt;</code> are encapsulated within a div now. The input element is followed by a button which toggles the visibility of the password input.</p> </div> <div class="paragraph"> <p>Old code example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="html"><span class="tag">&lt;input</span> <span class="attribute-name">type</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">password</span><span class="delimiter">&quot;</span></span> <span class="attribute-name">id</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">password</span><span class="delimiter">&quot;</span></span> <span class="attribute-name">name</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">password</span><span class="delimiter">&quot;</span></span> <span class="attribute-name">autocomplete</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">current-password</span><span class="delimiter">&quot;</span></span> <span class="attribute-name">style</span>=<span class="string"><span class="delimiter">&quot;</span><span class="key">display</span>:<span class="value">none</span>;<span class="delimiter">&quot;</span></span><span class="tag">/&gt;</span></code></pre> </div> </div> <div class="paragraph"> <p>New code example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="html"><span class="tag">&lt;div</span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">${properties.kcInputGroup!}</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span> <span class="tag">&lt;input</span> <span class="attribute-name">type</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">password</span><span class="delimiter">&quot;</span></span> <span class="attribute-name">id</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">password</span><span class="delimiter">&quot;</span></span> <span class="attribute-name">name</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">password</span><span class="delimiter">&quot;</span></span> <span class="attribute-name">autocomplete</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">current-password</span><span class="delimiter">&quot;</span></span> <span class="attribute-name">style</span>=<span class="string"><span class="delimiter">&quot;</span><span class="key">display</span>:<span class="value">none</span>;<span class="delimiter">&quot;</span></span><span class="tag">/&gt;</span> <span class="tag">&lt;button</span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">pf-c-button pf-m-control</span><span class="delimiter">&quot;</span></span> <span class="attribute-name">type</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">button</span><span class="delimiter">&quot;</span></span> <span class="attribute-name">aria-label</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">${msg('showPassword')}</span><span class="delimiter">&quot;</span></span> <span class="attribute-name">aria-controls</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">password</span><span class="delimiter">&quot;</span></span> <span class="attribute-name">data-password-toggle</span> <span class="attribute-name">data-label-show</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">${msg('showPassword')}</span><span class="delimiter">&quot;</span></span> <span class="attribute-name">data-label-hide</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">${msg('hidePassword')}</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span> <span class="tag">&lt;i</span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">fa fa-eye</span><span class="delimiter">&quot;</span></span> <span class="attribute-name">aria-hidden</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">true</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span><span class="tag">&lt;/i&gt;</span> <span class="tag">&lt;/button&gt;</span> <span class="tag">&lt;/div&gt;</span></code></pre> </div> </div> </div> <div class="sect3"> <h4 id="default-keycloak-cr-hostname"><a class="anchor" href="#default-keycloak-cr-hostname"></a>Default Keycloak CR Hostname</h4> <div class="paragraph"> <p>When running on OpenShift, with ingress enabled, and with the spec.ingress.classname set to openshift-default, you may leave the spec.hostname.hostname unpopulated in the Keycloak CR. The operator will assign a default hostname to the stored version of the CR similar to what would be created by an OpenShift Route without an explicit host - that is ingress-namespace.appsDomain If the appsDomain changes, or should you need a different hostname for any reason, then update the Keycloak CR.</p> </div> </div> <div class="sect3"> <h4 id="the-deprecated-auto-build-cli-option-was-removed"><a class="anchor" href="#the-deprecated-auto-build-cli-option-was-removed"></a>The deprecated <code>auto-build</code> CLI option was removed</h4> <div class="paragraph"> <p>The <code>auto-build</code> CLI option has been marked as deprecated for a long time. In this release, it was completely removed, and it is no longer supported.</p> </div> <div class="paragraph"> <p>When executing the <code>start</code> command, the server is automatically built based on the configuration. In order to prevent this behavior, set the <code>--optimized</code> flag.</p> </div> </div> <div class="sect3"> <h4 id="kc-sh-and-shell-metacharacters"><a class="anchor" href="#kc-sh-and-shell-metacharacters"></a>kc.sh and shell metacharacters</h4> <div class="paragraph"> <p>The kc.sh no longer uses an additional shell eval on parameters and the environment variables JAVA_OPTS_APPEND and JAVA_ADD_OPENS, thus the continued use of double escaping/quoting will result in the parameter being misunderstood. For example instead of</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>bin/kc.sh start --db postgres --db-username keycloak --db-url "\"jdbc:postgresql://localhost:5432/keycloak?ssl=false&amp;connectTimeout=30\"" --db-password keycloak --hostname localhost</code></pre> </div> </div> <div class="paragraph"> <p>Use a single escape:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>bin/kc.sh start --db postgres --db-username keycloak --db-url "jdbc:postgresql://localhost:5432/keycloak?ssl=false&amp;connectTimeout=30" --db-password keycloak --hostname localhost</code></pre> </div> </div> <div class="paragraph"> <p>This change also means you cannot invoke kc.sh using a single quoted value of all arguments. For example you can no longer use</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>bin/kc.sh "start --help"</code></pre> </div> </div> <div class="paragraph"> <p>it must instead be individual arguments</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>bin/kc.sh start --help</code></pre> </div> </div> <div class="paragraph"> <p>Similarly instead of</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>bin/kc.sh build "--db postgres"</code></pre> </div> </div> <div class="paragraph"> <p>it must instead be individual arguments</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>bin/kc.sh build --db postgres</code></pre> </div> </div> <div class="paragraph"> <p>The usage of individual arguments is also required in Dockerfile run commands.</p> </div> </div> <div class="sect3"> <h4 id="removed-registrationprofile-form-action"><a class="anchor" href="#removed-registrationprofile-form-action"></a>Removed RegistrationProfile form action</h4> <div class="paragraph"> <p>The form action <code>RegistrationProfile</code> (displayed in the UI of authentication flows as <code>Profile Validation</code>) was removed from the codebase and also from all authentication flows. By default, it was in the built-in registration flow of every realm. The validation of user attributes as well as creation of the user including all that user&#8217;s attributes is handled by <code>RegistrationUserCreation</code> form action and hence <code>RegistrationProfile</code> is not needed anymore. There is usually no further action needed in relation to this change, unless you used <code>RegistrationProfile</code> class in your own providers.</p> </div> </div> <div class="sect3"> <h4 id="deprecated-methods-from-data-providers-and-models"><a class="anchor" href="#deprecated-methods-from-data-providers-and-models"></a>Deprecated methods from data providers and models</h4> <div class="ulist"> <ul> <li> <p><code>RealmModel#getTopLevelGroupsStream()</code> and overloaded methods are now deprecated</p> </li> </ul> </div> </div> <div class="sect3"> <h4 id="groupprovider-changes"><a class="anchor" href="#groupprovider-changes"></a><code>GroupProvider</code> changes</h4> <div class="paragraph"> <p>A new method has been added to allow for searching and paging through top level groups. If you implement this interface you will need to implement the following method:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java">Stream&lt;GroupModel&gt; getTopLevelGroupsStream(RealmModel realm, <span class="predefined-type">String</span> search, <span class="predefined-type">Boolean</span> exact, <span class="predefined-type">Integer</span> firstResult, <span class="predefined-type">Integer</span> maxResults)</code></pre> </div> </div> </div> <div class="sect3"> <h4 id="grouprepresentation-changes"><a class="anchor" href="#grouprepresentation-changes"></a><code>GroupRepresentation</code> changes</h4> <div class="ulist"> <ul> <li> <p>new field <code>subGroupCount</code> added to inform client how many subgroups are on any given group</p> </li> <li> <p><code>subGroups</code> list is now only populated on queries that request hierarchy data</p> </li> <li> <p>This field is populated from the "bottom up" so cannot be relied on for getting all subgroups for a group. Use a <code>GroupProvider</code> or request the subgroups from <code>GET {keycloak server}/realms/{realm}/groups/{group_id}/children</code></p> </li> </ul> </div> </div> <div class="sect3"> <h4 id="new-endpoint-for-group-admin-api"><a class="anchor" href="#new-endpoint-for-group-admin-api"></a>New endpoint for Group Admin API</h4> <div class="paragraph"> <p>Endpoint <code>GET {keycloak server}/realms/{realm}/groups/{group_id}/children</code> added as a way to get subgroups of specific groups that support pagination</p> </div> </div> <div class="sect3"> <h4 id="resteeasy-reactive"><a class="anchor" href="#resteeasy-reactive"></a>RESTEeasy Reactive</h4> <div class="paragraph"> <p>Relying on RESTEasy Classic is not longer an option because it is not available anymore. Migration will be needed for SPI&#8217;s and code that is relying on RESTEasy Classic and related packages part of <code>org.jboss.resteasy.spi.*</code>.</p> </div> </div> <div class="sect3"> <h4 id="partial-export-requires-manage-realm-permission"><a class="anchor" href="#partial-export-requires-manage-realm-permission"></a>Partial export requires manage-realm permission</h4> <div class="paragraph"> <p>The endpoint <code>POST {keycloak server}/realms/{realm}/partial-export</code> and the corresponding action in the admin console now require <code>manage-realm</code> permission for execution instead of <code>view-realm</code>. This endpoint exports the realm configuration into a JSON file and the new permission is more appropriate. The parameters <code>exportGroupsAndRoles</code> and <code>exportClients</code>, which include the realm groups/roles and clients in the export respectively, continue managing the same permissions (<code>query-groups</code> and <code>view-clients</code>).</p> </div> </div> <div class="sect3"> <h4 id="removal-of-the-options-to-trim-the-events-details-length"><a class="anchor" href="#removal-of-the-options-to-trim-the-events-details-length"></a>Removal of the options to trim the event&#8217;s details length</h4> <div class="paragraph"> <p>Since this release, Keycloak supports long value for <code>EventEntity</code> details column. Therefore, it no longer supports options for trimming event detail length <code>--spi-events-store-jpa-max-detail-length</code> and <code>--spi-events-store-jpa-max-field-length</code>.</p> </div> </div> <div class="sect3"> <h4 id="user-profile-updates"><a class="anchor" href="#user-profile-updates"></a>User Profile updates</h4> <div class="paragraph"> <p>This release includes many fixes and updates that are related to user profile as we are working on promoting this feature from preview to officially supported. Minor changes exist for the SPI such as the newly added method <code>boolean isEnabled(RealmModel realm)</code> on <code>UserProfileProvider</code> interface. Also some user profile classes and some validator related classes (but not builtin validator implementations) were moved from <code>keycloak-server-spi-private</code> to <code>keycloak-server-spi</code> module. However, the packages for java classes remain the same. You might be affected in some corner cases, such as when you are overriding the built-in implementation with your own <code>UserProfileProvider</code> implementation. However, note that <code>UserProfileProvider</code> is an unsupported SPI.</p> </div> </div> <div class="sect3"> <h4 id="removal-of-the-map-store"><a class="anchor" href="#removal-of-the-map-store"></a>Removal of the Map Store</h4> <div class="paragraph"> <p>The Map Store has been an experimental feature in previous releases. Starting with this release, it is removed and users should continue to use the current JPA store.</p> </div> <div class="paragraph"> <p>Since this release, it is no longer possible to use <code>--storage</code> related CLI options. The modules <code>keycloak-model-map*</code> have been removed.</p> </div> </div> <div class="sect3"> <h4 id="removed-namespaces-from-our-translations"><a class="anchor" href="#removed-namespaces-from-our-translations"></a>Removed namespaces from our translations</h4> <div class="paragraph"> <p>All translations are moved into one file for the Admin Console. If you have made your own translations or extended the Admin Console you will need to migrate them to this new format. Also if you have "overrides" in your database, you will have to remove the namespace from the keys. Some keys are the same only in different namespaces, this is most obvious to help. In these cases we have postfix the key with <code>Help</code>.</p> </div> <div class="paragraph"> <p>If you want you can use this node script to help with the migration. It will take all the single files and put them into a new one and also take care of some of the mapping:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="js"><span class="reserved">import</span> { readFileSync, writeFileSync, appendFileSync } from <span class="string"><span class="delimiter">&quot;</span><span class="content">node:fs</span><span class="delimiter">&quot;</span></span>; const ns = [ <span class="string"><span class="delimiter">&quot;</span><span class="content">common</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">common-help</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">dashboard</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">clients</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">clients-help</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">client-scopes</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">client-scopes-help</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">groups</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">realm</span><span class="delimiter">&quot;</span></span>, <span class="string"><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">users</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">users-help</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">sessions</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">events</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">realm-settings</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">realm-settings-help</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">authentication</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">authentication-help</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">user-federation</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">user-federation-help</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">identity-providers</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">identity-providers-help</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">dynamic</span><span class="delimiter">&quot;</span></span>, ]; const map = <span class="keyword">new</span> Map(); const dup = []; ns.forEach((n) =&gt; { const rawData = readFileSync(n + <span class="string"><span class="delimiter">&quot;</span><span class="content">.json</span><span class="delimiter">&quot;</span></span>); const translation = JSON.parse(rawData); Object.entries(translation).map((e) =&gt; { const name = e[<span class="integer">0</span>]; const value = e[<span class="integer">1</span>]; <span class="keyword">if</span> (map.has(name) &amp;&amp; map.get(name) !== value) { <span class="keyword">if</span> (n.includes(<span class="string"><span class="delimiter">&quot;</span><span class="content">help</span><span class="delimiter">&quot;</span></span>)) { map.set(name + <span class="string"><span class="delimiter">&quot;</span><span class="content">Help</span><span class="delimiter">&quot;</span></span>, value); } <span class="keyword">else</span> { map.set(name, value); dup.push({ <span class="key">name</span>: name, <span class="key">value</span>: map.get(name), <span class="key">dup</span>: { <span class="key">ns</span>: n, <span class="key">value</span>: value }, }); } } <span class="keyword">else</span> { map.set(name, value); } }); }); writeFileSync( <span class="string"><span class="delimiter">&quot;</span><span class="content">translation.json</span><span class="delimiter">&quot;</span></span>, JSON.stringify(Object.fromEntries(map.entries()), <span class="predefined-constant">undefined</span>, <span class="integer">2</span>), ); const mapping = [ [<span class="string"><span class="delimiter">&quot;</span><span class="content">common:clientScope</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">clientScopeType</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">identity-providers:createSuccess</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">createIdentityProviderSuccess</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">identity-providers:createError</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">createIdentityProviderError</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">clients:createError</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">createClientError</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">clients:createSuccess</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">createClientSuccess</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">user-federation:createSuccess</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">createUserProviderSuccess</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">user-federation:createError</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">createUserProviderError</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">authentication-help:name</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">flowNameHelp</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">authentication-help:description</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">flowDescriptionHelp</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">clientScopes:noRoles</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">noRoles-clientScope</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">clientScopes:noRolesInstructions</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">noRolesInstructions-clientScope</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">users:noRoles</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">noRoles-user</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">users:noRolesInstructions</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">noRolesInstructions-user</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">clients:noRoles</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">noRoles-client</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">clients:noRolesInstructions</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">noRolesInstructions-client</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">groups:noRoles</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">noRoles-group</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">groups:noRolesInstructions</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">noRolesInstructions-group</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">roles:noRoles</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">noRoles-roles</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">roles:noRolesInstructions</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">noRolesInstructions-roles</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">realm:realmName:</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">realmNameField</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">client-scopes:searchFor</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">searchForClientScope</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">roles:searchFor</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">searchForRoles</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">authentication:title</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">titleAuthentication</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">events:title</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">titleEvents</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">roles:title</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">titleRoles</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">users:title</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">titleUsers</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">sessions:title</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">titleSessions</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">client-scopes:deleteConfirm</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">deleteConfirmClientScopes</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">users:deleteConfirm</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">deleteConfirmUsers</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">groups:deleteConfirm_one</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">deleteConfirmGroup_one</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">groups:deleteConfirm_other</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">deleteConfirmGroup_other</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">identity-providers:deleteConfirm</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">deleteConfirmIdentityProvider</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">realm-settings:deleteConfirm</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">deleteConfirmRealmSetting</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">roles:whoWillAppearLinkText</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">whoWillAppearLinkTextRoles</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">users:whoWillAppearLinkText</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">whoWillAppearLinkTextUsers</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">roles:whoWillAppearPopoverText</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">whoWillAppearPopoverTextRoles</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">users:whoWillAppearPopoverText</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">whoWillAppearPopoverTextUsers</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">client-scopes:deletedSuccess</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">deletedSuccessClientScope</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">identity-providers:deletedSuccess</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">deletedSuccessIdentityProvider</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">realm-settings:deleteSuccess</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">deletedSuccessRealmSetting</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">client-scopes:deleteError</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">deletedErrorClientScope</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">identity-providers:deleteError</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">deletedErrorIdentityProvider</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">realm-settings:deleteError</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">deletedErrorRealmSetting</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">realm-settings:saveSuccess</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">realmSaveSuccess</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">user-federation:saveSuccess</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">userProviderSaveSuccess</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">realm-settings:saveError</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">realmSaveError</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">user-federation:saveError</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">userProviderSaveError</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">realm-settings:validateName</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">validateAttributeName</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">identity-providers:disableConfirm</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">disableConfirmIdentityProvider</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">realm-settings:disableConfirm</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">disableConfirmRealm</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">client-scopes:updateSuccess</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">updateSuccessClientScope</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">client-scopes:updateError</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">updateErrorClientScope</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">identity-providers:updateSuccess</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">updateSuccessIdentityProvider</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">identity-providers:updateError</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">updateErrorIdentityProvider</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">user-federation:orderChangeSuccess</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">orderChangeSuccessUserFed</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">user-federation:orderChangeError</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">orderChangeErrorUserFed</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">authentication-help:alias</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">authenticationAliasHelp</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">authentication-help:flowType</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">authenticationFlowTypeHelp</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">authentication:createFlow</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">authenticationCreateFlowHelp</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">client-scopes-help:rolesScope</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">clientScopesRolesScope</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">client-scopes-help:name</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">scopeNameHelp</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">client-scopes-help:description</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">scopeDescriptionHelp</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">client-scopes-help:type</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">scopeTypeHelp</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">clients-help:description</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">clientDescriptionHelp</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">clients-help:clientType</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">clientsClientTypeHelp</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">clients-help:scopes</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">clientsClientScopesHelp</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">common:clientScope</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">clientScopeTypes</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">dashboard:realmName</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">realmNameTitle</span><span class="delimiter">&quot;</span></span>], [<span class="string"><span class="delimiter">&quot;</span><span class="content">common:description</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">description</span><span class="delimiter">&quot;</span></span>], ]; mapping.forEach((m) =&gt; { const key = m[<span class="integer">0</span>].split(<span class="string"><span class="delimiter">&quot;</span><span class="content">:</span><span class="delimiter">&quot;</span></span>); <span class="keyword">try</span> { const data = readFileSync(key[<span class="integer">0</span>] + <span class="string"><span class="delimiter">&quot;</span><span class="content">.json</span><span class="delimiter">&quot;</span></span>); const translation = JSON.parse(data); const value = translation[key[<span class="integer">1</span>]]; <span class="keyword">if</span> (value) { appendFileSync( <span class="string"><span class="delimiter">&quot;</span><span class="content">translation.json</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">'</span><span class="content">&quot;</span><span class="delimiter">'</span></span> + m[<span class="integer">1</span>] + <span class="string"><span class="delimiter">'</span><span class="content">&quot;: </span><span class="delimiter">'</span></span> + JSON.stringify(value) + <span class="string"><span class="delimiter">'</span><span class="content">,</span><span class="content">\n</span><span class="delimiter">'</span></span>, ); } } <span class="keyword">catch</span> (error) { console.error(<span class="string"><span class="delimiter">&quot;</span><span class="content">skipping namespace key: </span><span class="delimiter">&quot;</span></span> + key); } });</code></pre> </div> </div> <div class="paragraph"> <p>Save this into a file called <code>transform.mjs</code> in your <code>public/locale/&lt;language&gt;</code> folder and run it with:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>node ./transform.mjs</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"> This might not do a complete transform, but very close to it. </td> </tr> </table> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-22-0-4"><a class="anchor" href="#migrating-to-22-0-4"></a>Migrating to 22.0.4</h3> <div class="sect3"> <h4 id="a-new-parameter-for-specify-max-length-of-email-local-part"><a class="anchor" href="#a-new-parameter-for-specify-max-length-of-email-local-part"></a>A new parameter for specify max length of email local part</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/changes/changes-22_0_4.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/changes/changes-22_0_4.adoc&amp;description=%0A%0AFile:%20upgrading/topics/changes/changes-22_0_4.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 new parameter <code>--spi-user-profile-declarative-user-profile-max-email-local-part-length</code> is added to set max email local part length taking backwards compatibility into consideration. The default value is 64. Example of usage:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>kc.[sh|bat] start --spi-user-profile-declarative-user-profile-max-email-local-part-length=100 ...</code></pre> </div> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-22-0-2"><a class="anchor" href="#migrating-to-22-0-2"></a>Migrating to 22.0.2</h3> <div class="sect3"> <h4 id="never-expires-option-removed-from-client-advanced-settings-combos"><a class="anchor" href="#never-expires-option-removed-from-client-advanced-settings-combos"></a>Never expires option removed from client advanced settings combos</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/changes/changes-22_0_2.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/changes/changes-22_0_2.adoc&amp;description=%0A%0AFile:%20upgrading/topics/changes/changes-22_0_2.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 option <code>Never expires</code> is now removed from all the combos of the Advanced Settings client tab. This option was misleading because the different lifespans or idle timeouts were never infinite, but limited by the general user session or realm values. Therefore, this option is removed in favor of the other two remaining options: <code>Inherits from the realm settings</code> (the client uses general realm timeouts) and <code>Expires in</code> (the value is overridden for the client). Internally the <code>Never expires</code> was represented by <code>-1</code>. Now that value is shown with a warning in the Admin Console and cannot be set directly by the administrator.</p> </div> </div> <div class="sect3"> <h4 id="new-linkedin-openid-connect-social-provider"><a class="anchor" href="#new-linkedin-openid-connect-social-provider"></a>New LinkedIn OpenID Connect social provider</h4> <div class="paragraph"> <p>A new social identity provider called <strong>LinkedIn OpenID Connect</strong> has been introduced for the business and employment-focused platform. LinkedIn released recently a new product for developers called <a href="https://learn.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/sign-in-with-linkedin-v2">Sign In with LinkedIn using OpenID Connect</a>. The product provides a new way to authenticate members using OpenID Connect, but the default <strong>OpenID Connect v1.0</strong> identity provider does not work with it at present time. For that reason, Keycloak adds this new identity provider as the specific social provider for the new product.</p> </div> <div class="paragraph"> <p>The old LinkedIn way based on OAuth seems to be completely removed from the <a href="https://developer.linkedin.com">developer portal</a>. How the existing LinkedIn social provider is working with current applications is not clear. Keycloak maintains the old provider renamed to <strong>LinkedIn (deprecated)</strong>, but in a deprecated feature called <strong>linkedin-oauth</strong> which is disabled by default. It will be removed in future versions. Please enable it again at startup if needed:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>kc.[sh|bat] start --features linkedin-oauth ...</code></pre> </div> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-22-0-0"><a class="anchor" href="#migrating-to-22-0-0"></a>Migrating to 22.0.0</h3> <div class="sect3"> <h4 id="transition-from-java-ee-to-jakarta-ee"><a class="anchor" href="#transition-from-java-ee-to-jakarta-ee"></a>Transition from Java EE to Jakarta EE</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/changes/changes-22_0_0.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/changes/changes-22_0_0.adoc&amp;description=%0A%0AFile:%20upgrading/topics/changes/changes-22_0_0.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 migrated its codebase from Java EE (Enterprise Edition) to its successor Jakarta EE, which brings various changes into Keycloak.</p> </div> <div class="paragraph"> <p>We have upgraded all Jakarta EE specifications in order to support Jakarta EE 10, such as:</p> </div> <div class="ulist"> <ul> <li> <p>Jakarta Persistence 3.1</p> </li> <li> <p>Jakarta RESTful Web Services 3.1</p> </li> <li> <p>Jakarta Mail API 2.1</p> </li> <li> <p>Jakarta Servlet 6.0</p> </li> <li> <p>Jakarta Activation 2.1</p> </li> </ul> </div> <div class="paragraph"> <p>Jakarta EE 10 provides a modernized, simplified, lightweight approach to building cloud-native Java applications. The main changes provided within this initiative are changing the namespace from <code>javax.*</code> to <code>jakarta.*</code>. It does not apply for <code>javax.*</code> packages provided directly in the JDK, such as <code>javax.security</code>, <code>javax.net</code>, <code>javax.crypto</code>, etc.</p> </div> <div class="paragraph"> <p>You can be affected by these changes in your custom extensions, providers or JPA entities.</p> </div> </div> <div class="sect3"> <h4 id="upgrade-to-quarkus-3"><a class="anchor" href="#upgrade-to-quarkus-3"></a>Upgrade to Quarkus 3</h4> <div class="paragraph"> <p>Keycloak upgraded to version 3 of the Quarkus Java framework. Quarkus 3 continues the tradition of propelling Java development by moving fast and providing a cutting-edge user experience with the latest technologies. It continues to improve overall performance and efficiency.</p> </div> <div class="paragraph"> <p>Quarkus 3 is based on Jakarta EE 10, the same as Keycloak, creating smooth interoperability between them. In addition, it contains Eclipse MicroProfile 6, which aligns with Jakarta EE 10 Core Profile. The central part of the Quarkus 3 upgrade is built-in support for JPA 3.1 and Hibernate ORM 6.</p> </div> <div class="sect4"> <h5 id="quarkus-hibernate-orm-properties-no-longer-working"><a class="anchor" href="#quarkus-hibernate-orm-properties-no-longer-working"></a><code>quarkus.hibernate-orm.*</code> properties no longer working</h5> <div class="paragraph"> <p>For Quarkus 3, Hibernate ORM configurations must be specified in either the <code>persistence.xml</code> file or in Quarkus properties, but not in both places. Keycloak uses a <code>persistence.xml</code> file, therefore, it is no longer possible to override Keycloak&#8217;s JPA store configurations via Quarkus&#8217; configuration properties for the default persistence unit whose names start with <code>quarkus.hibernate-orm</code>.</p> </div> </div> </div> <div class="sect3"> <h4 id="upgrade-to-hibernate-orm-6"><a class="anchor" href="#upgrade-to-hibernate-orm-6"></a>Upgrade to Hibernate ORM 6</h4> <div class="paragraph"> <p>Keycloak now benefits from the upgrade to Hibernate ORM 6.2, which includes improved performance, better SQL, modern JDK support, and support for modern RDBMS features. The performance improvements primarily affect JDBC, HQL Translation, and Criteria Translation.</p> </div> <div class="paragraph"> <p>If you have custom providers or JPA entities, these changes may affect you.</p> </div> <div class="paragraph"> <p>We recommend reviewing the <a href="https://github.com/quarkusio/quarkus/wiki/Migration-Guide-3.0:-Hibernate-ORM-5-to-6-migration">Quarkus migration guide</a> or the <a href="https://hibernate.org/orm/releases/">Hibernate release notes</a> for more information.</p> </div> </div> <div class="sect3"> <h4 id="legacy-promise-api-removed-from-keycloak-js-adapter"><a class="anchor" href="#legacy-promise-api-removed-from-keycloak-js-adapter"></a>Legacy Promise API removed from Keycloak JS adapter</h4> <div class="paragraph"> <p>The legacy Promise API methods have been removed from the Keycloak JS adapter. This means that calling <code>.success()</code> and <code>.error()</code> on promises returned from the adapter is no longer possible. Instead standardized Promise methods such as <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then"><code>.then()</code></a> and <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch"><code>.catch()</code></a> should be used.</p> </div> <div class="listingblock"> <div class="title">Before migration:</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="javascript">const keycloak = <span class="keyword">new</span> Keycloak(); keycloak.init() .success(<span class="keyword">function</span>(authenticated) { alert(authenticated ? <span class="string"><span class="delimiter">'</span><span class="content">authenticated</span><span class="delimiter">'</span></span> : <span class="string"><span class="delimiter">'</span><span class="content">not authenticated</span><span class="delimiter">'</span></span>); }).error(<span class="keyword">function</span>() { alert(<span class="string"><span class="delimiter">'</span><span class="content">failed to initialize</span><span class="delimiter">'</span></span>); });</code></pre> </div> </div> <div class="listingblock"> <div class="title">After migration:</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="javascript">const keycloak = <span class="keyword">new</span> Keycloak(); keycloak.init() .then(<span class="keyword">function</span>(authenticated) { alert(authenticated ? <span class="string"><span class="delimiter">'</span><span class="content">authenticated</span><span class="delimiter">'</span></span> : <span class="string"><span class="delimiter">'</span><span class="content">not authenticated</span><span class="delimiter">'</span></span>); }).<span class="keyword">catch</span>(<span class="keyword">function</span>() { alert(<span class="string"><span class="delimiter">'</span><span class="content">failed to initialize</span><span class="delimiter">'</span></span>); });</code></pre> </div> </div> <div class="listingblock"> <div class="title">Or alternatively, when using the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await"><code>await</code></a> keyword to unwrap these promises:</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="javascript">const keycloak = <span class="keyword">new</span> Keycloak(); <span class="keyword">try</span> { const authenticated = await keycloak.init(); alert(authenticated ? <span class="string"><span class="delimiter">'</span><span class="content">authenticated</span><span class="delimiter">'</span></span> : <span class="string"><span class="delimiter">'</span><span class="content">not authenticated</span><span class="delimiter">'</span></span>); } <span class="keyword">catch</span> (error) { alert(<span class="string"><span class="delimiter">'</span><span class="content">failed to initialize</span><span class="delimiter">'</span></span>); }</code></pre> </div> </div> </div> <div class="sect3"> <h4 id="export-and-import-perform-an-automatic-build"><a class="anchor" href="#export-and-import-perform-an-automatic-build"></a>Export and Import perform an automatic build</h4> <div class="paragraph"> <p>In previous releases, the <code>export</code> and <code>import</code> commands required a <code>build</code> command to be run first. Starting with this release, the <code>export</code> and <code>import</code> commands perform an automatic rebuild of Keycloak if a build time configuration has changed.</p> </div> <div class="paragraph"> <p>When migrating existing scripts that run a <code>build</code> command first, migrate by adding the <code>--optimized</code> command line option to the <code>export</code> and <code>import</code> command to avoid Keycloak automatically re-building the image. Not adding the <code>--optimized</code> option in this might make Keycloak trigger a rebuild and revert to the default values, and then connecting to the database for export and import will not work.</p> </div> <div class="paragraph"> <p>The following examples assume that runtime parameters like a database password are provided via a configuration file or an environment variable.</p> </div> <div class="listingblock"> <div class="title">Before migration: Running the build command before running the export command</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">bin/kc.[sh|bat] build --db=postgres ... bin/kc.[sh|bat] export --dir &lt;dir&gt;</code></pre> </div> </div> <div class="listingblock"> <div class="title">After migration: Adding <code>--optimized</code> to the export command</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">bin/kc.[sh|bat] build --db=postgres ... bin/kc.[sh|bat] export <mark>--optimized</mark> --dir &lt;dir&gt;</code></pre> </div> </div> <div class="listingblock"> <div class="title">After migration: Leveraging the auto-build functionality</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">bin/kc.[sh|bat] export --dir &lt;dir&gt; --db=postgres ...</code></pre> </div> </div> <div class="dlist"> <dl> <dt class="hdlist1">NOTE</dt> <dd> <p>When the auto-build runs, the build time options will be in effect for all subsequent commands that are started with the <code>--optimized</code> flag, including the <code>start</code> command.</p> </dd> </dl> </div> <div class="paragraph"> <p>In previous releases the <code>export</code> and <code>import</code> commands allowed runtime parameters such as a database URL only in configuration files or environment variables. Starting with this release, those runtime parameters are now available on the command line as well. Use the <code>--help</code> option to find out about the supported parameters.</p> </div> </div> <div class="sect3"> <h4 id="renamed-keycloak-admin-client-artifacts"><a class="anchor" href="#renamed-keycloak-admin-client-artifacts"></a>Renamed Keycloak Admin client artifacts</h4> <div class="paragraph"> <p>After the upgrade to Jakarta EE, artifacts for Keycloak Admin clients were renamed to more descriptive names with consideration for long-term maintainability. We still provide two separate Keycloak Admin clients, one with Jakarta EE and the other with Java EE support.</p> </div> <div class="paragraph"> <p>We stopped releasing the <code>org.keycloak:keycloak-admin-client-jakarta</code> artifact. The default one for the Keycloak Admin client with Jakarta EE support is <code>org.keycloak:keycloak-admin-client</code> (since version 22.0.0).</p> </div> <div class="paragraph"> <p>The new artifact with Java EE support is <code>org.keycloak:keycloak-admin-client-jee</code>.</p> </div> <div class="sect4"> <h5 id="jakarta-ee-support"><a class="anchor" href="#jakarta-ee-support"></a>Jakarta EE support</h5> <div class="listingblock"> <div class="title">Before migration:</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;dependency&gt;</span> <span class="tag">&lt;groupId&gt;</span>org.keycloak<span class="tag">&lt;/groupId&gt;</span> <span class="tag">&lt;artifactId&gt;</span>keycloak-admin-client-jakarta<span class="tag">&lt;/artifactId&gt;</span> <span class="tag">&lt;version&gt;</span>21.0.0<span class="tag">&lt;/version&gt;</span> <span class="tag">&lt;/dependency&gt;</span></code></pre> </div> </div> <div class="listingblock"> <div class="title">After migration:</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;dependency&gt;</span> <span class="tag">&lt;groupId&gt;</span>org.keycloak<span class="tag">&lt;/groupId&gt;</span> <span class="tag">&lt;artifactId&gt;</span>keycloak-admin-client<span class="tag">&lt;/artifactId&gt;</span> <span class="tag">&lt;version&gt;</span>22.0.0<span class="tag">&lt;/version&gt;</span> <span class="tag">&lt;/dependency&gt;</span></code></pre> </div> </div> </div> <div class="sect4"> <h5 id="java-ee-support"><a class="anchor" href="#java-ee-support"></a>Java EE support</h5> <div class="listingblock"> <div class="title">Before migration:</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;dependency&gt;</span> <span class="tag">&lt;groupId&gt;</span>org.keycloak<span class="tag">&lt;/groupId&gt;</span> <span class="tag">&lt;artifactId&gt;</span>keycloak-admin-client<span class="tag">&lt;/artifactId&gt;</span> <span class="tag">&lt;version&gt;</span>21.0.0<span class="tag">&lt;/version&gt;</span> <span class="tag">&lt;/dependency&gt;</span></code></pre> </div> </div> <div class="listingblock"> <div class="title">After migration:</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;dependency&gt;</span> <span class="tag">&lt;groupId&gt;</span>org.keycloak<span class="tag">&lt;/groupId&gt;</span> <span class="tag">&lt;artifactId&gt;</span>keycloak-admin-client-jee<span class="tag">&lt;/artifactId&gt;</span> <span class="tag">&lt;version&gt;</span>22.0.0<span class="tag">&lt;/version&gt;</span> <span class="tag">&lt;/dependency&gt;</span></code></pre> </div> </div> </div> </div> <div class="sect3"> <h4 id="passthrough-proxy-mode-changes"><a class="anchor" href="#passthrough-proxy-mode-changes"></a>Passthrough proxy mode changes</h4> <div class="paragraph"> <p>Keycloak&#8217;s proxy configuration setting for mode <strong>passthrough</strong> no longer parses HTTP forwarding headers in the request, as when a proxy forwards an HTTPS connection in passthrough mode, a proxy is unable to add, remove or update HTTP headers.</p> </div> <div class="paragraph"> <p>Installations that want the HTTP headers in the client&#8217;s request to be parsed should use the <strong>edge</strong> or <strong>reencrypt</strong> setting.</p> </div> <div class="paragraph"> <p>See <a href="https://www.keycloak.org/server/reverseproxy">Using a reverse proxy</a> for details.</p> </div> </div> <div class="sect3"> <h4 id="consistent-fallback-message-resolving-for-all-themes"><a class="anchor" href="#consistent-fallback-message-resolving-for-all-themes"></a>Consistent fallback message resolving for all themes</h4> <div class="paragraph"> <p>This change only may affect you when you are using realm localization messages.</p> </div> <div class="paragraph"> <p>Up to this version, the resolving of fallback messages was inconsistent across themes, when realm localization messages were used. More information can be found in the following <a href="https://github.com/keycloak/keycloak/issues/15845">issue</a>.</p> </div> <div class="paragraph"> <p>The implementation has now been unified for all themes. In general, the message for the most specific matching language tag has the highest priority. If there are both a realm localization message and a Theme 18n message, the realm localization message has the higher priority. Summarized, the priority of the messages is as follows (RL = realm localization, T = Theme i18n files): <code>RL &lt;variant&gt; &gt; T &lt;variant&gt; &gt; RL &lt;region&gt; &gt; T &lt;region&gt; &gt; RL &lt;language&gt; &gt; T &lt;language&gt; &gt; RL en &gt; T en</code>.</p> </div> <div class="paragraph"> <p>Probably this can be better explained with an example: When the variant <code>de-CH-1996</code> is requested and there is a realm localization message for the variant, this message will be used. If such a realm localization message does not exist, the Theme i18n files are searched for a corresponding message for that variant. If such a message does not exist, a realm localization message for the region (<code>de-CH</code>) will be searched. If such a realm localization message does not exist, the Theme i18n files are searched for a message for that region. If still no message is found, a realm localization message for the language (<code>de</code>) will be searched. If there is no matching realm localization message, the Theme i18n files are be searched for a message for that language. As last fallback, the English (<code>en</code>) translation is used: First, an English realm localization will be searched - if not found, the Theme 18n files are searched for an English message.</p> </div> </div> <div class="sect3"> <h4 id="userqueryprovider-changes"><a class="anchor" href="#userqueryprovider-changes"></a><code>UserQueryProvider</code> changes</h4> <div class="paragraph"> <p><code>UserQueryProvider</code> interface was split into two. One is <code>UserQueryMethodsProvider</code> providing capabilities for querying users. Second one is <code>UserCountMethodsProvider</code> which provides capability for counting number of users in particular storage.</p> </div> <div class="paragraph"> <p>Keycloak now has the ability to differentiate between user storage providers that can efficiently execute count queries and those that cannot. The <code>UserQueryProvider</code> interface still exists and extends both new interfaces. Therefore, there is no need for any modifications in the existing implementations of <code>UserQueryProvider</code> since it retains the same methods.</p> </div> </div> <div class="sect3"> <h4 id="ldapstorageprovider-search-changes"><a class="anchor" href="#ldapstorageprovider-search-changes"></a><code>LDAPStorageProvider</code> search changes</h4> <div class="paragraph"> <p>Starting with this release Keycloak uses a pagination mechanism when querying federated LDAP database. Searching for users should be consistent with search in local database.</p> </div> <div class="paragraph"> <p>Since this release <code>LDAPStorageProvider</code> implements only <code>UserQueryMethodsProvider</code>, not <code>UserQueryProvider</code>.</p> </div> </div> <div class="sect3"> <h4 id="deprecation-of-keycloak-openid-connect-adapters"><a class="anchor" href="#deprecation-of-keycloak-openid-connect-adapters"></a>Deprecation of Keycloak OpenID Connect Adapters</h4> <div class="paragraph"> <p>Starting with this release, we no longer will invest our time on the following Keycloak OpenID Connect Adapters:</p> </div> <div class="ulist"> <ul> <li> <p>Keycloak Wildfly OpenID Connect Adapter</p> </li> <li> <p>Keycloak JEE Servlet OpenID Connect Adapter</p> </li> <li> <p>Keycloak Spring Boot and Spring Security OpenID Connect Adapter</p> </li> </ul> </div> <div class="paragraph"> <p>This move is already reflected in our documentation and in our quickstart repository. Please, consider looking at the following references for more information:</p> </div> <div class="ulist"> <ul> <li> <p><a href="https://github.com/keycloak/keycloak-quickstarts">Keycloak Quickstart GitHub Repository</a></p> </li> <li> <p><a href="https://www.keycloak.org/guides#securing-apps">Keycloak Securing Applications Documentation</a></p> </li> </ul> </div> <div class="paragraph"> <p>We recommend starting to look into moving your applications to the alternatives from the references above. Those adapters should not be available anymore in future releases.</p> </div> </div> <div class="sect3"> <h4 id="deprecation-of-keycloak-jee-saml-adapter"><a class="anchor" href="#deprecation-of-keycloak-jee-saml-adapter"></a>Deprecation of Keycloak JEE SAML Adapter</h4> <div class="paragraph"> <p>The Keycloak JEE SAML Adapter has been discontinued, and we will no longer invest our time on its development following this release.</p> </div> <div class="paragraph"> <p>The official adapter is now based on Jakarta and should be used as soon as you switch your applications to this technology.</p> </div> <div class="paragraph"> <p>This change is already in our documentation and in our quickstart repository. For more information, please consider looking at the following references:</p> </div> <div class="ulist"> <ul> <li> <p><a href="https://github.com/keycloak/keycloak-quickstarts">Keycloak Quickstart GitHub Repository</a></p> </li> <li> <p><a href="https://www.keycloak.org/guides#securing-apps">Keycloak Securing Applications Documentation</a></p> </li> </ul> </div> <div class="paragraph"> <p>If you cannot migrate your applications to Jakarta, you can still use the "legacy" SAML JEE adapter and still be able to integrate with future releases of the server. However, consider upgrading your applications as soon as possible because we are no longer providing support to JEE.</p> </div> </div> <div class="sect3"> <h4 id="changes-for-openshift-integration-feature"><a class="anchor" href="#changes-for-openshift-integration-feature"></a>Changes for openshift-integration feature</h4> <div class="paragraph"> <p>The preview feature <code>openshift-integration</code> was removed from Keycloak codebase and moved into separate extension. This includes moving of related providers such as custom client storage provider and token review endpoint for Openshift integration.</p> </div> <div class="paragraph"> <p>If you used this feature, you should not use the <code>openshift-integration</code> feature anymore when starting Keycloak server and instead you need to deploy the JAR file from custom extension. You can check the <a href="https://github.com/keycloak-extensions/keycloak-openshift-ext/">Openshift extension</a> and the instructions in it&#8217;s README file for how to deploy the extension to your Keycloak server.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> The Openshift extension is not officially supported and maintained by Keycloak team. You can use it only at your own risk. </td> </tr> </table> </div> <div class="sect4"> <h5 id="http-challenge-flow-removed"><a class="anchor" href="#http-challenge-flow-removed"></a>Http Challenge flow removed</h5> <div class="paragraph"> <p>The built-in authentication flow <code>http challenge</code> was removed along with the authenticator implementations <code>no-cookie-redirect</code>, <code>basic-auth</code>, and <code>basic-auth-otp</code>. The <code>http challenge</code> authentication flow was also intended for Openshift integration and therefore it was removed along with other related capabilities as described above. Authenticator implementations were moved to the Openshift extension described in the previous paragraph.</p> </div> <div class="paragraph"> <p>If you use the <code>http challenge</code> flow as a realm flow or as <code>First Broker Login</code> or <code>Post Broker Login</code> flow for any of your identity providers, the migration is not possible. Be sure to update your realm configuration to eliminate the use of the <code>http challenge</code> flow before migration. If you use the <code>http challenge</code> flow as <code>Authentication Flow Binding Override</code> for any client, the migration would complete, but you could no longer log in to that client. After the migration, you would need to re-create the flow and update the configuration of your clients to use the new/differentJson flow.</p> </div> </div> </div> <div class="sect3"> <h4 id="removing-third-party-dependencies"><a class="anchor" href="#removing-third-party-dependencies"></a>Removing third party dependencies</h4> <div class="paragraph"> <p>The removal of openshift-integration allows us to remove few third party dependencies from Keycloak distribution. This includes <code>openshift-rest-client</code>, <code>okio-jvm</code>, <code>okhttp</code>, <code>commons-lang</code>, <code>commons-compress</code>, <code>jboss-dmr</code> and <code>kotlin-stdlib</code>. This means that if you use any of these libraries as dependencies of your own providers deployed to Keycloak server, you may also need to copy those <code>jar</code> files explicitly to the Keycloak distribution <code>providers</code> directory as well.</p> </div> </div> <div class="sect3"> <h4 id="context-and-dependency-injection-no-longer-enabled-to-jax-rs-resources"><a class="anchor" href="#context-and-dependency-injection-no-longer-enabled-to-jax-rs-resources"></a>Context and dependency injection no longer enabled to JAX-RS Resources</h4> <div class="paragraph"> <p>In order to provide a better runtime and leverage as much as possible the underlying stack, all injection points for contextual data using the <code>javax.ws.rs.core.Context</code> annotation were removed. The expected improvement in performance involves no longer creating proxies instances multiple times during the request lifecycle, and drastically reducing the amount of reflection code at runtime.</p> </div> <div class="paragraph"> <p>If you are extending one of the following SPIs:</p> </div> <div class="ulist"> <ul> <li> <p><code>PolicySpi</code></p> </li> <li> <p><code>AdminRealmResourceSpi</code></p> </li> <li> <p><code>IdentityProviderSpi</code></p> </li> <li> <p><code>RealmResourceSPI</code></p> </li> </ul> </div> <div class="paragraph"> <p>You should review your custom JAX-RS (sub)resources in order to obtain any contextual data as follows:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java">KeycloakSession session = org.keycloak.common.util.Resteasy.getContextData(KeycloakSession.class);</code></pre> </div> </div> <div class="paragraph"> <p>If you need access to the current request and response objects, you can now obtain their instances directly from the <code>KeycloakSession</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@Context</span> org.jboss.resteasy.spi.HttpRequest request; <span class="annotation">@Context</span> org.jboss.resteasy.spi.HttpResponse response;</code></pre> </div> </div> <div class="paragraph"> <p>was replaced by:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java">KeycloakSession session = <span class="comment">// obtain the session, which is usually available when creating a custom provider from a factory</span> KeycloakContext context = session.getContext(); HttpRequest request = context.getHttpRequest(); HttpResponse response = context.getHttpResponse();</code></pre> </div> </div> <div class="paragraph"> <p>In case you have no access to a <code>KeycloakSession</code> instance when invoking a JAX-RS resource method, you can obtain contextual data from the JAX-RS runtime as follows:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java">KeycloakSession session = org.keycloak.common.util.Resteasy.getContextData(KeycloakSession.class);</code></pre> </div> </div> <div class="paragraph"> <p>Additional contextual data can be obtained from the runtime through the <code>KeycloakContext</code> instance:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java">KeycloakSession session = <span class="comment">// obtain the session</span> KeycloakContext context = session.getContext(); MyContextualObject myContextualObject = context.getContextObject(MyContextualObject.class);</code></pre> </div> </div> </div> <div class="sect3"> <h4 id="upgrading-your-custom-jax-rs-resources"><a class="anchor" href="#upgrading-your-custom-jax-rs-resources"></a>Upgrading your custom JAX-RS resources</h4> <div class="paragraph"> <p>If you are extending the server&#8217;s REST APIs through the following SPIs:</p> </div> <div class="ulist"> <ul> <li> <p><code>PolicySpi</code></p> </li> <li> <p><code>AdminRealmResourceSpi</code></p> </li> <li> <p><code>IdentityProviderSpi</code></p> </li> <li> <p><code>RealmResourceSPI</code></p> </li> </ul> </div> <div class="paragraph"> <p>You need to add an empty <code>META-INF/beans.xml</code> to the JAR file where your custom providers are packaged. Otherwise, they are not recognized by the server at runtime.</p> </div> <div class="paragraph"> <p>If you are using <code>RealmResourceSPI</code> or <code>AdminRealmResourceSpi</code>, you have the choice between adding an empty file named <code>beans.xml</code> under <code>META-INF</code> or annotating the JAX-RS resource classes with the <code>jakarta.ws.rs.ext.Provider</code> annotation.</p> </div> <div class="paragraph"> <p>You should also make sure your JAX-RS methods are declaring the expected media types for input and output by marking them with the <code>@Consumes</code> and <code>@Produces</code> annotations, respectively.</p> </div> </div> <div class="sect3"> <h4 id="deprecated-methods-from-data-providers-and-models-2"><a class="anchor" href="#deprecated-methods-from-data-providers-and-models-2"></a>Deprecated methods from data providers and models</h4> <div class="paragraph"> <p>In earlier versions of Keycloak, provider and model interfaces underwent a cleanup process that involved deprecating certain methods. In this release the methods were removed and some additional methods were deprecated. The Javadoc for these methods from Keycloak 21 included information about their corresponding replacements.</p> </div> <div class="ulist"> <ul> <li> <p><code>RealmModel#searchForGroupByNameStream(String, Integer, Integer)</code> was removed.</p> </li> <li> <p><code>UserProvider#getUsersStream(RealmModel, boolean)</code> was removed.</p> </li> <li> <p><code>UserSessionPersisterProvider#loadUserSessions(int, int, boolean, int, String)</code> was removed.</p> </li> <li> <p>Interfaces added for Streamification work were removed. Such as <code>RoleMapperModel.Streams</code> and similar.</p> </li> <li> <p><code>Streams</code> interfaces in federated storage provider classes were deprecated.</p> </li> <li> <p><code>KeycloakModelUtils#getClientScopeMappings</code> was removed.</p> </li> <li> <p>Deprecated methods from <code>KeycloakSession</code> were removed.</p> </li> <li> <p><code>UserQueryProvider#getUsersStream</code> methods were removed.</p> </li> </ul> </div> </div> <div class="sect3"> <h4 id="multiple-keycloak-instances"><a class="anchor" href="#multiple-keycloak-instances"></a>Multiple Keycloak instances</h4> <div class="paragraph"> <p>Multiple Keycloak CRs may be created in the same namespace and will be managed independently by the operator. To allow for this StatefulSets created by older versions of the operator must be re-created. This will happen automatically when the operator is upgraded and lead to small amount of downtime.</p> </div> </div> <div class="sect3"> <h4 id="k8s-keycloak-orgv2alpha1-changes"><a class="anchor" href="#k8s-keycloak-orgv2alpha1-changes"></a>k8s.keycloak.org/v2alpha1 changes</h4> <div class="paragraph"> <p>The condition status field was changed from a boolean to a string for conformance with standard Kubernetes conditions. In the CRD it will temporarily be represented as accepting any content, but it will only ever be a string. Please make sure any of your usage of this field is updated to expect the values "True", "False", or "Unknown", rather than true or false.</p> </div> </div> <div class="sect3"> <h4 id="keycloak-supports-ipv4ipv6-dual-stack"><a class="anchor" href="#keycloak-supports-ipv4ipv6-dual-stack"></a>Keycloak supports IPv4/IPv6 dual stack</h4> <div class="paragraph"> <p>Keycloak supports the IPv4/IPv6 dual stack and can be accessible by default via the IPv4 and IPv6 addresses. In the older versions of Keycloak, the default approach was to use only IPv4 addresses.</p> </div> <div class="paragraph"> <p>For more details, see <a href="https://www.keycloak.org/server/configuration-production#_configure_keycloak_server_with_ipv4_or_ipv6">Configure Keycloak Server with IPv4 or IPv6</a>.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-21-1-0"><a class="anchor" href="#migrating-to-21-1-0"></a>Migrating to 21.1.0</h3> <div class="sect3"> <h4 id="javascript-engine-available-by-default-on-the-classpath"><a class="anchor" href="#javascript-engine-available-by-default-on-the-classpath"></a>Javascript engine available by default on the classpath</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/changes/changes-21_1_0.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/changes/changes-21_1_0.adoc&amp;description=%0A%0AFile:%20upgrading/topics/changes/changes-21_1_0.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 previous version, when Keycloak was used on Java 17 with Javascript providers (Script authenticator, Javascript authorization policy or Script protocol mappers for OIDC and SAML clients), it was needed to copy javascript engine to the distribution. This is no longer needed as Nashorn javascript engine is available in Keycloak server by default. When you deploy script providers, it is recommended to not copy the nashorn script engine and it&#8217;s dependencies into the Keycloak distribution.</p> </div> </div> <div class="sect3"> <h4 id="change-of-the-default-client-id-mapper-of-service-account-client"><a class="anchor" href="#change-of-the-default-client-id-mapper-of-service-account-client"></a>Change of the default Client ID mapper of Service Account Client</h4> <div class="paragraph"> <p>Default <code>Client ID</code> mapper of <code>Service Account Client</code> has been changed. <code>Token Claim Name</code> field value has been changed from <code>clientId</code> to <code>client_id</code>. <code>client_id</code> claim is compliant with OAuth2 specifications:</p> </div> <div class="ulist"> <ul> <li> <p><a href="https://datatracker.ietf.org/doc/html/rfc9068#section-2.2">JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens</a></p> </li> <li> <p><a href="https://www.rfc-editor.org/rfc/rfc7662#section-2.2">OAuth 2.0 Token Introspection</a></p> </li> <li> <p><a href="https://datatracker.ietf.org/doc/html/rfc8693#section-4.3">OAuth 2.0 Token Exchange</a></p> </li> </ul> </div> <div class="paragraph"> <p><code>clientId</code> userSession note still exists.</p> </div> </div> <div class="sect3"> <h4 id="keycloak-js-adapter-must-be-instantiated-with-the-new-operator"><a class="anchor" href="#keycloak-js-adapter-must-be-instantiated-with-the-new-operator"></a>Keycloak JS adapter must be instantiated with the <code>new</code> operator</h4> <div class="paragraph"> <p>Historically it has been possible to create an instance of the Keycloak JS adapter by calling the <code>Keycloak()</code> function directly:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="javascript">const keycloak = Keycloak();</code></pre> </div> </div> <div class="paragraph"> <p>To align this with modern conventions in the JavaScript world it has been possible to use the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new"><code>new</code> operator</a> to create an instance instead:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="javascript">const keycloak = <span class="keyword">new</span> Keycloak();</code></pre> </div> </div> <div class="paragraph"> <p>The function-style constructor has been deprecated for a while, but starting this version we will actively log a deprecation message when it used. This style of constructor will be removed in a future version so make sure to migrate your code to use the <code>new</code> operator.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-21-0-2"><a class="anchor" href="#migrating-to-21-0-2"></a>Migrating to 21.0.2</h3> <div class="sect3"> <h4 id="terms-and-conditions-user-attribute-migration"><a class="anchor" href="#terms-and-conditions-user-attribute-migration"></a>Terms and Conditions user attribute migration</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/changes/changes-21_0_2.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/changes/changes-21_0_2.adoc&amp;description=%0A%0AFile:%20upgrading/topics/changes/changes-21_0_2.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>terms_and_conditions</code> user attribute was accidentally changed in 21.0.0 to uppercase. This version reverts the user attribute back to lowercase. The value of the attribute is set when accepting Terms and Conditions page.</p> </div> <div class="paragraph"> <p>If any of your custom extensions relies on this attribute, you may need to adjust your code to check both attributes <code>terms_and_conditions</code> and <code>TERMS_AND_CONDITIONS</code>.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-21-0-0"><a class="anchor" href="#migrating-to-21-0-0"></a>Migrating to 21.0.0</h3> <div class="sect3"> <h4 id="keycloak-uses-micrometer-for-metrics"><a class="anchor" href="#keycloak-uses-micrometer-for-metrics"></a>Keycloak uses Micrometer for metrics</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/changes/changes-21_0_0.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/changes/changes-21_0_0.adoc&amp;description=%0A%0AFile:%20upgrading/topics/changes/changes-21_0_0.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 an optional a metrics endpoint which exports metrics in the Prometheus format. In this release the implementation to provide this data switched from SmallRye to Micrometer, which is the <a href="https://quarkus.io/guides/micrometer/">recommended metrics library for Quarkus</a>.</p> </div> <div class="paragraph"> <p>Due to this change, metrics have been renamed. The following table shows some examples.</p> </div> <div class="paragraph"> <p>Before upgrading it is recommended to review all metrics returned from the endpoint before and after the change, and update their usage in dashboards and alerts.</p> </div> <table class="tableblock frame-all grid-all stretch"> <caption class="title">Table 1. Examples of changed metrics names</caption> <colgroup> <col style="width: 50%;"> <col style="width: 50%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Old metric name</th> <th class="tableblock halign-left valign-top">New metric name</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>base_gc_total</code></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>jvm_gc_pause_seconds_count</code></p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>base_gc_time_total_seconds</code></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>jvm_gc_pause_seconds_sum</code></p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>base_thread_count</code></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>jvm_threads_live_threads</code></p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>vendor_agroal_*</code></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><code>agroal_*</code></p></td> </tr> </tbody> </table> </div> <div class="sect3"> <h4 id="deprecated-rsa_sha1-and-dsa_sha1-algorithms-for-saml"><a class="anchor" href="#deprecated-rsa_sha1-and-dsa_sha1-algorithms-for-saml"></a>Deprecated RSA_SHA1 and DSA_SHA1 algorithms for SAML</h4> <div class="paragraph"> <p>Algorithms <code>RSA_SHA1</code> and <code>DSA_SHA1</code>, which can be configured as <code>Signature algorithms</code> on SAML adapters, clients and identity providers are deprecated. We recommend to use safer alternatives based on <code>SHA256</code> or <code>SHA512</code>. Also, verifying signatures on signed SAML documents or assertions with these algorithms do not work on Java 17 or higher. If you use this algorithm and the other party consuming your SAML documents is running on Java 17 or higher, verifying signatures will not work.</p> </div> <div class="paragraph"> <p>The possible workaround is to remove algorithms such as <code>http://www.w3.org/2000/09/xmldsig#rsa-sha1</code> or <code>http://www.w3.org/2000/09/xmldsig#dsa-sha1</code> from the list of "disallowed algorithms" configured on property <code>jdk.xml.dsig.secureValidationPolicy</code> in the file <code>$JAVA_HOME/conf/security/java.security</code>.</p> </div> </div> <div class="sect3"> <h4 id="saml-sp-metadata-changes"><a class="anchor" href="#saml-sp-metadata-changes"></a>SAML SP metadata changes</h4> <div class="paragraph"> <p>In this version, Keycloak will refuse to decrypt assertions encrypted using a realm key generated for signing purpose. This change means all encrypted communication from IDP to SP (where Keycloak acts as the SP) will stop working.</p> </div> <div class="paragraph"> <p>There are two ways to make this work:</p> </div> <div class="ulist"> <ul> <li> <p>either update the IDP configuration with the metadata generated by a newer version of Keycloak,</p> </li> <li> <p>or run Keycloak in backward compatibility mode that will make Keycloak work with the metadata generated by older Keycloak versions. This mode can be enabled using <code>-Dkeycloak.saml.deprecated.encryption=true</code> flag. Note this backward compatibility mode is planned to be removed in Keycloak 24.</p> </li> </ul> </div> </div> <div class="sect3"> <h4 id="deprecated-methods-from-user-session-provider-were-removed"><a class="anchor" href="#deprecated-methods-from-user-session-provider-were-removed"></a>Deprecated methods from user session provider were removed</h4> <div class="paragraph"> <p>In Keycloak 13 there was introduced <code>UserLoginFailureProvider</code> and some methods from <code>UserSessionProvider</code> were moved there. The methods in <code>UserSessionProvider</code> were deprecated and now has been removed. Javadoc of these methods contained a corresponding replacement (see Javadoc of Keycloak 20 release).</p> </div> </div> <div class="sect3"> <h4 id="custom-themes-using-old-admin-console-wont-work"><a class="anchor" href="#custom-themes-using-old-admin-console-wont-work"></a>Custom themes using old admin console won&#8217;t work</h4> <div class="paragraph"> <p>The old admin console, which was deprecated in previous versions, was finally removed. This also means that your custom themes, which were using it as parent theme or importing from it, won&#8217;t work. It is highly recommended to not deploy such themes at all as extending old admin console is not applicable anymore and there can be issues in Keycloak (at least warnings or errors in the logs) with such themes deployed.</p> </div> </div> <div class="sect3"> <h4 id="curl-has-been-removed-from-the-container"><a class="anchor" href="#curl-has-been-removed-from-the-container"></a>Curl has been removed from the container</h4> <div class="paragraph"> <p>The <a href="https://quay.io/repository/keycloak/keycloak?tab=info">Keycloak Container Image</a> has been modified to enhance security. As a result, <code>curl</code> and other CLI tools have been removed, which you may have been using in your customized image. See the updated <a href="https://www.keycloak.org/server/containers">container guide</a> for information on how to handle this change.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-20-0-0"><a class="anchor" href="#migrating-to-20-0-0"></a>Migrating to 20.0.0</h3> <div class="sect3"> <h4 id="resteasy-version-update"><a class="anchor" href="#resteasy-version-update"></a>RESTEasy Version Update</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/changes/changes-20_0_0.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/changes/changes-20_0_0.adoc&amp;description=%0A%0AFile:%20upgrading/topics/changes/changes-20_0_0.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>Updated the RESTEasy version of Keycloak Admin REST Client to the next major version.</p> </div> </div> <div class="sect3"> <h4 id="h2-version-update"><a class="anchor" href="#h2-version-update"></a>H2 Version Update</h4> <div class="paragraph"> <p>Keycloak ships for development purposes with an H2 database driver. As it is intended for development purposes only, it should never be used in a production environment.</p> </div> <div class="paragraph"> <p>In this release, the H2 driver has been upgraded from version 1.x to version 2.x. This change might require changes to the H2 JDBC URL or migration of the H2 database files in an existing Keycloak setup.</p> </div> <div class="sect4"> <h5 id="changes-to-the-h2-jdbc-url"><a class="anchor" href="#changes-to-the-h2-jdbc-url"></a>Changes to the H2 JDBC URL</h5> <div class="paragraph"> <p>For Keycloak to run with its JPA legacy store with H2 version 2.x, the JDBC URL requires the attribute <code>NON_KEYWORDS=VALUE</code>.</p> </div> <div class="paragraph"> <p>In a setup where H2 is initialized by Keycloak without extra parameters, Keycloak will append the attribute automatically. This is the default for development setups.</p> </div> <div class="paragraph"> <p>If an H2 JDBC URL is provided on the command line or in a configuration file, and it already contains the <code>NON_KEYWORDS=</code> attribute in the JDBC URL, this attribute needs to be amended with the <code>VALUE</code> keyword.</p> </div> <div class="paragraph"> <p>If the connection factory for the H2 database is initialized outside Keycloak, that initialization needs to take care of adding the <code>NON_KEYWORDS</code> attribute.</p> </div> <div class="paragraph"> <p>See the H2 documentation <a href="http://www.h2database.com/html/commands.html#set_non_keywords">on the <code>NON_KEYWORDS</code> attribute</a> for details.</p> </div> </div> <div class="sect4"> <h5 id="upgrade-of-h2-database-files"><a class="anchor" href="#upgrade-of-h2-database-files"></a>Upgrade of H2 database files</h5> <div class="paragraph"> <p>H2 database base files created with H2 version 1.x should not be used with version 2.x.</p> </div> <div class="paragraph"> <p>Purge existing H2 database files to start with an empty database, export and import the realms using Keycloak&#8217;s export and import functionality, or refer to the <a href="http://www.h2database.com/html/migration-to-v2.html">migration notes on the H2 database project&#8217;s website</a> for details on how to migrate H2 database contents.</p> </div> </div> </div> <div class="sect3"> <h4 id="breaking-changes-in-the-new-version-of-keycloak-operator"><a class="anchor" href="#breaking-changes-in-the-new-version-of-keycloak-operator"></a>Breaking changes in the new version of Keycloak Operator</h4> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> In order to use the newest version of the Keycloak Operator, the manual reinstallation and upgrade of your CRs are required. There鈥檚 no automated migration. </td> </tr> </table> </div> <div class="paragraph"> <p>This release contains the following breaking changes in Keycloak CRs:</p> </div> <div class="sect4"> <h5 id="serverconfiguration-free-form-field-was-renamed"><a class="anchor" href="#serverconfiguration-free-form-field-was-renamed"></a>serverConfiguration free-form field was renamed</h5> <div class="paragraph"> <p>From now on it鈥檚 called <code>additionalOptions</code>. The idea behind this decision is to align it more with the Keycloak Quarkus distribution and achieve/preserve a naming consistency. <code>serverConfiguration</code> can be still used for configuring options that haven鈥檛 got a declared alternative in Keycloak custom resources (CRs). A good example of such use can be service providers.</p> </div> </div> <div class="sect4"> <h5 id="ingress-options-were-refined"><a class="anchor" href="#ingress-options-were-refined"></a>Ingress options were refined</h5> <div class="paragraph"> <p>In the past, it used to be defined via the <code>disableDefaultIngress</code> property. We decided to clarify it a bit, thus from now on you can use the following structure to control your ingress settings:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="yaml"><span class="key">spec</span>: <span class="error">...</span> <span class="key">ingress</span>: <span class="key">enabled</span>: <span class="string"><span class="content">false</span></span></code></pre> </div> </div> </div> <div class="sect4"> <h5 id="http-options-were-added"><a class="anchor" href="#http-options-were-added"></a>HTTP options were added</h5> <div class="paragraph"> <p>Similarly, like with ingress, you can define multiple HTTP options in a better structural manner:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="yaml"><span class="key">spec</span>: <span class="error">...</span> <span class="key">http</span>: <span class="key">httpEnabled</span>: <span class="string"><span class="content">true</span></span> <span class="key">httpPort</span>: <span class="string"><span class="content">80</span></span> <span class="key">httpsPort</span>: <span class="string"><span class="content">443</span></span> <span class="key">tlsSecret</span>: <span class="string"><span class="content">my-tls-secret</span></span></code></pre> </div> </div> </div> <div class="sect4"> <h5 id="hostname-options-were-added"><a class="anchor" href="#hostname-options-were-added"></a>Hostname options were added</h5> <div class="paragraph"> <p>Last but not least, the hostname options were also changed:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="yaml"><span class="key">spec</span>: <span class="error">...</span> <span class="key">hostname</span>: <span class="key">hostname</span>: <span class="string"><span class="content">[keycloak-server-hostname]</span></span> <span class="key">admin</span>: <span class="string"><span class="content">[admin-console-hostname]</span></span> <span class="key">adminUrl</span>: <span class="string"><span class="content">[admin-console-base-url]</span></span> <span class="key">strict</span>: <span class="string"><span class="content">[true|false]</span></span> <span class="key">strictBackchannel</span>: <span class="string"><span class="content">[true|false]</span></span></code></pre> </div> </div> </div> <div class="sect4"> <h5 id="some-fields-are-no-longer-required"><a class="anchor" href="#some-fields-are-no-longer-required"></a>Some fields are no longer required</h5> <div class="paragraph"> <p>The <code>hostname</code> and <code>tlsSecret</code> fields are now optional to align with the Quarkus distribution configuration. With that we also removed the possibility to set <code>INSECURE-DISABLE</code> special value to those fields. In order to disable hostname checks and enable HTTP, please follow the same approach as with the Quarkus distribution, i.e. set <code>strict: false</code>, <code>strictBackchannel: false</code> and <code>httpEnabled: true</code> fields.</p> </div> </div> </div> <div class="sect3"> <h4 id="olm-channel-was-changed-to-fast"><a class="anchor" href="#olm-channel-was-changed-to-fast"></a>OLM channel was changed to fast</h4> <div class="paragraph"> <p>The default channel of Keycloak Operator Lifecycle Manager was changed to <code>fast</code>.</p> </div> </div> <div class="sect3"> <h4 id="deprecated-methods-from-data-providers-and-models-were-removed"><a class="anchor" href="#deprecated-methods-from-data-providers-and-models-were-removed"></a>Deprecated methods from data providers and models were removed</h4> <div class="paragraph"> <p>Prior to Keycloak 15, there was a clean-up of provider and model interfaces where we deprecated some methods. Javadoc of these methods contained a corresponding replacement method (see Javadoc of Keycloak 19 release). In this release the methods were removed. The following is a list of all changed classes.</p> </div> <div class="paragraph"> <p>The most common patterns for deprecating and removing the methods are the following.</p> </div> <div class="ulist"> <ul> <li> <p>Streamification - interfaces now contain only Stream-based methods.</p> <div class="paragraph"> <p>For example in <a href="https://github.com/keycloak/keycloak/blob/19.0.3/server-spi/src/main/java/org/keycloak/models/GroupProvider.java"><code>GroupProvider</code></a> interface</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@Deprecated</span> <span class="predefined-type">List</span>&lt;GroupModel&gt; getGroups(RealmModel realm);</code></pre> </div> </div> <div class="paragraph"> <p>was replaced by</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java">Stream&lt;GroupModel&gt; getGroupsStream(RealmModel realm);</code></pre> </div> </div> <div class="paragraph"> <p>More details on streamification work can be found in <a href="https://issues.redhat.com/browse/KEYCLOAK-14011">KEYCLOAK-14011</a>.</p> </div> </li> <li> <p>Consistent parameter ordering - methods now have strict parameter ordering where <code>RealmModel</code> is always the first parameter.</p> <div class="paragraph"> <p>For example in <a href="https://github.com/keycloak/keycloak/blob/19.0.3/server-spi/src/main/java/org/keycloak/storage/user/UserLookupProvider.java"><code>UserLookupProvider</code></a> interface</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@Deprecated</span> UserModel getUserById(<span class="predefined-type">String</span> id, RealmModel realm);</code></pre> </div> </div> <div class="paragraph"> <p>was replaced by</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java">UserModel getUserById(RealmModel realm, <span class="predefined-type">String</span> id)</code></pre> </div> </div> </li> </ul> </div> <div class="sect4"> <h5 id="list-of-changed-interfaces"><a class="anchor" href="#list-of-changed-interfaces"></a>List of changed interfaces</h5> <div class="paragraph"> <p>(<code>o.k.</code> stands for <code>org.keycloak.</code> package)</p> </div> <div class="ulist"> <ul> <li> <p><code>server-spi</code> module</p> <div class="ulist"> <ul> <li> <p><code>o.k.credential.CredentialInputUpdater</code></p> </li> <li> <p><code>o.k.credential.UserCredentialStore</code></p> </li> <li> <p><code>o.k.models.ClientProvider</code></p> </li> <li> <p><code>o.k.models.ClientSessionContext</code></p> </li> <li> <p><code>o.k.models.GroupModel</code></p> </li> <li> <p><code>o.k.models.GroupProvider</code></p> </li> <li> <p><code>o.k.models.KeyManager</code></p> </li> <li> <p><code>o.k.models.KeycloakSessionFactory</code></p> </li> <li> <p><code>o.k.models.ProtocolMapperContainerModel</code></p> </li> <li> <p><code>o.k.models.RealmModel</code></p> </li> <li> <p><code>o.k.models.RealmProvider</code></p> </li> <li> <p><code>o.k.models.RoleContainerModel</code></p> </li> <li> <p><code>o.k.models.RoleMapperModel</code></p> </li> <li> <p><code>o.k.models.RoleModel</code></p> </li> <li> <p><code>o.k.models.RoleProvider</code></p> </li> <li> <p><code>o.k.models.ScopeContainerModel</code></p> </li> <li> <p><code>o.k.models.UserCredentialManager</code></p> </li> <li> <p><code>o.k.models.UserModel</code></p> </li> <li> <p><code>o.k.models.UserProvider</code></p> </li> <li> <p><code>o.k.models.UserSessionProvider</code></p> </li> <li> <p><code>o.k.models.utils.RoleUtils</code></p> </li> <li> <p><code>o.k.sessions.AuthenticationSessionProvider</code></p> </li> <li> <p><code>o.k.storage.client.ClientLookupProvider</code></p> </li> <li> <p><code>o.k.storage.group.GroupLookupProvider</code></p> </li> <li> <p><code>o.k.storage.user.UserLookupProvider</code></p> </li> <li> <p><code>o.k.storage.user.UserQueryProvider</code></p> </li> </ul> </div> </li> <li> <p><code>server-spi-private</code> module</p> <div class="ulist"> <ul> <li> <p><code>o.k.events.EventQuery</code></p> </li> <li> <p><code>o.k.events.admin.AdminEventQuery</code></p> </li> <li> <p><code>o.k.keys.KeyProvider</code></p> </li> </ul> </div> </li> </ul> </div> <div class="paragraph"> <p>All changes are linked to the following <a href="https://github.com/keycloak/keycloak/issues/14720">issue</a>.</p> </div> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-19-0-2"><a class="anchor" href="#migrating-to-19-0-2"></a>Migrating to 19.0.2</h3> <div class="sect3"> <h4 id="openid-connect-logout-prompt"><a class="anchor" href="#openid-connect-logout-prompt"></a>OpenID Connect Logout Prompt</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/changes/changes-19_0_2.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/changes/changes-19_0_2.adoc&amp;description=%0A%0AFile:%20upgrading/topics/changes/changes-19_0_2.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>At Keycloak 18.0.0, the logout is now compatible with the new OIDC specification, which changed the handling for the url parameters. However, to also remain compatible with earlier versions, a compatibility flag is introduced. See the <a href="https://www.keycloak.org/docs/26.0.6/upgrading/#openid-connect-logout">Upgrading Guide</a> for further information for the backwards compatibility option, which allows your application to still use the old format for the url parameters.</p> </div> <div class="paragraph"> <p>While the url parameters can now be configured to be compatible, there was still one incompatibility with keycloak 17 and earlier releases. If the user does not provide a valid <code>idTokenHint</code>, a logout prompt appears instead of a successful logout redirect. Therefore, a new compatibility flag <code>suppress-logout-confirmation-screen</code> is introduced to suppress the logout screen.</p> </div> <div class="paragraph"> <p>You can enable this parameter when you start the server by entering the following command:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>bin/kc.[sh|bat] --spi-login-protocol-openid-connect-suppress-logout-confirmation-screen=true start</code></pre> </div> </div> <div class="paragraph"> <p>With this configuration, you can still use the logout endpoint without a user prompt.</p> </div> <div class="admonitionblock warning"> <table> <tr> <td class="icon"> <i class="fa icon-warning" title="Warning"></i> </td> <td class="content"> The backwards compatibility switch will be removed in some future version - probably Keycloak 23. You are encouraged to update your clients as soon as possible as described above rather than rely on this switch. </td> </tr> </table> </div> </div> <div class="sect3"> <h4 id="deploying-scripts-through-saml-javascript-protocol-mapper"><a class="anchor" href="#deploying-scripts-through-saml-javascript-protocol-mapper"></a>Deploying scripts through SAML javascript protocol mapper</h4> <div class="paragraph"> <p>Until now, administrators, which used SAML javascript protocol mapper on their SAML clients or client scopes, were allowed to upload scripts to the server through the Keycloak Administration Console as well as through the RESTful Admin API.</p> </div> <div class="paragraph"> <p>For now on, this capability is <strong>disabled</strong> and users should deploy scripts directly to the server. This behaviour is aligned with other script based providers. For more details, please take a look at <a href="https://www.keycloak.org/docs/26.0.6/server_development/#_script_providers">JavaScript Providers</a>.</p> </div> </div> <div class="sect3"> <h4 id="userinfo-endpoint-changes"><a class="anchor" href="#userinfo-endpoint-changes"></a>UserInfo Endpoint Changes</h4> <div class="dlist"> <dl> <dt class="hdlist1">Error response changes</dt> <dd> <p>The UserInfo endpoint is now returning error responses fully compliant with <a href="https://datatracker.ietf.org/doc/html/rfc6750">RFC 6750</a> (The OAuth 2.0 Authorization Framework: Bearer Token Usage). Error code and description (if available) are provided as <code>WWW-Authenticate</code> challenge attributes rather than JSON object fields. The responses will be the following, depending on the error condition:</p> <div class="ulist"> <ul> <li> <p>In case no access token is provided:</p> <div class="listingblock"> <div class="content"> <pre>401 Unauthorized WWW-Authenticate: Bearer realm="myrealm"</pre> </div> </div> </li> <li> <p>In case several methods are used simultaneously to provide an access token (for example, Authorization header + POST access_token parameter), or POST parameters are duplicated:</p> <div class="listingblock"> <div class="content"> <pre>400 Bad Request WWW-Authenticate: Bearer realm="myrealm", error="invalid_request", error_description="..."</pre> </div> </div> </li> <li> <p>In case an access token is missing <code>openid</code> scope:</p> <div class="listingblock"> <div class="content"> <pre>403 Forbidden WWW-Authenticate: Bearer realm="myrealm", error="insufficient_scope", error_description="Missing openid scope"</pre> </div> </div> </li> <li> <p>In case of inability to resolve cryptographic keys for UserInfo response signing/encryption:</p> <div class="listingblock"> <div class="content"> <pre>500 Internal Server Error</pre> </div> </div> </li> <li> <p>In case of a token validation error, a <code>401 Unauthorized</code> is returned in combination with the <code>invalid_token</code> error code. This error includes user and client related checks and actually captures all the remaining error cases:</p> <div class="listingblock"> <div class="content"> <pre>401 Unauthorized WWW-Authenticate: Bearer realm="myrealm", error="invalid_token", error_description="..."</pre> </div> </div> </li> </ul> </div> </dd> <dt class="hdlist1">Other Changes</dt> <dd> <div class="ulist"> <ul> <li> <p>It is now required for access tokens to have the <code>openid</code> scope, which is stipulated by UserInfo being a feature specific to OpenID Connect and not OAuth 2.0. If the <code>openid</code> scope is missing from the token, the request will be denied with a <code>403 Forbidden</code> (see above).</p> </li> <li> <p>UserInfo now checks the user status, and returns the <code>invalid_token</code> response if the user is disabled.</p> </li> </ul> </div> </dd> </dl> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-19-0-0"><a class="anchor" href="#migrating-to-19-0-0"></a>Migrating to 19.0.0</h3> <div class="sect3"> <h4 id="new-admin-console-is-now-the-default-console"><a class="anchor" href="#new-admin-console-is-now-the-default-console"></a>New Admin Console is now the default console</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/changes/changes-19_0_0.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/changes/changes-19_0_0.adoc&amp;description=%0A%0AFile:%20upgrading/topics/changes/changes-19_0_0.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 new admin console is now the default console in Keycloak. If you are not able to start using the new admin console it is possible to continue to use the old admin console by disabling the new console, by for example running:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>bin/kc.sh start-dev --features-disabled=admin2</code></pre> </div> </div> <div class="paragraph"> <p>An alternative approach to continue using the old admin console is to set the theme for the master realm or any other realm to <code>keycloak</code>.</p> </div> <div class="paragraph"> <p>As the new admin console is significantly different to the old admin console, is now based on React and uses a newer version of PatternFly, any custom themes will most likely have to be re-implemented from scratch. To create a custom theme for the new admin console the theme should extend <code>keycloak.v2</code> instead of <code>keycloak</code>.</p> </div> <div class="paragraph"> <p>If you have explicitly set the admin console theme to <code>keycloak</code> for the master realm or any other realm, it will continue to use the old admin console. To update to the new admin console you need to change the theme to <code>keycloak.v2</code>.</p> </div> <div class="paragraph"> <p>The old admin console will be removed in Keycloak 21.</p> </div> </div> <div class="sect3"> <h4 id="changes-to-the-server-configuration-and-startup"><a class="anchor" href="#changes-to-the-server-configuration-and-startup"></a>Changes to the server configuration and startup</h4> <div class="paragraph"> <p>Before this release, you would use the <code>--auto-build</code> when running the <code>start</code> command to tell the server to conditionally run a <code>build</code> if any build option has changed prior to starting the server.</p> </div> <div class="paragraph"> <p>In this release, the <code>--auto-build</code> flag is <strong>deprecated</strong> and you no longer need to use it to indicate that you want to set build options when starting the server. Instead, the server is always going to run a <code>build</code> by default prior to starting the server if any build option has changed. The new behavior improves the overall experience when configuring and starting the server by making it optional, although highly recommended, to run a <code>build</code> command beforehand in order to achieve the best startup time and memory footprint.</p> </div> <div class="paragraph"> <p>Now, in order to achieve the best startup time and memory footprint, set the <code>--optimized</code> option to disable the new default behavior. The <code>--optimized</code> flag tells the server that checking for and running a <code>build</code> directly as part of the startup is not needed:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>kc.sh start --optimized</code></pre> </div> </div> <div class="paragraph"> <p>If you are already using a custom image to set build options and run an optimized Keycloak container, make sure you set the <code>--optimized</code> option when invoking the <code>start</code> command.</p> </div> <div class="paragraph"> <p>For more details, please take a look at the <a href="https://www.keycloak.org/server/configuration">Configuration Guide</a> and the <a href="https://www.keycloak.org/server/containers">Containers Guide</a>.</p> </div> </div> <div class="sect3"> <h4 id="potentially-breaking-changes-to-the-health-endpoints"><a class="anchor" href="#potentially-breaking-changes-to-the-health-endpoints"></a>Potentially breaking changes to the health endpoints</h4> <div class="paragraph"> <p>Before Keycloak 19.0.0, the quarkus based Keycloak distribution always enabled the following non-application endpoints unintentionally:</p> </div> <div class="ulist"> <ul> <li> <p>/q/health</p> </li> <li> <p>/q/health/live</p> </li> <li> <p>/q/health/ready</p> </li> <li> <p>/q/metrics</p> </li> </ul> </div> <div class="paragraph"> <p>Starting in Keycloak 19.0.0, these endpoints are <strong>disabled</strong> and a request will result in a 404 HTTP status-code. If you are using the <code>/q/&#8230;&#8203;</code> endpoints, make sure to change your probes and monitoring systems to use the intended health endpoints instead when upgrading to Keycloak 19.0.0.</p> </div> <div class="paragraph"> <p>The intended health endpoints are:</p> </div> <div class="ulist"> <ul> <li> <p>/health</p> </li> <li> <p>/health/live</p> </li> <li> <p>/health/ready</p> </li> <li> <p>/metrics</p> </li> </ul> </div> <div class="paragraph"> <p>Apart from disabling the /q/ endpoints, these are the other improvements made to the health endpoints:</p> </div> <div class="ulist"> <ul> <li> <p>The <code>health/live</code> endpoint used for liveness probes is now decoupled from the database connections health, to match current good practices and to not have the same behaviour as the <code>health/ready</code> endpoint. As a result, the database check is not shown in the <code>checks:</code> array anymore when calling <code>/health/live</code>, so when there is a database hiccup, the liveness probe will still return HTTP status-code 200 and a status of UP, so no pod restart may be triggered.</p> </li> <li> <p>The <code>health/ready</code> endpoint used for readiness probes still checks for a working database connection. Make sure you have not only <code>health-enabled=true</code> but also <code>metrics-enabled=true</code> set in your configuration, to enable the database check, resulting in an effective readiness probe. It will return HTTP status-code 503 and a status of DOWN when the database connection is not in a healthy state.</p> </li> </ul> </div> <div class="paragraph"> <p>Expect more enhancements in this area in the future. For more information, see the <a href="https://www.keycloak.org/server/health">Health guide</a></p> </div> </div> <div class="sect3"> <h4 id="changes-using-gelf-centralized-log-management"><a class="anchor" href="#changes-using-gelf-centralized-log-management"></a>Changes using GELF / centralized log management</h4> <div class="paragraph"> <p>As stated in the release notes, Keycloak now supports gelf logging for centralized logging systems out of the box.</p> </div> <div class="paragraph"> <p>When you added the gelf related quarkus jars yourself in a prior version, make sure to switch to the supported configuration options in the <a href="https://www.keycloak.org/server/logging">logging guide</a> and remove your jars from the <code>providers</code> folder.</p> </div> </div> <div class="sect3"> <h4 id="changes-affecting-developers"><a class="anchor" href="#changes-affecting-developers"></a>Changes affecting developers</h4> <div class="paragraph"> <p>Keycloak undergoes large refactoring, which impacts existing code. Some of these changes require updates to existing code. These are in more detailed described below.</p> </div> <div class="sect4"> <h5 id="rationale-for-changes"><a class="anchor" href="#rationale-for-changes"></a>Rationale for changes</h5> <div class="paragraph"> <p>Keycloak has several limitations; for example, downtime is needed for upgrading a Keycloak cluster. To address the limitations, an in-depth refactor has been initiated.</p> </div> <div class="paragraph"> <p>The changes in this version are mostly attached to storage refactoring and a preparation of a new storage, called map storage. This storage will eventually replace the current storage, which will be called a <em>legacy store</em> with this version. The legacy store will still be available in Keycloak for several more versions.</p> </div> <div class="paragraph"> <p>The new store imposes a strict separation of responsibility between the service and storage layers. For that reason, the service layer&#8217;s visibility of an object&#8217;s origin will be restricted, so it will not be able to discriminate between cached or non-cached objects, or objects originating from local or federated storage.</p> </div> <div class="paragraph"> <p>User storage SPI will become deprecated. It will be supported for several more versions, but will be eventually replaced by the Map Storage SPI, which will offer the ability to create custom storages for any recognized area, such as users, roles, clients, or groups.</p> </div> <div class="paragraph"> <p>Extensions that rely on the level of detail available to services in the legacy store will need adjustment to retain this ability for the full deprecation period of the legacy store. The following section describes how that adjustment is accomplished.</p> </div> <div class="paragraph"> <p>Using a legacy and map store is mutually exclusive; one store cannot be used while the other is active.</p> </div> </div> <div class="sect4"> <h5 id="changes-in-the-module-structure"><a class="anchor" href="#changes-in-the-module-structure"></a>Changes in the module structure</h5> <div class="paragraph"> <p>As part of introducing the new storage functionality, several public APIs around storage functionality in <code>KeycloakSession</code> have been consolidated, and some have been deprecated and will be removed in one of the next versions. Three new modules have been introduced, and data-oriented code from <code>server-spi</code>, <code>server-spi-private</code>, and <code>services</code> modules have been moved there:</p> </div> <div class="dlist"> <dl> <dt class="hdlist1"><code>org.keycloak:keycloak-model-legacy</code></dt> <dd> <p>Contains all public facing APIs from the legacy store, such as the User Storage API.</p> </dd> <dt class="hdlist1"><code>org.keycloak:keycloak-model-legacy-private</code></dt> <dd> <p>Contains private implementations that relate to user storage management, such as storage <code>*Manager</code> classes.</p> </dd> <dt class="hdlist1"><code>org.keycloak:keycloak-model-legacy-services</code></dt> <dd> <p>Contains all REST endpoints that directly operate on the legacy store, and have no meaning in the new store.</p> </dd> </dl> </div> <div class="paragraph"> <p>These modules will be available as long as legacy stores will be supported. After that period, they will be removed.</p> </div> <div class="paragraph"> <p>This change impacts deployments of existing user storage providers in the Wildfly distribution. If your user storage provider is deployed as a WAR archive, you need to add the <code>META-INF/jboss-deployment-structure.xml</code> file into that archive stating the modified dependencies as shown below:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;jboss-deployment-structure</span> <span class="attribute-name">xmlns</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">urn:jboss:deployment-structure:1.2</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span> <span class="tag">&lt;deployment&gt;</span> <span class="tag">&lt;dependencies&gt;</span> <span class="tag">&lt;module</span> <span class="attribute-name">name</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">org.keycloak.keycloak-model-legacy</span><span class="delimiter">&quot;</span></span> <span class="attribute-name">meta-inf</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">import</span><span class="delimiter">&quot;</span></span><span class="tag">/&gt;</span> <span class="tag">&lt;/dependencies&gt;</span> <span class="tag">&lt;/deployment&gt;</span> <span class="tag">&lt;/jboss-deployment-structure&gt;</span></code></pre> </div> </div> </div> <div class="sect4"> <h5 id="changes-in-keycloaksession"><a class="anchor" href="#changes-in-keycloaksession"></a>Changes in <code>KeycloakSession</code></h5> <div class="paragraph"> <p><code>KeycloakSession</code> has been simplified. Several methods have been deprecated in <code>KeycloakSession</code> and will be removed in a future version.</p> </div> <div class="paragraph"> <p><code>KeycloakSession</code> session contains several methods for obtaining a provider for a particular object type, such as for a <code>UserProvider</code> there are <code>users()</code>, <code>userLocalStorage()</code>, <code>userCache()</code>, <code>userStorageManager()</code>, and <code>userFederatedStorage()</code>. This situation may be confusing for the developer who has to understand the exact meaning of each method, and depends on current store layout. The new store does not distinguish federated from local storage.</p> </div> <div class="paragraph"> <p>For those reasons, only the <code>users()</code> method will be kept in <code>KeycloakSession</code>, and should replace all other calls listed above. The rest of the methods are deprecated, and will eventually be removed. The same pattern of deprecation applies to methods of other object areas, such as <code>clients()</code> or <code>groups()</code>. All methods ending in <code>*StorageManager()</code> and <code>*LocalStorage()</code> now throw an exception when being called, as there is no direct replacement in the new store. The next section describes how to migrate those calls to the new API or use the legacy API while using the old store.</p> </div> <div class="paragraph"> <p>The deprecated methods in KeycloakSession will be removed in a future release. The <code>keycloak-model-legacy-*</code> modules will be available for a longer time and will eventually be removed.</p> </div> <div class="sect5"> <h6 id="migrating-existing-providers-that-do-not-depend-on-the-legacy-store"><a class="anchor" href="#migrating-existing-providers-that-do-not-depend-on-the-legacy-store"></a>Migrating existing providers that do not depend on the legacy store</h6> <div class="paragraph"> <p>The existing providers need no migration if they do not call a deprecated method, which should be the case for most providers.</p> </div> <div class="paragraph"> <p>If the provider uses deprecated methods, but does not rely on local versus non-local storage, changing a call from the now deprecated <code>userLocalStorage()</code> to the method <code>users()</code> is the best option. Be aware that the semantics change here as the new method involves a cache if that has been enabled in the local setup.</p> </div> <div class="listingblock"> <div class="title">Before migration: accessing a deprecated API that now throws an exception</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java">session<strong>.userLocalStorage()</strong>;</code></pre> </div> </div> <div class="listingblock"> <div class="title">After migration: accessing the new API caller does not depend on the legacy storage API</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java">session<strong>.users()</strong>;</code></pre> </div> </div> </div> <div class="sect5"> <h6 id="migrating-existing-providers-that-depend-on-the-legacy-store"><a class="anchor" href="#migrating-existing-providers-that-depend-on-the-legacy-store"></a>Migrating existing providers that depend on the legacy store</h6> <div class="paragraph"> <p>In the rare case when a custom provider needs to distinguish between the mode of a particular provider, access to the deprecated objects is provided by using the <code>LegacyStoreManagers</code> data store provider. This option will be available only if the legacy modules are part of the deployment.</p> </div> <div class="listingblock"> <div class="title">Before migration: accessing a deprecated API that now throws an exception</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java">session<strong>.userLocalStorage()</strong>;</code></pre> </div> </div> <div class="listingblock"> <div class="title">After migration: accessing the old functionality via the LegacyStoreManagers API</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java">((LegacyDatastoreProvider) session.getProvider(DatastoreProvider.class))<strong>.userLocalStorage()</strong>;</code></pre> </div> </div> <div class="paragraph"> <p>Some user storage related APIs have been wrapped in <code>org.keycloak.storage.UserStorageUtil</code> for convenience.</p> </div> </div> <div class="sect5"> <h6 id="creating-custom-storage-providers"><a class="anchor" href="#creating-custom-storage-providers"></a>Creating custom storage providers</h6> <div class="paragraph"> <p>The API for creating a custom storage provider has not been fully stabilized yet, though it is available as a tech preview. See the <code>MapStorageProvider</code> SPI and its Javadoc for details. The availability of the new API is a priority for the next Keycloak version.</p> </div> </div> </div> <div class="sect4"> <h5 id="changes-to-realmmodel"><a class="anchor" href="#changes-to-realmmodel"></a>Changes to <code>RealmModel</code></h5> <div class="paragraph"> <p>The methods getUserStorageProviders`, <code>getUserStorageProvidersStream</code>, <code>getClientStorageProviders</code>, <code>getClientStorageProvidersStream</code>, <code>getRoleStorageProviders</code> and <code>getRoleStorageProvidersStream</code> have been removed. Code which depends on these methods and runs with the legacy storage enabled should cast the instance as follows:</p> </div> <div class="listingblock"> <div class="title">Before migration: code will not compile due to the changed API</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java">realm<strong>.getClientStorageProvidersStream()</strong>...;</code></pre> </div> </div> <div class="listingblock"> <div class="title">After migration: cast the instance to the legacy interface</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java">((LegacyRealmModel) realm)<strong>.getClientStorageProvidersStream()</strong>...;</code></pre> </div> </div> <div class="paragraph"> <p>Similarly, code that used to implement the interface <code>RealmModel</code> and wants to provide these methods should implement the new interface <code>LegacyRealmModel</code>. This interface is a sub-interface of <code>RealmModel</code> and includes the old methods:</p> </div> <div class="listingblock"> <div class="title">Before migration: code implements the old interface</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">MyClass</span> <span class="directive">extends</span> RealmModel { <span class="comment">/* might not compile due to @Override annotations for methods no longer present in the interface RealmModel. <strong>/</span> <span class="comment">/</strong> ... */</span> }</code></pre> </div> </div> <div class="listingblock"> <div class="title">After migration: code implements the new interface</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">MyClass</span> <span class="directive">extends</span> LegacyRealmModel { <span class="comment">/* ... */</span> }</code></pre> </div> </div> </div> <div class="sect4"> <h5 id="interface-usercache-moved-to-the-legacy-module"><a class="anchor" href="#interface-usercache-moved-to-the-legacy-module"></a>Interface <code>UserCache</code> moved to the legacy module</h5> <div class="paragraph"> <p>As the caching status of objects will be transparent to services, the interface <code>UserCache</code> has been moved to the module <code>keycloak-legacy</code>. Calls to <code>session.userCache()</code> will therefore return only a <code>UserProvider</code>, which is a breaking change.</p> </div> <div class="paragraph"> <p>Code that depends on the legacy implementation should access the <code>UserCache</code> directly. While such calls might be necessary while caching with the legacy store is used, it will not be necessary when using the new map store, as that one handles caching transparently.</p> </div> <div class="listingblock"> <div class="title">Before migration: code will not compile due to a changed return type</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// session.userCache() might return null, null-check omitted for brevity.</span> session<strong>.userCache()</strong>.evict(realm, user);</code></pre> </div> </div> <div class="listingblock"> <div class="title">After migration: use the API directly</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// session.getProvider(UserCache.class) might return null, null-check omitted for brevity.</span> session.<strong>getProvider(UserCache.class)</strong>.evict(realm, user);</code></pre> </div> </div> <div class="paragraph"> <p>To trigger the invalidation of a realm, instead of using the <code>UserCache</code> API, consider triggering an event:</p> </div> <div class="listingblock"> <div class="title">Before migration: code will not compile due to a changed return type</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java">UserCache cache = session.getProvider(UserCache.class); <span class="keyword">if</span> (cache != <span class="predefined-constant">null</span>) cache.clear();</code></pre> </div> </div> <div class="listingblock"> <div class="title">After migration: use the invalidation API</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java">session.invalidate(InvalidationHandler.ObjectType.REALM, realm.getId());</code></pre> </div> </div> </div> <div class="sect4"> <h5 id="credential-management-for-users"><a class="anchor" href="#credential-management-for-users"></a>Credential management for users</h5> <div class="paragraph"> <p>Credentials for users were previously managed using <code>session.userCredentialManager().<em>method</em>(realm, user, ...)</code>. The new way is to leverage <code>user.credentialManager().<em>method</em>(...)</code>. This form gets the credential functionality closer to the API of users, and does not rely on prior knowledge of the user credential&#8217;s location in regard to realm and storage.</p> </div> <div class="paragraph"> <p>The old APIs have been deprecated, and will only work when the legacy storage is enabled in the deployment. The new APIs will work with both old and new storages.</p> </div> <div class="listingblock"> <div class="title">Before migration: accessing a deprecated API</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java">session.userCredentialManager()<strong>.createCredential</strong>(realm, user, credentialModel)</code></pre> </div> </div> <div class="listingblock"> <div class="title">After migration: accessing the new API</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java">user.credentialManager()<strong>.createStoredCredential</strong>(credentialModel)</code></pre> </div> </div> <div class="paragraph"> <p>For a custom <code>UserStorageProvider</code>, there is a new method <code>credentialManager()</code> that needs to be implemented when returning a <code>UserModel</code>. As those providers run in an environment with the legacy storage enabled, those must return an instance of the <code>LegacyUserCredentialManager</code>:</p> </div> <div class="listingblock"> <div class="title">Before migration: code will not compile due to the new method <code>credentialManager()</code> required by <code>UserModel</code></div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">MyUserStorageProvider</span> <span class="directive">implements</span> UserLookupProvider, ... { <span class="comment">/* ... */</span> <span class="directive">protected</span> UserModel createAdapter(RealmModel realm, <span class="predefined-type">String</span> username) { <span class="keyword">return</span> <span class="keyword">new</span> AbstractUserAdapter(session, realm, model) { <span class="annotation">@Override</span> <span class="directive">public</span> <span class="predefined-type">String</span> getUsername() { <span class="keyword">return</span> username; } }; } }</code></pre> </div> </div> <div class="listingblock"> <div class="title">After migration: implementation of the API <code>UserModel.credentialManager()</code> for the legacy store.</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">MyUserStorageProvider</span> <span class="directive">implements</span> UserLookupProvider, ... { <span class="comment">/* ... */</span> <span class="directive">protected</span> UserModel createAdapter(RealmModel realm, <span class="predefined-type">String</span> username) { <span class="keyword">return</span> <span class="keyword">new</span> AbstractUserAdapter(session, realm, model) { <span class="annotation">@Override</span> <span class="directive">public</span> <span class="predefined-type">String</span> getUsername() { <span class="keyword">return</span> username; } <span class="annotation">@Override</span> <span class="directive">public</span> SubjectCredentialManager credentialManager() { <span class="keyword">return</span> <span class="keyword">new</span> LegacyUserCredentialManager(session, realm, <span class="local-variable">this</span>); } }; } }</code></pre> </div> </div> </div> </div> <div class="sect3"> <h4 id="deprecated-poddisruptionbudget-in-the-legacy-keycloak-operator"><a class="anchor" href="#deprecated-poddisruptionbudget-in-the-legacy-keycloak-operator"></a>Deprecated <code>podDisruptionBudget</code> in the legacy Keycloak Operator</h4> <div class="paragraph"> <p>With this release, we have deprecated <code>podDisruptionBudget</code> field in the Keycloak CR of the <a href="https://github.com/keycloak/keycloak-operator">legacy Keycloak Operator</a>. This optional field will be ignored when the Operator is deployed on Kubernetes version 1.25 and higher.</p> </div> <div class="paragraph"> <p>As a workaround, you can manually create the Pod Disruption Budget in your cluster, for example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="yaml"><span class="key">apiVersion</span>: <span class="string"><span class="content">policy/v1</span></span> <span class="key">kind</span>: <span class="string"><span class="content">PodDisruptionBudget</span></span> <span class="key">metadata</span>: <span class="key">labels</span>: <span class="key">app</span>: <span class="string"><span class="content">keycloak</span></span> <span class="key">name</span>: <span class="string"><span class="content">keycloak</span></span> <span class="key">spec</span>: <span class="key">maxUnavailable</span>: <span class="string"><span class="content">1</span></span> <span class="key">selector</span>: <span class="key">matchLabels</span>: <span class="key">component</span>: <span class="string"><span class="content">keycloak</span></span></code></pre> </div> </div> <div class="paragraph"> <p>See also the <a href="https://kubernetes.io/docs/tasks/run-application/configure-pdb/">Kubernetes Documentation</a>.</p> </div> </div> <div class="sect3"> <h4 id="deployment-changes-in-the-new-keycloak-operator"><a class="anchor" href="#deployment-changes-in-the-new-keycloak-operator"></a>Deployment changes in the new Keycloak Operator</h4> <div class="paragraph"> <p>The new Keycloak Operator now uses <code>StatefulSet</code> instead of <code>Deployment</code> for Keycloak deployments. There&#8217;s no automated migration in place given the Operator is a tech preview in this release. If you are using the new Operator with 18.0.z, please make sure to back up, delete and recreate your Keycloak CR after the upgrade to 19.0.0.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-18-0-0"><a class="anchor" href="#migrating-to-18-0-0"></a>Migrating to 18.0.0</h3> <div class="sect3"> <h4 id="step-up-authentication"><a class="anchor" href="#step-up-authentication"></a>Step-up authentication</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/changes/changes-18_0_0.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/changes/changes-18_0_0.adoc&amp;description=%0A%0AFile:%20upgrading/topics/changes/changes-18_0_0.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>Step-up authentication is a new feature. This feature provides the <code>acr</code> client scope, which contains a protocol mapper that is supposed to add the <code>acr</code> claim in the token. The <code>acr</code> claim is not added automatically now as it was before this version, but it is added with the usage of this client scope and protocol mapper.</p> </div> <div class="paragraph"> <p>The client scope is added as a realm "default" client scope and hence will be added to all newly created clients. For performance reasons, the client scope is not automatically added to all existing clients during migration. The clients will not have an <code>acr</code> claim by default after the migration. Consider these possible actions:</p> </div> <div class="ulist"> <ul> <li> <p>If you do not plan to use step-up authentication feature, but you rely on the <code>acr</code> claim in the token, you can disable <code>step_up_authentication</code> feature. The claim will be added with the value <code>1</code> in case of normal authentication and <code>0</code> in case of SSO authentication.</p> </li> <li> <p>Add <code>acr</code> client scope to your clients manually by admin REST API or admin console. This is needed especially if you want to use step-up authentication. If you have a large number of clients in the realm and want to use <code>acr</code> claim for all of them, you can trigger some SQL similar to this against your DB. However, remember to clear the cache or restart the server if Keycloak is already started:</p> </li> </ul> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>insert into CLIENT_SCOPE_CLIENT (CLIENT_ID, SCOPE_ID, DEFAULT_SCOPE) select CLIENT.ID as CLIENT_ID, CLIENT_SCOPE.ID as SCOPE_ID, true as DEFAULT_SCOPE from CLIENT_SCOPE, CLIENT where CLIENT_SCOPE.REALM_ID='test' and CLIENT_SCOPE.NAME='acr' and CLIENT.REALM_ID='test' and CLIENT.PROTOCOL='openid-connect';</code></pre> </div> </div> </div> <div class="sect3"> <h4 id="openid-connect-logout"><a class="anchor" href="#openid-connect-logout"></a>OpenID Connect Logout</h4> <div class="paragraph"> <p>Previous versions of Keycloak had supported automatic logout of the user and redirecting to the application by opening logout endpoint URL such as <code>http(s)://example-host/auth/realms/my-realm-name/protocol/openid-connect/logout?redirect_uri=encodedRedirectUri</code>. While that implementation was easy to use, it had potentially negative impact on performance and security. The new version has better support for logout based on the OpenID Connect RP-Initiated Logout specification. The parameter <code>redirect_uri</code> is no longer supported; also, in the new version, the user needs to confirm the logout. It is possible to omit the confirmation and do automatic redirect to the application when you include parameter <code>post_logout_redirect_uri</code> together with the parameter <code>id_token_hint</code> with the ID Token used for login.</p> </div> <div class="paragraph"> <p>The existing deployments are affected in the following ways:</p> </div> <div class="ulist"> <ul> <li> <p>If your application directly uses links to logout endpoint with the <code>redirect_uri</code> parameter, you may be required to change this as described above. Consider either removing the <code>redirect_uri</code> parameter entirely or replacing it with the <code>id_token_hint</code> and <code>post_logout_redirect_uri</code> parameters.</p> </li> <li> <p>If you use java adapters and your application does logout by call <code>httpServletRequest.logout()</code>, you are not affected because this call uses the backchannel variant of the logout endpoint and that one was not changed.</p> </li> <li> <p>If you use the latest javascript adapter, you are also not affected. However if your application uses an older version of the JavaScript adapter, you are affected as this adapter uses the variant of the logout endpoint with the deprecated <code>redirect_uri</code> parameter. In this case, you may need to upgrade to the latest version of the JavaScript adapter.</p> </li> <li> <p>For the Node.js adapter, the same guideline applies as for the JavaScript adapter. You are encouraged to update to the latest version as the older version of the adapter uses the deprecated <code>redirect_uri</code> parameter. With the latest Node.js adapter, you are not affected as long as you use the logout based on the <code>/logout</code> URL as described in the documentation or in the Node.js adapter example. However, in the case when your application directly uses the method <code>keycloak.logoutUrl</code>, you can consider adding <code>idTokenHint</code> as the second argument to this method. The possibility to add <code>idTokenHint</code> as second argument was newly added in this version. The <code>idTokenHint</code> needs to be a valid ID Token that was obtained during the login. Adding <code>idTokenHint</code> is optional, but if you omit it, your users will need to confirm the logout screen as described earlier. Also they will not be redirected back to the application after logout.</p> </li> </ul> </div> <div class="paragraph"> <p>There is a backwards compatibility option, which allows your application to still use the old format of the <code>redirect_uri</code> parameter.</p> </div> <div class="paragraph"> <p>You can enable this parameter when you start the server by entering the following command:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>bin/kc.[sh|bat] --spi-login-protocol-openid-connect-legacy-logout-redirect-uri=true start</code></pre> </div> </div> <div class="paragraph"> <p>With this configuration, you can still use the format with the <code>redirect_uri</code> parameter. Note the confirmation screen will be needed if the <code>id_token_hint</code> is omitted.</p> </div> <div class="admonitionblock warning"> <table> <tr> <td class="icon"> <i class="fa icon-warning" title="Warning"></i> </td> <td class="content"> The backwards compatibility switch will be removed in some future version - probably Keycloak 23. You are encouraged to update your clients as soon as possible as described above rather than rely on this switch. </td> </tr> </table> </div> </div> <div class="sect3"> <h4 id="removal-of-the-upload-scripts-feature"><a class="anchor" href="#removal-of-the-upload-scripts-feature"></a>Removal of the <code>upload-scripts</code> feature</h4> <div class="paragraph"> <p>Previous versions of Keycloak had supported managing JavaScript code through the management interfaces like the administrations console and REST API. Starting from this version this is no longer possible, and you should now deploy your scripts to the server in order to configure the following providers:</p> </div> <div class="ulist"> <ul> <li> <p>OpenID Connect Script Mapper</p> </li> <li> <p>Script Authenticator (Authentication Execution)</p> </li> <li> <p>JavaScript Policies</p> </li> </ul> </div> <div class="paragraph"> <p>More details about how to deploy scripts to the server are available in the <a href="https://www.keycloak.org/docs/latest/server_development/#_script_providers">documentation</a>. Note that to use scripts, you are still required to enable the <code>scripts</code> technology preview feature.</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code>kc.[sh|bat] start --auto-build --features=preview</code></pre> </div> </div> <div class="paragraph"> <p>When deploying scripts, the server is going to automatically create their corresponding providers so that you can select them when configuring authentication flows, mappers, and authorization policies.</p> </div> <div class="paragraph"> <p>In general, the steps to update your realms are the following:</p> </div> <div class="ulist"> <ul> <li> <p>Before upgrading, remove any script provider you are using.</p> </li> <li> <p>After the upgrade, deploy your scripts following the instructions in the <a href="https://www.keycloak.org/docs/latest/server_development/#_script_providers">documentation</a>.</p> </li> <li> <p>Update your authentication flows, mappers, and the client authorization settings to use the providers created from the scripts deployed to the server.</p> </li> </ul> </div> </div> <div class="sect3"> <h4 id="account-console-patternfly-upgrade"><a class="anchor" href="#account-console-patternfly-upgrade"></a>Account console Patternfly upgrade</h4> <div class="paragraph"> <p>The Patternfly (PF) React libraries have been updated, <code>@patternfly/react-core</code> from v3.153.3 to v4.147.0, <code>@patternfly/react-icons</code> from v3.15.16 to v 4.11.8, and <code>@patternfly/react-styles</code> from v3.7.14 to v4.11.8. Several minor UI updates were made to bring the account console into alignment with PF design standards.</p> </div> <div class="paragraph"> <p>Custom developed account UIs might not be compatible with these updates due to the breaking changes in PF. Most breaking changes should be resolvable by updating props on PF components.</p> </div> <div class="paragraph"> <p>Resources:</p> </div> <div class="ulist"> <ul> <li> <p>[Patternfly docs](<a href="https://www.patternfly.org" class="bare">https://www.patternfly.org</a>)</p> </li> </ul> </div> <div class="paragraph"> <p>Components known to have breaking changes:</p> </div> <div class="ulist"> <ul> <li> <p>Alert</p> </li> <li> <p><code>action</code> prop changed to <code>actionClose</code></p> </li> <li> <p>Expandable</p> </li> <li> <p>renamed to <code>ExpandableSection</code></p> </li> <li> <p>Title</p> </li> <li> <p>size attr now uses <code>TitleSizes</code></p> </li> <li> <p>DataListContent</p> </li> <li> <p><code>noPadding</code> changed to <code>hasNoPadding</code></p> </li> <li> <p>Grid, Stack, Level, Gallery</p> </li> <li> <p><code>gutter</code> attr changed to <code>hasGutter</code></p> </li> <li> <p>Modal</p> </li> <li> <p>sizing control changed from, e.g. <code>isLarge</code>, to use <code>ModalVariant</code>, e.g. <code>variant={ModalVariant.large}</code></p> </li> <li> <p>Select</p> </li> <li> <p><code>ariaLabelTypeAhead</code> to <code>typeAheadAriaLabel</code></p> </li> <li> <p><code>isExpanded</code> to <code>isOpen</code></p> </li> <li> <p><code>ariaLabelledBy</code> to <code>aria-labelledby</code></p> </li> <li> <p>DataListContent</p> </li> <li> <p><code>noPadding</code> to <code>hasNoPadding</code></p> </li> </ul> </div> </div> <div class="sect3"> <h4 id="quarkus-distribution-split-metrics-enabled-option-into-health-enabled-and-metrics-enabled"><a class="anchor" href="#quarkus-distribution-split-metrics-enabled-option-into-health-enabled-and-metrics-enabled"></a>Quarkus distribution: Split metrics-enabled option into health-enabled and metrics-enabled</h4> <div class="paragraph"> <p>The <code>metrics-enabled</code> option now only enables the metrics for Keycloak. To enable the readiness and liveness health endpoints, there&#8217;s a new boolean option <code>health-enabled</code>. This allows more fine-grained usage of these options, e.g. enabling metrics but not enabling readiness/liveness probes for on-premise use cases. In order to keep the same behaviour as before when <code>metrics-enabled=true</code> was set, you need to additionally set <code>health-enabled=true</code> when building Keycloak.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-17-0-0"><a class="anchor" href="#migrating-to-17-0-0"></a>Migrating to 17.0.0</h3> <div class="sect3"> <h4 id="default-distribution-is-now-powered-by-quarkus"><a class="anchor" href="#default-distribution-is-now-powered-by-quarkus"></a>Default distribution is now powered by Quarkus</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/changes/changes-17_0_0.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/changes/changes-17_0_0.adoc&amp;description=%0A%0AFile:%20upgrading/topics/changes/changes-17_0_0.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 default distribution of Keycloak is now powered by Quarkus, which brings a number of breaking changes to you configure Keycloak and deploy custom providers. For more information check out the <a href="https://www.keycloak.org/migration/migrating-to-quarkus">Quarkus Migration Guide</a>.</p> </div> <div class="paragraph"> <p>The WildFly distribution of Keycloak is now deprecated, with support ending June 2022. We recommend migrating to the Quarkus distribution as soon as possible. However, if you need to remain on the legacy WildFly distribution for some time, there are some changes to consider:</p> </div> <div class="ulist"> <ul> <li> <p>Container images for the legacy distribution tags have changed. To use the legacy distribution use the tags <code>legacy</code> or <code>17.0.0-legacy</code>.</p> </li> <li> <p>Download on the website for the legacy distribution has changed to <code>keycloak-legacy-17.0.0.[zip|tar.gz]</code>.</p> </li> </ul> </div> <div class="paragraph"> <p>If you encounter problems migrating to the Quarkus distribution, missing ability to configure something, or have general ideas and feedback, please open a discussion in <a href="https://github.com/keycloak/keycloak/discussions/categories/keycloak-x-quarkus-distribution">GitHub Discussions</a>.</p> </div> </div> <div class="sect3"> <h4 id="migrating-from-the-preview-quarkus-distribution"><a class="anchor" href="#migrating-from-the-preview-quarkus-distribution"></a>Migrating from the preview Quarkus distribution</h4> <div class="paragraph"> <p>A number of things have changed since the preview Quarkus distribution was released in Keycloak 15.1.0. The ideal way to learn about what&#8217;s changed is to check out the new <a href="https://www.keycloak.org/guides#server">Server guides</a>. In summary, the changes include:</p> </div> <div class="ulist"> <ul> <li> <p>Container now published to <code>quay.io/keycloak/keycloak:latest</code> and <code>quay.io/keycloak/keycloak:17.0.0</code></p> </li> <li> <p>Download on website renamed to <code>keycloak-17.0.0.[zip|tar.gz]</code>.</p> </li> <li> <p><code>conf/keycloak.properties</code> changed to <code>conf/keycloak.conf</code>, which unifies configuration keys between the config file and CLI arguments.</p> </li> <li> <p>Clearer separation between <code>build options</code> and <code>runtime configuration</code>.</p> </li> <li> <p>Custom Quarkus configuration is done through <code>conf/quarkus.properties</code>.</p> </li> <li> <p><code>h2-mem</code> and <code>h2-file</code> databases renamed to <code>dev-mem</code> and <code>dev-file</code>.</p> </li> <li> <p>Features are now enabled/disabled with <code>--features</code> and <code>--features-disabled</code> replacing the previous approach that had a separate config key for each feature.</p> </li> <li> <p>Runtime configuration can no longer be passed to <code>kc.[sh|bat] build</code> and is no longer persisted in the build</p> </li> <li> <p>Logging level and format is now configured with <code>--log-level</code> and <code>--log-format</code>, while in the past these had to be configured using unsupported Quarkus properties.</p> </li> </ul> </div> </div> <div class="sect3"> <h4 id="client-policies-migration-client-scopes"><a class="anchor" href="#client-policies-migration-client-scopes"></a>Client Policies Migration : client-scopes</h4> <div class="paragraph"> <p>If you used a policy including client-scopes condition and edited JSON document directly, you will need to change the "scope" field name in a JSON document to "scopes".</p> </div> </div> <div class="sect3"> <h4 id="liquibase-upgraded-to-version-4-6-2"><a class="anchor" href="#liquibase-upgraded-to-version-4-6-2"></a>Liquibase upgraded to version 4.6.2</h4> <div class="paragraph"> <p>Liquibase was updated from version 3.5.5 to 4.6.2, which includes, among other things, several bug fixes, and a new way of registering custom extensions using <code>ServiceLoader</code>.</p> </div> <div class="paragraph"> <p>Migration from previous Keycloak versions to Keycloak 17.0.0 has been extensively tested with all currently supported databases, but we would like to stress the importance of closely following the <a href="#_upgrading">Upgrading Guide</a>, specifically of <strong>backing up existing database before upgrade</strong>. While we did our best to test the consequences of the Liquibase upgrade, some installations could be using specific setup unknown to us.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-16-0-0"><a class="anchor" href="#migrating-to-16-0-0"></a>Migrating to 16.0.0</h3> <div class="sect3"> <h4 id="wildfly-25-upgrade"><a class="anchor" href="#wildfly-25-upgrade"></a>WildFly 25 upgrade</h4> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/changes/changes-16_0_0.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/changes/changes-16_0_0.adoc&amp;description=%0A%0AFile:%20upgrading/topics/changes/changes-16_0_0.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>WildFly 25 deprecates the legacy security subsystem that among other things was used to configure TLS. Due to the amount of changes we are not able to provide migration scripts as we have done in the past.</p> </div> <div class="paragraph"> <p>We recommend that rather than copying configuration files from previous versions of Keycloak that you start with the default configuration files provided in Keycloak 16 and apply the relevant changes.</p> </div> <div class="paragraph"> <p>Configuration for the Keycloak subsystem can be copied directly.</p> </div> <div class="paragraph"> <p>For more information around the Elytron subsystem refer to the <a href="https://docs.wildfly.org/25/WildFly_Elytron_Security.html">WildFly documentation</a>.</p> </div> <div class="paragraph"> <p>We are really sorry for this inconvenience and understand this will make it significantly harder for everyone to upgrade to Keycloak 16, but we simply have not been able to find an alternative approach.</p> </div> <div class="paragraph"> <p>One thing worth pointing out is the switch to Quarkus distribution, which we plan to make fully supported in Keycloak 17, will make it significantly easier to configure and upgrade Keycloak.</p> </div> <div class="paragraph"> <p>For more information on WildFly 25 refer to the <a href="https://www.wildfly.org/news/2021/10/05/WildFly25-Final-Released/">WildFly 25 release notes</a>.</p> </div> </div> <div class="sect3"> <h4 id="proxy-environment-variables"><a class="anchor" href="#proxy-environment-variables"></a>Proxy environment variables</h4> <div class="paragraph"> <p>Keycloak now respects the standard <code>HTTP_PROXY</code>, <code>HTTPS_PROXY</code> and <code>NO_PROXY</code> environment variables for outgoing HTTP requests. This change could lead to unexpected use of a proxy server if you have for example the <code>HTTP_PROXY</code> variable defined but have no explicit proxy mappings specified in your SPI configuration. To prevent Keycloak from using those environment variables, you can explicitly create a no proxy route for all requests as <code>.*;NO_PROXY</code>.</p> </div> </div> <div class="sect3"> <h4 id="deprecated-features-in-the-keycloak-operator"><a class="anchor" href="#deprecated-features-in-the-keycloak-operator"></a>Deprecated features in the Keycloak Operator</h4> <div class="paragraph"> <p>With this release, we have deprecated and/or marked as unsupported some features in the Keycloak Operator. This concerns the Backup CRD and the operator managed Postgres Database.</p> </div> </div> <div class="sect3"> <h4 id="keycloak-operator-examples-including-unsupported-metrics-extension"><a class="anchor" href="#keycloak-operator-examples-including-unsupported-metrics-extension"></a>Keycloak Operator examples including unsupported Metrics extension</h4> <div class="paragraph"> <p>Previously, an unsupported metrics extension was added in the example for the creation of the Keycloak CR by the Keycloak Operator. This has been removed.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-14-0-0"><a class="anchor" href="#migrating-to-14-0-0"></a>Migrating to 14.0.0</h3> <div class="sect3"> <h4 id="client-policies-migration"><a class="anchor" href="#client-policies-migration"></a>Client policies migration</h4> <div class="paragraph"> <p>The Client policies feature was a preview feature since Keycloak 12 and did not have proper support. If you tried this feature and configured some client policies or client profiles in Keycloak 12 or Keycloak 13, then you will need to configure your client policies and client profiles again in the new version. The format of the configuration changed significantly as it was only a preview and hence we do not provide automatic migration of client policies and client profiles created in Keycloak 12 or Keycloak 13.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-13-0-0"><a class="anchor" href="#migrating-to-13-0-0"></a>Migrating to 13.0.0</h3> <div class="sect3"> <h4 id="manual-migration-step-needed"><a class="anchor" href="#manual-migration-step-needed"></a>Manual migration step needed</h4> <div class="paragraph"> <p>Manual change is required when the standalone.xml contains references to any of the SmallRye modules. SmallRye modules were removed from the underlying WildFly distribution, and the server does not start if the configuration references them. Thus if the configuration in the <code>standalone.xml</code> refers to these modules, the server configuration migration via <code>migrate-standalone.cli</code> fails before any changes are made to the configuration. In such case, to perform server configuration migration, you have to manually remove all the lines that refer to SmallRye modules. In the default configuration, you need to remove specifically the following lines:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;extension</span> <span class="attribute-name">module</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">org.wildfly.extension.microprofile.config-smallrye</span><span class="delimiter">&quot;</span></span><span class="tag">/&gt;</span> <span class="tag">&lt;extension</span> <span class="attribute-name">module</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">org.wildfly.extension.microprofile.health-smallrye</span><span class="delimiter">&quot;</span></span><span class="tag">/&gt;</span> <span class="tag">&lt;extension</span> <span class="attribute-name">module</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">org.wildfly.extension.microprofile.metrics-smallrye</span><span class="delimiter">&quot;</span></span><span class="tag">/&gt;</span></code></pre> </div> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;subsystem</span> <span class="attribute-name">xmlns</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">urn:wildfly:microprofile-config-smallrye:1.0</span><span class="delimiter">&quot;</span></span><span class="tag">/&gt;</span> <span class="tag">&lt;subsystem</span> <span class="attribute-name">xmlns</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">urn:wildfly:microprofile-health-smallrye:2.0</span><span class="delimiter">&quot;</span></span> <span class="attribute-name">security-enabled</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">false</span><span class="delimiter">&quot;</span></span> <span class="attribute-name">empty-liveness-checks-status</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">${env.MP_HEALTH_EMPTY_LIVENESS_CHECKS_STATUS:UP}</span><span class="delimiter">&quot;</span></span> <span class="attribute-name">empty-readiness-checks-status</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">${env.MP_HEALTH_EMPTY_READINESS_CHECKS_STATUS:UP}</span><span class="delimiter">&quot;</span></span><span class="tag">/&gt;</span> <span class="tag">&lt;subsystem</span> <span class="attribute-name">xmlns</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">urn:wildfly:microprofile-metrics-smallrye:2.0</span><span class="delimiter">&quot;</span></span> <span class="attribute-name">security-enabled</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">false</span><span class="delimiter">&quot;</span></span> <span class="attribute-name">exposed-subsystems</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">*</span><span class="delimiter">&quot;</span></span> <span class="attribute-name">prefix</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">${wildfly.metrics.prefix:wildfly}</span><span class="delimiter">&quot;</span></span><span class="tag">/&gt;</span></code></pre> </div> </div> </div> <div class="sect3"> <h4 id="upgrade-to-wildfly-23"><a class="anchor" href="#upgrade-to-wildfly-23"></a>Upgrade to Wildfly 23</h4> <div class="paragraph"> <p>The Keycloak server was upgraded to use Wildfly 23 as the underlying container. This does not directly involve any specific Keycloak server functionality, however, note these changes related to migration:</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Dependency updates</dt> <dd> <p>The dependencies were updated to the versions used by the Wildfly 23 server. For example, Infinispan is now <code>11.0.9.Final</code>.</p> </dd> <dt class="hdlist1">Configuration changes</dt> <dd> <p>A few configuration changes exist in the <code>standalone(-ha).xml</code> and <code>domain.xml</code> files. You should follow the <a href="#_install_new_version">Downloading the Keycloak server</a> section to handle the migration of configuration files automatically. However, here are the most important changes, which you may need if you made your own configuration changes:</p> <div class="ulist"> <ul> <li> <p>The <code>module</code> attribute of Infinispan cache containers is now <strong>deprecated</strong> (unused) and is <strong>replaced with</strong> the <code>modules</code> attribute, representing the set of modules associated with this cache container&#8217;s configuration. Moreover, there were also additional changes to attributes of various elements, originating from the use of Wildfly 23 as the underlying container. For example, the <code>managed-executor-service</code> and <code>managed-scheduled-executor-service</code> elements now recognize the new <code>hung-task-termination-period</code> attribute. See <a href="https://docs.wildfly.org/23/wildscribe/index.html">the Wildfly 23 full model reference</a> for details.</p> </li> </ul> </div> </dd> </dl> </div> </div> <div class="sect3"> <h4 id="upgrade-to-wildfly-22"><a class="anchor" href="#upgrade-to-wildfly-22"></a>Upgrade to Wildfly 22</h4> <div class="paragraph"> <p>The Keycloak server was upgraded to use Wildfly 22 as the underlying container. This does not directly involve any specific Keycloak server functionality, however, note these changes related to migration:</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Dependency updates</dt> <dd> <p>The dependencies were updated to the versions used by the Wildfly 22 server. For example, Infinispan is now <code>11.0.8.Final</code>.</p> </dd> <dt class="hdlist1">Configuration changes</dt> <dd> <p>A few configuration changes exist in the <code>standalone(-ha).xml</code> and <code>domain.xml</code> files. You should follow the <a href="#_install_new_version">Downloading the Keycloak server</a> section to handle the migration of configuration files automatically. However, here are the most important changes, which you may need if you made your own configuration changes:</p> <div class="ulist"> <ul> <li> <p>The <a href="https://docs.wildfly.org/22/Admin_Guide.html#MicroProfile_Config_SmallRye">Eclipse MicroProfile Config</a>, <a href="https://docs.wildfly.org/22/Admin_Guide.html#MicroProfile_Health_SmallRye">Eclipse MicroProfile Health</a>, and <a href="https://docs.wildfly.org/22/Admin_Guide.html#MicroProfile_Metrics_SmallRye">Eclipse MicroProfile Metrics</a> subsystems are replaced with <a href="https://docs.wildfly.org/22/Admin_Guide.html#Health">WildFly subsystem for health</a> and <a href="https://docs.wildfly.org/22/Admin_Guide.html#MicroProfile_Metrics_SmallRye">WildFly subsystem for base metrics</a>.</p> </li> <li> <p>The default Wildfly configuration now uses the ability to make use of an automatically generated self-signed certificate with Elytron. Refer to <a href="https://docs.wildfly.org/22/WildFly_Elytron_Security.html#update-wildfly-to-use-the-default-elytron-components-for-application-authentication">a dedicated <code>applicationSSC</code> server SSL context section</a> for details.</p> </li> </ul> </div> </dd> </dl> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-12-0-2"><a class="anchor" href="#migrating-to-12-0-2"></a>Migrating to 12.0.2</h3> <div class="sect3"> <h4 id="read-only-attributes"><a class="anchor" href="#read-only-attributes"></a>Read-only attributes</h4> <div class="paragraph"> <p>There was added support for the read-only user attributes. This includes the user attributes, which are not supposed to be edited by the user or by the administrator when updating user with REST API or with the Keycloak user interfaces. It can be important especially if you use:</p> </div> <div class="ulist"> <ul> <li> <p>Custom user storage providers</p> </li> <li> <p>Custom authenticators</p> </li> <li> <p>Custom JavaScript authorization policies, which establish authorization based on some user attribute</p> </li> <li> <p>X.509 authenticator with custom attribute for mapping the X.509 certificate to the user identity</p> </li> <li> <p>Any other custom functionality, where some of the user attributes are used as the metadata for storing authentication/authorization/identity context rather than simple user profile information.</p> </li> </ul> </div> <div class="paragraph"> <p>See the details in the <a href="https://www.keycloak.org/docs/26.0.6/server_admin/#read_only_user_attributes">Threat model mitigation chapter</a>.</p> </div> </div> <div class="sect3"> <h4 id="valid-request-uris"><a class="anchor" href="#valid-request-uris"></a>Valid Request URIs</h4> <div class="paragraph"> <p>If you use the OpenID Connect parameter <code>request_uri</code>, a requirement exists that your client needs to have <code>Valid Request URIs</code> configured. This can be configured through the admin console on the client details page or through the admin REST API or client registration API. Valid Request URIs need to contain the list of Request URI values, which are permitted for the particular client. This is to avoid SSRF attacks. There is possibility to use wildcards or relative paths similarly such as the <code>Valid Redirect URIs</code> option, however for security purposes, we typically recommend to use as specific value as possible.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-13-0-0-2"><a class="anchor" href="#migrating-to-13-0-0-2"></a>Migrating to 13.0.0</h3> <div class="sect3"> <h4 id="upgrade-to-wildfly-22-2"><a class="anchor" href="#upgrade-to-wildfly-22-2"></a>Upgrade to Wildfly 22</h4> <div class="paragraph"> <p>The Keycloak server was upgraded to use Wildfly 22 as the underlying container. This does not directly involve any specific Keycloak server functionality, but a few changes related to the migration, which are worth mentioning.</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Dependency updates</dt> <dd> <p>The dependencies were updated to the versions used by Wildfly 22 server. For example, Infinispan is now <code>11.0.8.Final</code>.</p> </dd> <dt class="hdlist1">Configuration changes</dt> <dd> <p>A few configuration changes exist in the <code>standalone(-ha).xml</code> and <code>domain.xml</code> files. You should follow the <a href="#_install_new_version">Downloading the Keycloak server</a> section to handle the migration of configuration files automatically. If more detail is needed, because, for example, you did some configuration changes on your own, the list of the most important changes follows:</p> <div class="ulist"> <ul> <li> <p>The <a href="https://docs.wildfly.org/22/Admin_Guide.html#MicroProfile_Config_SmallRye">Eclipse MicroProfile Config</a>, <a href="https://docs.wildfly.org/22/Admin_Guide.html#MicroProfile_Health_SmallRye">Eclipse MicroProfile Health</a>, and <a href="https://docs.wildfly.org/22/Admin_Guide.html#MicroProfile_Metrics_SmallRye">Eclipse MicroProfile Metrics</a> subsystems were replaced by <a href="https://docs.wildfly.org/22/Admin_Guide.html#Health">WildFly subsystem for health</a> and <a href="https://docs.wildfly.org/22/Admin_Guide.html#MicroProfile_Metrics_SmallRye">WildFly subsystem for base metrics</a>.</p> </li> <li> <p>The default Wildfly configuration now utilizes the ability to make use of an automatically generated self-signed certificate with Elytron. Refer to <a href="https://docs.wildfly.org/22/WildFly_Elytron_Security.html#update-wildfly-to-use-the-default-elytron-components-for-application-authentication">a dedicated <code>applicationSSC</code> server SSL context section</a> for details.</p> </li> </ul> </div> </dd> </dl> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-12-0-0"><a class="anchor" href="#migrating-to-12-0-0"></a>Migrating to 12.0.0</h3> <div class="sect3"> <h4 id="upgrade-to-wildfly-21"><a class="anchor" href="#upgrade-to-wildfly-21"></a>Upgrade to Wildfly 21</h4> <div class="paragraph"> <p>The Keycloak server was upgraded to use Wildfly 21 as the underlying container. This does not directly involve any specific Keycloak server functionality, however, note these changes related to migration:</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Dependency updates</dt> <dd> <p>The dependencies were updated to the versions used by the Wildfly 21 server. For example, Infinispan is now 11.0.4.Final.</p> </dd> <dt class="hdlist1">Configuration changes</dt> <dd> <p>A few configuration changes exist in the <code>standalone(-ha).xml</code> and <code>domain.xml</code> files. You should follow the <a href="#_install_new_version">Downloading the Keycloak server</a> section to handle the migration of configuration files automatically. However, here are the most important changes, which you may need if you made your own configuration changes:</p> <div class="ulist"> <ul> <li> <p>The <code>object-memory</code> element of Infinispan caches is now <strong>deprecated</strong> (unused) and is <strong>replaced with</strong> the <code>heap-memory</code> element.</p> </li> </ul> </div> </dd> </dl> </div> </div> <div class="sect3"> <h4 id="skip-creation-of-user-session-for-the-docker-protocol-authentication"><a class="anchor" href="#skip-creation-of-user-session-for-the-docker-protocol-authentication"></a>Skip creation of user session for the Docker protocol authentication</h4> <div class="paragraph"> <p>No user session is created after successful authentication with the Docker protocol. For details, please refer to the <a href="https://www.keycloak.org/docs/26.0.6/server_admin/#_docker">Server Administration Guide</a>.</p> </div> </div> <div class="sect3"> <h4 id="upgrade-to-patternfly-4"><a class="anchor" href="#upgrade-to-patternfly-4"></a>Upgrade to PatternFly 4</h4> <div class="paragraph"> <p>The Keycloak login theme components have been upgraded to PatternFly 4. The old PatternFly 3 runs simultaneously with the new one, so it&#8217;s possible to keep PF3 components. However, some changes to the design of the login theme were performed. Please upgrade your custom login theme due them. An example with the necessary changes can be found in the <code>keycloak/examples/themes/theme/sunrise</code> directory. No additional setup is required.</p> </div> </div> <div class="sect3"> <h4 id="client-credentials-grant-without-refresh-token-by-default"><a class="anchor" href="#client-credentials-grant-without-refresh-token-by-default"></a>Client Credentials Grant without refresh token by default</h4> <div class="paragraph"> <p>From this Keycloak version, the OAuth2 Client Credentials Grant endpoint does not issue refresh tokens by default. This behavior is aligned with the OAuth2 specification. As a side effect of this change, no user session is created on the Keycloak server side after successful Client Credentials authentication, which results in improved performance and memory consumption. Clients that use Client Credentials Grant are encouraged to stop using refresh tokens and instead always authenticate at every request with <code>grant_type=client_credentials</code> instead of using <code>refresh_token</code> as grant type. In relation to this, Keycloak has support for revocation of access tokens in the OAuth2 Revocation Endpoint, hence clients are allowed to revoke individual access tokens if needed.</p> </div> <div class="paragraph"> <p>For backwards compatibility, a possibility to stick to the behavior of old versions exists. When this is used, the refresh token will be still issued after a successful authentication with the Client Credentials Grant and also the user session will be created. This can be enabled for the particular client in the Keycloak admin console, in client details in the section with <code>OpenID Connect Compatibility Modes</code> with the switch <code>Use Refresh Tokens For Client Credentials Grant</code>.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-11-0-0"><a class="anchor" href="#migrating-to-11-0-0"></a>Migrating to 11.0.0</h3> <div class="sect3"> <h4 id="upgrade-to-wildfly-20"><a class="anchor" href="#upgrade-to-wildfly-20"></a>Upgrade to Wildfly 20</h4> <div class="paragraph"> <p>The Keycloak server was upgraded to use Wildfly 20 as the underlying container. This does not directly involve any specific Keycloak server functionality, however, note these changes related to migration:</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Dependency updates</dt> <dd> <p>The dependencies were updated to the versions used by the Wildfly 20 server. For example, Infinispan is now 10.1.8.Final.</p> </dd> <dt class="hdlist1">Configuration changes</dt> <dd> <p>A few configuration changes exist in the <code>standalone(-ha).xml</code> and <code>domain.xml</code> files. You should follow the <a href="#_install_new_version">Downloading the Keycloak server</a> section to handle the migration of configuration files automatically.</p> </dd> <dt class="hdlist1">Cross-Datacenter Replication changes</dt> <dd> <div class="ulist"> <ul> <li> <p>You will need to upgrade Infinispan server to version 9.4.19. The older version may still work, but it is not guaranteed as they are not tested anymore.</p> </li> <li> <p>It is recommended to use the <code>protocolVersion</code> property added to the <code>remote-store</code> element when configuring Infinispan caches. When connecting to the Infinispan server 9.4.18, the recommended version of the hotrod protocol version is 2.9 as the Infinispan library version differs among Keycloak server and Infinispan server. For more details, see the Cross-Datacenter documentation.</p> </li> <li> <p>It is recommended to use <code>remoteStoreSecurityEnabled</code> property under <code>connectionsInfinispan</code> subsystem. For more details, see the Cross-Datacenter documentation.</p> </li> </ul> </div> </dd> </dl> </div> </div> <div class="sect3"> <h4 id="ldap-no-import-bugfix"><a class="anchor" href="#ldap-no-import-bugfix"></a>LDAP no-import bugfix</h4> <div class="paragraph"> <p>In the previous Keycloak version, when the LDAP provider was configured with <code>Import Users</code> OFF, it was possible to update the user even if some of non-LDAP mapped attributes were changed. This situation resulted in confusing behavior, when the attribute appeared to be updated, but it was not. In the current version, the update is not allowed to be performed at all if any non-LDAP mapped attributes are changed.</p> </div> <div class="paragraph"> <p>This should not affect most of the deployments, but some can be affected under some rare circumstances. For example if you previously tried to update a user with the admin REST API and the user had some incorrect attribute changes, the update was possible. With the current version, the update is not possible and you will be immediately informed about the reason.</p> </div> </div> <div class="sect3"> <h4 id="usermodel-changes"><a class="anchor" href="#usermodel-changes"></a>UserModel changes</h4> <div class="paragraph"> <p>The fields <code>username</code>, <code>email</code>, <code>firstName</code> and <code>lastName</code> in the <code>UserModel</code> are migrated to custom attributes as a preparation for adding more sophisticated user profiles to Keycloak in an upcoming version. If a database contains users with custom attributes of that exact name, the custom attributes will need to be migrated before upgrading. This migration does not occur automatically. Otherwise, they will not be read from the database anymore and possibly deleted. This situation implies that the <code>username</code> can now also be accessed and set via <code>UserModel.getFirstAttribute(UserModel.USERNAME)</code>. Similar implications exist for other fields. Implementers of SPIs subclassing the <code>UserModel</code> directly or indirectly should ensure that the behavior between <code>setUsername</code> and <code>setSingleAttribute(UserModel.USERNAME, &#8230;&#8203;)</code> (and similar for the other fields) is consistent. Users of the policy evaluation feature have to adapt their policies if they use the number of attributes in their evaluations since every user will now have four new attributes by default.</p> </div> <div class="paragraph"> <p>The public API of <code>UserModel</code> did not change. No changes to frontend resources or SPIs accessing user data are necessary. Also, the database did not change yet.</p> </div> </div> <div class="sect3"> <h4 id="instagram-idp-migrated-to-new-the-api"><a class="anchor" href="#instagram-idp-migrated-to-new-the-api"></a>Instagram IdP migrated to new the API</h4> <div class="paragraph"> <p>Instagram IdP now uses new API as the old legacy API was <strong>deprecated</strong>. This requires getting new API credentials. For details, please refer to the <a href="https://www.keycloak.org/docs/26.0.6/server_admin/#instagram">Server Administration Guide</a>.</p> </div> <div class="paragraph"> <p>Special attention is required for existing users that use Instagram IdP, specially the ones for whom it is the only authentication option. Such users have to log in to Keycloak using Instagram IdP before September 30th, 2020. After that day they&#8217;ll have to use a different authentication method (like password) to log in to manually update their Instagram social link, or create a new account in Keycloak. This is because Instagram user IDs are not compatible between the old and new API, however the new API temporarily returns both new and old user IDs to allow migration. Keycloak automatically migrates the ID once user logs in.</p> </div> </div> <div class="sect3"> <h4 id="non-standard-token-introspection-endpoint-removed"><a class="anchor" href="#non-standard-token-introspection-endpoint-removed"></a>Non-standard token introspection endpoint removed</h4> <div class="paragraph"> <p>In previous versions, Keycloak advertised two introspection endpoints: <code>token_introspection_endpoint</code> and <code>introspection_endpoint</code>. The latter is the one defined by <a href="https://datatracker.ietf.org/doc/html/rfc8414#section-2">RFC-8414</a>. The former, previously deprecated, has now been removed.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-9-0-1"><a class="anchor" href="#migrating-to-9-0-1"></a>Migrating to 9.0.1</h3> <div class="sect3"> <h4 id="legacy-promise-in-javascript-adapter"><a class="anchor" href="#legacy-promise-in-javascript-adapter"></a>Legacy promise in JavaScript adapter</h4> <div class="paragraph"> <p>It is no longer necessary to set promiseType in the JavaScript adapter, and both are available at the same time. It is recommended to update applications to use native promise API (<code>then</code> and <code>catch</code>) as soon as possible, as the legacy API (<code>success</code> and <code>error</code>) will be removed at some point.</p> </div> </div> <div class="sect3"> <h4 id="duplicated-top-level-groups"><a class="anchor" href="#duplicated-top-level-groups"></a>Duplicated top level groups</h4> <div class="paragraph"> <p>Version 9.0.1 fixes a problem which could create duplicated top level groups in the realm. Nevertheless the existence of previous duplicated groups makes the upgrade process fail. The Keycloak server can be affected by this issue if it is using an H2, MariaDB, MySQL or PostgreSQL database. Before launching the upgrade, check if the server contains duplicated top level groups. For example the following SQL query can be executed at database level to list them:</p> </div> <div class="listingblock"> <div class="content"> <pre>SELECT REALM_ID, NAME, COUNT(*) FROM KEYCLOAK_GROUP WHERE PARENT_GROUP is NULL GROUP BY REALM_ID, NAME HAVING COUNT(*) &gt; 1;</pre> </div> </div> <div class="paragraph"> <p>Only one top level group can exist in each realm with the same name. Duplicates should be reviewed and deleted before the upgrade. The error in the upgrade contains the message <code>Change Set META-INF/jpa-changelog-9.0.1.xml::9.0.1- KEYCLOAK-12579-add-not-null-constraint::keycloak failed.</code></p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-9-0-0"><a class="anchor" href="#migrating-to-9-0-0"></a>Migrating to 9.0.0</h3> <div class="sect3"> <h4 id="improved-handling-of-user-locale"><a class="anchor" href="#improved-handling-of-user-locale"></a>Improved handling of user locale</h4> <div class="paragraph"> <p>A number of improvements have been made to how the locale for the login page is selected, as well as when the locale is updated for a user.</p> </div> <div class="paragraph"> <p>See the <a href="https://www.keycloak.org/docs/26.0.6/server_admin/#_user_locale_selection">Server Administration Guide</a> for more details.</p> </div> </div> <div class="sect3"> <h4 id="deprecated-methods-in-token-representation-java-classes"><a class="anchor" href="#deprecated-methods-in-token-representation-java-classes"></a>Deprecated methods in token representation Java classes</h4> <div class="paragraph"> <p>In the year 2038 an <code>int</code> is no longer able to hold the value of seconds since 1970, as such we are working on updating these to <code>long</code> values. Moreover, another issue related with processing of <code>int</code> values exists in token representation. An <code>int</code> will by default result into <code>0</code> in the JSON representation, while it should not be included.</p> </div> <div class="paragraph"> <p>See JavaDocs for further details on exact methods that have been deprecated and replacement methods.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-8-0-2"><a class="anchor" href="#migrating-to-8-0-2"></a>Migrating to 8.0.2</h3> <div class="sect3"> <h4 id="more-authentication-flows-changes"><a class="anchor" href="#more-authentication-flows-changes"></a>More authentication flows changes</h4> <div class="dlist"> <dl> <dt class="hdlist1">REQUIRED and ALTERNATIVE executions not supported at same flow</dt> <dd> <p>In previous version, it was possible to have REQUIRED and ALTERNATIVE executions in the same authentication flow at the same level. There were some issues with this approach and we did the refactoring in the Authentication SPI, which means that this is not considered valid anymore. If ALTERNATIVE and REQUIRED executions are configured at the same level, the ALTERNATIVE executions are considered disabled. So when migrating to the newest version, your existing authentication flows will be automatically migrated preserved the same behavior as existed in the previous version. If they contain ALTERNATIVE executions at the same level as some REQUIRED executions, then the ALTERNATIVE executions will be added to the separate REQUIRED subflow. This should ensure same/similar behavior of the particular authentication flow as in the previous version. We always recommend to double-check the configuration of your authentication flow and test it to double-check that everything works as expected. This recommendation is true in particular if you have some more customized authentication flows with custom authenticator implementations.</p> </dd> </dl> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-8-0-0"><a class="anchor" href="#migrating-to-8-0-0"></a>Migrating to 8.0.0</h3> <div class="sect3"> <h4 id="new-default-hostname-provider"><a class="anchor" href="#new-default-hostname-provider"></a>New default Hostname provider</h4> <div class="paragraph"> <p>The old request and fixed hostname providers are replaced with a new default hostname provider. The request and fixed hostname providers are now deprecated and it is recommended to switch to the default hostname provider as soon as possible.</p> </div> </div> <div class="sect3"> <h4 id="upgrade-to-wildfly-18"><a class="anchor" href="#upgrade-to-wildfly-18"></a>Upgrade to Wildfly 18</h4> <div class="paragraph"> <p>The Keycloak server was upgraded to use Wildfly 18 as the underlying container. This does not directly involve any specific Keycloak server functionality, however, note these changes related to migration:</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Dependency updates</dt> <dd> <p>The dependencies were updated to the versions used by the Wildfly 18 server. For example, Infinispan is now 9.4.16.Final.</p> </dd> <dt class="hdlist1">Configuration changes</dt> <dd> <p>A few configuration changes exist in the <code>standalone(-ha).xml</code> and <code>domain.xml</code> files. You should follow the <a href="#_install_new_version">Downloading the Keycloak server</a> section to handle the migration of configuration files automatically.</p> </dd> <dt class="hdlist1">Cross-Datacenter Replication changes</dt> <dd> <div class="ulist"> <ul> <li> <p>You will need to upgrade Infinispan server to version 9.4.19. The older version may still work, but it is not guaranteed as we don&#8217;t test it anymore.</p> </li> </ul> </div> </dd> </dl> </div> </div> <div class="sect3"> <h4 id="deploying-scripts-to-the-server"><a class="anchor" href="#deploying-scripts-to-the-server"></a>Deploying scripts to the server</h4> <div class="paragraph"> <p>Until now, administrators were allowed to upload scripts to the server through the Keycloak Administration Console as well as through the RESTful Admin API.</p> </div> <div class="paragraph"> <p>For now on, this capability is <strong>disabled</strong> by default and users should prefer to deploy scripts directly to the server. For more details, please take a look at <a href="https://www.keycloak.org/docs/26.0.6/server_development/#_script_providers">JavaScript Providers</a>.</p> </div> </div> <div class="sect3"> <h4 id="client-credentials-in-the-javascript-adapter"><a class="anchor" href="#client-credentials-in-the-javascript-adapter"></a>Client credentials in the JavaScript adapter</h4> <div class="paragraph"> <p>In the previous releases, developers were allowed to provide client credentials to the JavaScript adapter. For now on, this capability was <strong>removed</strong>, because client-side apps are not safe to keep secrets.</p> </div> </div> <div class="sect3"> <h4 id="authentication-flows-changes"><a class="anchor" href="#authentication-flows-changes"></a>Authentication flows changes</h4> <div class="paragraph"> <p>We did some refactoring and improvements related to the authentication flows, which requires some attention during migration.</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">OPTIONAL execution requirement removed</dt> <dd> <p>Regarding migration, the most important change is removing the support for the OPTIONAL requirement from authentication executions and replacing it with the CONDITIONAL requirement, which allows more flexibility. The existing OPTIONAL authenticators configured in the previous version are replaced with the CONDITIONAL subflows. These subflows have the <code>Condition - User Configured</code> condition configured as first execution, and the previously OPTIONAL authenticator (for example <code>OTP Form</code>) as second execution. From the user&#8217;s point of view, the behavior during authentication is the same as in the previous version.</p> </dd> <dt class="hdlist1">Changes in the Java SPI</dt> <dd> <p>Some changes exist in the Java Authentication SPI and Credential Provider SPI. The interface <code>Authenticator</code> is not changed, but you may be affected if you&#8217;re developing more advanced authenticators, which introduce some new credential types (subclasses of <code>CredentialModel</code>). There are changes on the <code>CredentialProvider</code> interface and introduction of some new interfaces like <code>CredentialValidator</code>. Also you may be affected if your authenticator supported the OPTIONAL execution requirement. It is recommended to double-check the latest authentication examples in the server development guide for more details.</p> </dd> <dt class="hdlist1">Freemarker template changes</dt> <dd> <p>Some changes in the freemarker templates exist. You may be affected if you have your own theme with custom freemarker templates for login forms or some account forms, especially for the forms related to OTP. It is recommended to double-check changes in the Freemarker templates in the latest Keycloak and align your templates according to it.</p> </dd> </dl> </div> </div> <div class="sect3"> <h4 id="user-credentials-changes"><a class="anchor" href="#user-credentials-changes"></a>User credentials changes</h4> <div class="paragraph"> <p>We added more flexibility around storing of user credentials. Among other things, every user can have multiple credentials of the same type, for example multiple OTP credentials. As a result, some changes to the database schema were performed. However the credentials from the previous version should be automatically updated to the new format and users should be still able to login with their passwords or OTP credentials set in the previous version.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-7-0-0"><a class="anchor" href="#migrating-to-7-0-0"></a>Migrating to 7.0.0</h3> <div class="sect3"> <h4 id="upgrade-to-wildfly-17"><a class="anchor" href="#upgrade-to-wildfly-17"></a>Upgrade to Wildfly 17</h4> <div class="paragraph"> <p>The Keycloak server was upgraded to use Wildfly 17 as the underlying container. This does not directly involve any specific Keycloak server functionality, however, note these changes related to migration:</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Dependency updates</dt> <dd> <p>The dependencies were updated to the versions used by the Wildfly 17 server. For example, Infinispan is now 9.4.14.Final.</p> </dd> <dt class="hdlist1">Configuration changes</dt> <dd> <p>A few configuration changes exist in the <code>standalone(-ha).xml</code> and <code>domain.xml</code> files. You should follow the <a href="#_install_new_version">Downloading the Keycloak server</a> section to handle the migration of configuration files automatically.</p> </dd> <dt class="hdlist1">Cross-Datacenter Replication changes</dt> <dd> <div class="ulist"> <ul> <li> <p>You will need to upgrade Infinispan server to version 9.4.19. The older version may still work, but it is not guaranteed as we don&#8217;t test it anymore.</p> </li> </ul> </div> </dd> </dl> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-6-0-0"><a class="anchor" href="#migrating-to-6-0-0"></a>Migrating to 6.0.0</h3> <div class="sect3"> <h4 id="upgrade-to-wildfly-16"><a class="anchor" href="#upgrade-to-wildfly-16"></a>Upgrade to Wildfly 16</h4> <div class="paragraph"> <p>The Keycloak server was upgraded to use Wildfly 16 as the underlying container. This does not directly involve any specific Keycloak server functionality, however, note these changes related to migration:</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Dependency updates</dt> <dd> <p>The dependencies were updated to the versions used by the Wildfly 16 server. For example, Infinispan is now 9.4.8.Final.</p> </dd> <dt class="hdlist1">Configuration changes</dt> <dd> <p>A few configuration changes exist in the <code>standalone(-ha).xml</code> and <code>domain.xml</code> files. You should follow the <a href="#_install_new_version">Downloading the Keycloak server</a> section to handle the migration of configuration files automatically.</p> </dd> <dt class="hdlist1">Cross-Datacenter Replication changes</dt> <dd> <div class="ulist"> <ul> <li> <p>You will need to upgrade Infinispan server to version 9.4.19. The older version may still work, but it is not guaranteed as we don&#8217;t test it anymore.</p> </li> </ul> </div> </dd> </dl> </div> </div> <div class="sect3"> <h4 id="new-optional-client-scope"><a class="anchor" href="#new-optional-client-scope"></a>New optional client scope</h4> <div class="paragraph"> <p>We have added a new <code>microprofile-jwt</code> optional client scope to handle the claims defined in the <a href="https://github.com/eclipse/microprofile/wiki/JWT_Auth">MicroProfile/JWT Auth Specification</a>. This new client scope defines protocol mappers to set the username of the authenticated user to the <code>upn</code> claim and to set the realm roles to the <code>groups</code> claim.</p> </div> </div> <div class="sect3"> <h4 id="ability-to-propagate-promptnone-to-default-idp"><a class="anchor" href="#ability-to-propagate-promptnone-to-default-idp"></a>Ability to propagate prompt=none to default IDP</h4> <div class="paragraph"> <p>We have added a new switch in the OIDC identity provider configuration named <code>Accepts prompt=none forward from client</code> to identify IDPs that are able to handle forwarded requests that include the <code>prompt=none</code> query parameter.</p> </div> <div class="paragraph"> <p>Until now, when receiving an auth request with <code>prompt=none</code> a realm would return a <code>login_required</code> error if the user is not authenticated in the realm without checking if the user has been authenticated by an IDP. From now on, if a default IDP can be determined for the auth request (either by the use of the <code>kc_idp_hint</code> query param or by setting up a default IDP for the realm) and if the <code>Accepts prompt=none forward from client</code> switch has been enabled for the IDP, the auth request is forwarded to the IDP to check if the user has been authenticated there.</p> </div> <div class="paragraph"> <p>It is important to note that this switch is only taken into account if a default IDP is specified, in which case we know where to forward the auth request without having to prompt the user to select an IDP. If a default IDP cannot be determined we cannot assume which one will be used to fulfill the auth request so the request forwarding is not performed.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-5-0-0"><a class="anchor" href="#migrating-to-5-0-0"></a>Migrating to 5.0.0</h3> <div class="sect3"> <h4 id="upgrade-to-wildfly-15"><a class="anchor" href="#upgrade-to-wildfly-15"></a>Upgrade to Wildfly 15</h4> <div class="paragraph"> <p>The Keycloak server was upgraded to use Wildfly 15 as the underlying container. This does not directly involve any specific Keycloak server functionality, however, note these changes related to migration:</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Dependency updates</dt> <dd> <p>The dependencies were updated to the versions used by the Wildfly 15 server. For example, Infinispan is now 9.4.3.Final.</p> </dd> <dt class="hdlist1">Configuration changes</dt> <dd> <p>A few configuration changes exist in the <code>standalone(-ha).xml</code> and <code>domain.xml</code> files. You should follow the <a href="#_install_new_version">Downloading the Keycloak server</a> section to handle the migration of configuration files automatically.</p> </dd> <dt class="hdlist1">Cross-Datacenter Replication changes</dt> <dd> <div class="ulist"> <ul> <li> <p>You will need to upgrade Infinispan server to version 9.4.19. The older version may still work, but it is not guaranteed as we don&#8217;t test it anymore.</p> </li> </ul> </div> </dd> </dl> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-4-8-2"><a class="anchor" href="#migrating-to-4-8-2"></a>Migrating to 4.8.2</h3> <div class="sect3"> <h4 id="google-identity-provider-updated-to-use-google-sign-in-authentication-system"><a class="anchor" href="#google-identity-provider-updated-to-use-google-sign-in-authentication-system"></a>Google Identity Provider updated to use Google Sign-in authentication system</h4> <div class="paragraph"> <p>The Google Identity Provider implementation in Keycloak up to version 4.8.1 relies on the Google+ API endpoints for authorization and obtaining the user profile. From March 2019 onwards, Google is removing support for the Google+ API in favor of the new Google Sign-in authentication system. The Keycloak identity provider has been updated to use the new endpoints so if this integration is in use make sure you upgrade to Keycloak version 4.8.2 or later.</p> </div> <div class="paragraph"> <p>If you run into an error saying that the application identifier was not found in the directory, you will have to register the client application again in the <a href="https://console.cloud.google.com/apis/credentials">Google API Console</a> portal to obtain a new application id and secret.</p> </div> <div class="paragraph"> <p>It is possible that you will need to adjust custom mappers for non-standard claims that were provided by Google+ user information endpoint and are provided under different name by Google Sign-in API. Please consult Google documentation for the most up-to-date information on available claims.</p> </div> </div> <div class="sect3"> <h4 id="linkedin-social-broker-updated-to-version-2-of-linkedin-apis"><a class="anchor" href="#linkedin-social-broker-updated-to-version-2-of-linkedin-apis"></a>LinkedIn social broker updated to Version 2 of LinkedIn APIs</h4> <div class="paragraph"> <p>Accordingly with LinkedIn, all developers need to migrate to version 2.0 of their APIs and OAuth 2.0. As such, we have updated our LinkedIn Social Broker.</p> </div> <div class="paragraph"> <p>Existing deployments using this broker may start experiencing errors when fetching user&#8217;s profile using version 2 of LinkedIn APIs. This error may be related with the lack of permissions granted to the client application used to configure the broker which may not be authorized to access the Profile API or request specific OAuth2 scopes during the authentication process.</p> </div> <div class="paragraph"> <p>Even for newly created LinkedIn client applications, you need to make sure that the client is able to request the <code>r_liteprofile</code> and <code>r_emailaddress</code> OAuth2 scopes, at least, as well that the client application can fetch current member&#8217;s profile from the <code><a href="https://api.linkedin.com/v2/me" class="bare">https://api.linkedin.com/v2/me</a></code> endpoint.</p> </div> <div class="paragraph"> <p>Due to these privacy restrictions imposed by LinkedIn in regards to access to member&#8217;s information and the limited set of claims returned by the current member&#8217;s Profile API, the LinkedIn Social Broker is now using the member&#8217;s email address as the default username. That means that the <code>r_emailaddress</code> is always set when sending authorization requests during the authentication.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-4-6-0"><a class="anchor" href="#migrating-to-4-6-0"></a>Migrating to 4.6.0</h3> <div class="sect3"> <h4 id="new-default-client-scopes"><a class="anchor" href="#new-default-client-scopes"></a>New default client scopes</h4> <div class="paragraph"> <p>We have added new realm default client scopes <code>roles</code> and <code>web-origins</code>. These client scopes contain protocol mappers to add the roles of the user and allowed web origins to the token. During migration, these client scopes should be automatically added to all the OpenID Connect clients as default client scopes. Hence no setup should be required after database migration is finished.</p> </div> <div class="sect4"> <h5 id="protocol-mapper-spi-addition"><a class="anchor" href="#protocol-mapper-spi-addition"></a>Protocol mapper SPI addition</h5> <div class="paragraph"> <p>Related to this, a small addition to the (unsupported) Protocol Mappers SPI exists. You can be affected only if you implemented a custom ProtocolMapper. A new <code>getPriority()</code> method on the ProtocolMapper interface got introduced. The method has the default implementation set to return 0. If your protocol mapper implementation relies on the roles in the access token <code>realmAccess</code> or <code>resourceAccess</code> properties, you may need to increase the priority of your mapper.</p> </div> </div> <div class="sect4"> <h5 id="audience-resolving"><a class="anchor" href="#audience-resolving"></a>Audience resolving</h5> <div class="paragraph"> <p>Audiences of all the clients, for which authenticated user has at least one client role in the token, are automatically added to the <code>aud</code> claim in the access token now. On the other hand, an access token may not automatically contain the audience of the frontend client, for which it was issued. Read the <a href="https://www.keycloak.org/docs/26.0.6/server_admin/#audience-support">Server Administration Guide</a> for more details.</p> </div> </div> </div> <div class="sect3"> <h4 id="javascript-adapter-promise"><a class="anchor" href="#javascript-adapter-promise"></a>JavaScript adapter promise</h4> <div class="paragraph"> <p>To use native JavaScript promise with the JavaScript adapter it is now required to set <code>promiseType</code> to <code>native</code> in the init options.</p> </div> <div class="paragraph"> <p>In the past if native promise was available a wrapper was returned that provided both the legacy Keycloak promise and the native promise. This was causing issues as the error handler was not always set prior to the native error event, which resulted in <code>Uncaught (in promise)</code> error.</p> </div> </div> <div class="sect3"> <h4 id="microsoft-identity-provider-updated-to-use-the-microsoft-graph-api"><a class="anchor" href="#microsoft-identity-provider-updated-to-use-the-microsoft-graph-api"></a>Microsoft Identity Provider updated to use the Microsoft Graph API</h4> <div class="paragraph"> <p>The Microsoft Identity Provider implementation in Keycloak up to version 4.5.0 relies on the Live SDK endpoints for authorization and obtaining the user profile. From November 2018 onwards, Microsoft is removing support for the Live SDK API in favor of the new Microsoft Graph API. The Keycloak identity provider has been updated to use the new endpoints so if this integration is in use make sure you upgrade to Keycloak version 4.6.0 or later.</p> </div> <div class="paragraph"> <p>Legacy client applications registered under "Live SDK applications" won&#8217;t work with the Microsoft Graph endpoints due to changes in the id format of the applications. If you run into an error saying that the application identifier was not found in the directory, you will have to register the client application again in the <a href="https://account.live.com/developers/applications/create">Microsoft Application Registration</a> portal to obtain a new application id.</p> </div> </div> <div class="sect3"> <h4 id="upgrade-to-wildfly-14"><a class="anchor" href="#upgrade-to-wildfly-14"></a>Upgrade to Wildfly 14</h4> <div class="paragraph"> <p>The Keycloak server was upgraded to use Wildfly 14 as the underlying container. This does not directly involve any specific Keycloak server functionality, however, note these changes related to migration:</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Dependency updates</dt> <dd> <p>The dependencies were updated to the versions used by the Wildfly 14 server. For example, Infinispan is now 9.3.1.Final.</p> </dd> <dt class="hdlist1">Configuration changes</dt> <dd> <p>A few configuration changes exist in the <code>standalone(-ha).xml</code> and <code>domain.xml</code> files. You should follow the <a href="#_install_new_version">Downloading the Keycloak server</a> section to handle the migration of configuration files automatically.</p> </dd> <dt class="hdlist1">Cross-Datacenter Replication changes</dt> <dd> <div class="ulist"> <ul> <li> <p>You will need to upgrade Infinispan server to version 9.4.19. The older version may still work, but it is not guaranteed as we don&#8217;t test it anymore.</p> </li> </ul> </div> </dd> </dl> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-4-4-0"><a class="anchor" href="#migrating-to-4-4-0"></a>Migrating to 4.4.0</h3> <div class="sect3"> <h4 id="upgrade-to-wildfly-13"><a class="anchor" href="#upgrade-to-wildfly-13"></a>Upgrade to Wildfly 13</h4> <div class="paragraph"> <p>The Keycloak server was upgraded to use Wildfly 13 as the underlying container. This does not directly involve any specific Keycloak server functionality, however, note these changes related to migration:</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Dependency updates</dt> <dd> <p>The dependencies were updated to the versions used by the Wildfly 13 server. For example, Infinispan is now 9.2.4.Final and Undertow is 2.0.9.Final</p> </dd> <dt class="hdlist1">Configuration changes</dt> <dd> <p>A few configuration changes exist in the <code>standalone(-ha).xml</code> and <code>domain.xml</code> files. You should follow the <a href="#_install_new_version">Downloading the Keycloak server</a> section to handle the migration of configuration files automatically. However, here are the most important changes, which you may need if you made your own configuration changes:</p> <div class="ulist"> <ul> <li> <p>Element <code>eviction</code> on infinispan caches is now <strong>deprecated</strong> (unused) and is <strong>replaced with</strong> element <code>object-memory</code></p> </li> <li> <p>The <code>cache-container</code> element in Infinispan subsystem <strong>does not recognize</strong> the <code>jndi-attribute</code> anymore.</p> </li> </ul> </div> </dd> <dt class="hdlist1">Cross-Datacenter Replication changes</dt> <dd> <div class="ulist"> <ul> <li> <p>You will need to upgrade Infinispan server to version 9.4.19. The older version may still work, but it is not guaranteed as we don&#8217;t test it anymore.</p> </li> <li> <p>You don&#8217;t need to configure security anymore in the Infinispan server configuration file.</p> </li> <li> <p>The <code>transaction</code> element needs to be removed from the configuration of replicated caches in the Infinispan server configuration file. This is needed because of the infinispan bug <a href="https://issues.redhat.com/browse/ISPN-9323" class="bare">https://issues.redhat.com/browse/ISPN-9323</a>.</p> </li> </ul> </div> </dd> </dl> </div> </div> </div> <div class="sect2"> <h3 id="migration-to-4-3-0"><a class="anchor" href="#migration-to-4-3-0"></a>Migration to 4.3.0</h3> <div class="sect3"> <h4 id="hostname-configuration"><a class="anchor" href="#hostname-configuration"></a>Hostname configuration</h4> <div class="paragraph"> <p>In previous versions it was recommended to use a filter to specify permitted hostnames. It is now possible to set a fixed hostname which makes it easier to make sure the valid hostname is used and also allows internal applications to invoke Keycloak through an alternative URL, for example an internal IP address. It is recommended that you switch to this approach in production.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-4-0-0"><a class="anchor" href="#migrating-to-4-0-0"></a>Migrating to 4.0.0</h3> <div class="sect3"> <h4 id="client-templates-changed-to-client-scopes"><a class="anchor" href="#client-templates-changed-to-client-scopes"></a>Client Templates changed to Client Scopes</h4> <div class="paragraph"> <p>We added support for Client Scopes, which requires some attention during migration.</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Client Templates changed to Client Scopes</dt> <dd> <p>Client Templates were changed to Client Scopes. If you had any Client Templates, their protocol mappers and role scope mappings will be preserved.</p> </dd> <dt class="hdlist1">Spaces replaced in the names</dt> <dd> <p>Client templates with the space character in the name were renamed by replacing spaces with an underscore, because spaces are not allowed in the name of client scopes. For example, a client template <code>my template</code> will be changed to client scope <code>my_template</code>.</p> </dd> <dt class="hdlist1">Linking Client Scopes to Clients</dt> <dd> <p>For clients which had the client template, the corresponding client scope is now added as <code>Default Client Scope</code> to the client. So protocol mappers and role scope mappings will be preserved on the client.</p> </dd> <dt class="hdlist1">Realm Default Client Scopes not linked with existing clients</dt> <dd> <p>During the migration, the list of built-in client scopes is added to each realm as well as list of <code>Realm Default Client Scopes</code>. However, existing clients are NOT upgraded and new client scopes are NOT automatically added to them. Also all the protocol mappers and role scope mappings are kept on existing clients. In the new version, when you create a new client, it automatically has Realm Default Client Scopes attached to it and it does not have any protocol mappers attached to it. We did not change existing clients during migration as it would be impossible to properly detect customizations, which you will have for protocol mappers of the clients, for example. If you want to update existing clients (remove protocol mappers from them and link them with client scopes), you will need to do it manually.</p> </dd> <dt class="hdlist1">Consents need to be confirmed again</dt> <dd> <p>The client scopes change required the refactoring of consents. Consents now point to client scopes, not to roles or protocol mappers. Because of this change, the previously confirmed persistent consents by users are not valid anymore and users need to confirm the consent page again after the migration.</p> </dd> <dt class="hdlist1">Some configuration switches removed</dt> <dd> <p>The switch <code>Scope Param Required</code> was removed from Role Detail. The switches <code>Consent Required</code> and <code>Consent Text</code> were removed from the Protocol Mapper details. Those switches are replaced with the Client Scope feature.</p> </dd> </dl> </div> </div> <div class="sect3"> <h4 id="changes-to-authorization-services"><a class="anchor" href="#changes-to-authorization-services"></a>Changes to Authorization Services</h4> <div class="paragraph"> <p>We added support for UMA 2.0. This version of the UMA specification introduced some important changes on how permissions are obtained from the server.</p> </div> <div class="paragraph"> <p>Here are the main changes introduced by UMA 2.0 support. See <a href="https://www.keycloak.org/docs/26.0.6/authorization_services/">Authorization Services Guide</a> for details.</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Authorization API was removed</dt> <dd> <p>Prior to UMA 2.0 (UMA 1.0), client applications were using the Authorization API to obtain permissions from the server in the format of an RPT. The new version of UMA specification has removed the Authorization API which was also removed from Keycloak. In UMA 2.0, RPTs can now be obtained from the token endpoint by using a specific grant type. See <a href="https://www.keycloak.org/docs/26.0.6/authorization_services/#_service_obtaining_permissions">Authorization Services Guide</a> for details.</p> </dd> <dt class="hdlist1">Entitlement API was removed</dt> <dd> <p>With the introduction of UMA 2.0, we decided to leverage the token endpoint and UMA grant type to allow obtaining RPTs from Keycloak and avoid having different APIs. The functionality provided by the Entitlement API was kept the same and is still possible to obtain permissions for a set of one or more resources and scopes or all permissions from the server in case no resource or scope is provided. See <a href="https://www.keycloak.org/docs/26.0.6/authorization_services/#_service_obtaining_permissions">Authorization Services Guide</a> for details.</p> </dd> <dt class="hdlist1">Changes to UMA Discovery Endpoint</dt> <dd> <p>UMA Discovery document changed, see <a href="https://www.keycloak.org/docs/26.0.6/authorization_services/#_service_authorization_api">Authorization Services Guide</a> for details.</p> </dd> <dt class="hdlist1">Changes to Keycloak Authorization JavaScript adapter</dt> <dd> <p>The Keycloak Authorization JavaScript adapter (keycloak-authz.js) changed in order to comply with the changes introduced by UMA 2.0 while keeping the same behavior as before. The main change is on how you invoke both <code>authorization</code> and <code>entitlement</code> methods which now expect a specific object type representing an authorization request. This new object type provides more flexibility on how permissions can be obtained from the server by supporting the different parameters supported by the UMA grant type.</p> <div class="literalblock"> <div class="content"> <pre>One of the main changes introduced by this release is that you are no longer required to exchange access tokens with RPTs in order to access resources protected by a resource server (when not using UMA). Depending on how the policy enforcer is configured on the resource server side, you can just send regular access tokens as a bearer token and permissions will still be enforced.</pre> </div> </div> </dd> <dt class="hdlist1">Changes to Keycloak Authorization Client Java API</dt> <dd> <p>When upgrading to the new version of Keycloak Authorization Client Java API, you&#8217;ll notice that some representation classes were moved to a different package in <code>org.keycloak:keycloak-core</code>.</p> </dd> </dl> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-3-4-2"><a class="anchor" href="#migrating-to-3-4-2"></a>Migrating to 3.4.2</h3> <div class="sect3"> <h4 id="added-session_state-parameter-to-openid-connect-authentication-response"><a class="anchor" href="#added-session_state-parameter-to-openid-connect-authentication-response"></a>Added session_state parameter to OpenID Connect Authentication Response</h4> <div class="paragraph"> <p>The OpenID Connect Session Management specification requires that the parameter <code>session_state</code> is present in the OpenID Connect Authentication Response.</p> </div> <div class="paragraph"> <p>In past releases, we did not have this parameter, but now Keycloak adds this parameter by default, as required by the specification.</p> </div> <div class="paragraph"> <p>However, some OpenID Connect / OAuth2 adapters, and especially older Keycloak adapters, may have issues with this new parameter.</p> </div> <div class="paragraph"> <p>For example, the parameter will be always present in the browser URL after successful authentication to the client application. In these cases, it may be useful to disable adding the <code>session_state</code> parameter to the authentication response. This can be done for the particular client in the Keycloak admin console, in client details in the section with <code>OpenID Connect Compatibility Modes</code>, described in <a href="#_compatibility_with_older_adapters">Compatibility with older adapters</a>. Dedicated <code>Exclude Session State From Authentication Response</code> switch exists, which can be turned on to prevent adding the <code>session_state</code> parameter to the Authentication Response.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> The parameter <code>session_state</code> was added in 3.4.2, however the switch <code>Exclude Session State From Authentication Response</code> was added in 4.0.0.Beta1. If your Keycloak server is on 3.4.2 or 3.4.3 and you have issues with <code>session_state</code> parameter, you will need to upgrade the server to 4.0.0.Beta1 or newer. </td> </tr> </table> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-3-2-0"><a class="anchor" href="#migrating-to-3-2-0"></a>Migrating to 3.2.0</h3> <div class="sect3"> <h4 id="new-password-hashing-algorithms"><a class="anchor" href="#new-password-hashing-algorithms"></a>New password hashing algorithms</h4> <div class="paragraph"> <p>We&#8217;ve added two new password hashing algorithms (pbkdf2-sha256 and pbkdf2-sha512). New realms will use the pbkdf2-sha256 hashing algorithm with 27500 hashing iterations. Since pbkdf2-sha256 is slightly faster than pbkdf2 the iterations was increased to 27500 from 20000.</p> </div> <div class="paragraph"> <p>Existing realms are upgraded if the password policy contains the default value for hashing algorithm (not specified) and iteration (20000). If you have changed the hashing iterations you need to manually change to pbkdf2-sha256 if you&#8217;d like to use the more secure hashing algorithm.</p> </div> </div> <div class="sect3"> <h4 id="id-token-requires-scopeopenid"><a class="anchor" href="#id-token-requires-scopeopenid"></a>ID Token requires scope=openid</h4> <div class="paragraph"> <p>OpenID Connect specification requires that parameter <code>scope</code> with value <code>openid</code> is used in initial authorization request. So in Keycloak 2.1.0 we changed our adapters to use <code>scope=openid</code> in the redirect URI to Keycloak. Now we changed the server part too and ID token will be sent to the application just if <code>scope=openid</code> is really used. If it&#8217;s not used, then ID token will be skipped and just Access token and Refresh token will be sent to the application. This also allows that you can omit the generation of ID Token on purpose - for example for space or performance purposes.</p> </div> <div class="paragraph"> <p>Direct grants (OAuth2 Resource Owner Password Credentials Grant) and Service accounts login (OAuth2 Client credentials grant) also don&#8217;t use ID Token by default now. You need to explicitly add <code>scope=openid</code> parameter to have ID Token included.</p> </div> </div> <div class="sect3"> <h4 id="authentication-sessions-and-action-tokens"><a class="anchor" href="#authentication-sessions-and-action-tokens"></a>Authentication sessions and Action tokens</h4> <div class="paragraph"> <p>We are working on support for multiple datacenters. As the initial step, we introduced authentication session and action tokens. Authentication session replaces Client session, which was used in previous versions. Action tokens are currently used especially for the scenarios, where the authenticator or requiredActionProvider requires sending email to the user and requires user to click on the link in email.</p> </div> <div class="paragraph"> <p>Here are concrete changes related to this, which may affect you for the migration.</p> </div> <div class="paragraph"> <p>First change related to this is introducing new Infinispan caches <code>authenticationSessions</code> and <code>actionTokens</code> in <code>standalone.xml</code> or <code>standalone-ha.xml</code>. If you use our migration CLI, you don&#8217;t need to care much as your <code>standalone(-ha).xml</code> files will be migrated automatically.</p> </div> <div class="paragraph"> <p>Second change is changing of some signatures in methods of authentication SPI. This may affect you if you use custom <code>Authenticator</code> or <code>RequiredActionProvider</code>. Classes <code>AuthenticationFlowContext</code> and <code>RequiredActionContext</code> now allow to retrieve authentication session instead of client session.</p> </div> <div class="paragraph"> <p>We also added some initial support for sticky sessions. You may want to change your load balancer/proxy server and configure it if you don&#8217;t want to suffer from it and want to have better performance. The route is added to the new <code>AUTH_SESSION_ID</code> cookie. More info in the clustering documentation.</p> </div> <div class="paragraph"> <p>Another change is, that <code>token.getClientSession()</code> was removed. This may affect you for example if you&#8217;re using Client Initiated Identity Broker Linking feature.</p> </div> <div class="paragraph"> <p>The <code>ScriptBasedAuthenticator</code> changed the binding name from <code>clientSession</code> to <code>authenticationSession</code>, so you would need to update your scripts if you&#8217;re using this authenticator.</p> </div> <div class="paragraph"> <p>Finally we added some new timeouts to the admin console. This allows you for example to specify different timeouts for the email actions triggered by admin and by user himself.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-2-5-1"><a class="anchor" href="#migrating-to-2-5-1"></a>Migrating to 2.5.1</h3> <div class="sect3"> <h4 id="migration-of-old-offline-tokens"><a class="anchor" href="#migration-of-old-offline-tokens"></a>Migration of old offline tokens</h4> <div class="paragraph"> <p>If you migrate from version 2.2.0 or older and you used offline tokens, then your offline tokens didn&#8217;t have KID in the token header. We added KID to the token header in 2.3.0 together with the ability to have multiple realm keys, so Keycloak is able to find the correct key based on the token KID.</p> </div> <div class="paragraph"> <p>For the offline tokens without KID, Keycloak 2.5.1 will always use the active realm key to find the proper key for the token verification. In other words, migration of old offline tokens will work. So for example, your user requested offline token in 1.9.8, then you migrate from 1.9.8 to 2.5.1 and then your user will be still able to refresh his old offline token in 2.5.1 version.</p> </div> <div class="paragraph"> <p>But a limitation exists. Once you change the realm active key, the users won&#8217;t be able to refresh old offline tokens anymore. So you shouldn&#8217;t change the active realm key until all your users with offline tokens refreshed their tokens. Obviously newly refreshed tokens will have KID in the header, so after all users exchange their old offline tokens, you are free to change the active realm key.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-2-5-0"><a class="anchor" href="#migrating-to-2-5-0"></a>Migrating to 2.5.0</h3> <div class="sect3"> <h4 id="changes-to-the-infinispan-caches"><a class="anchor" href="#changes-to-the-infinispan-caches"></a>Changes to the Infinispan caches</h4> <div class="paragraph"> <p>The <code>realms</code> cache defined in the infinispan subsystem in <code>standalone.xml</code> or <code>standalone-ha.xml</code> configuration file, now has the eviction with the 10000 records by default. This is the same default as the <code>users</code> cache.</p> </div> <div class="paragraph"> <p>Also the <code>authorization</code> cache now doesn&#8217;t have any eviction on it by default.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-2-4-0"><a class="anchor" href="#migrating-to-2-4-0"></a>Migrating to 2.4.0</h3> <div class="sect3"> <h4 id="server-spi-split-into-server-spi-and-sever-spi-private"><a class="anchor" href="#server-spi-split-into-server-spi-and-sever-spi-private"></a>Server SPI split into Server SPI and Sever SPI Private</h4> <div class="paragraph"> <p>The keycloak-server-spi module has been split into keycloak-server-spi and keycloak-server-spi-private. APIs within keycloak-server-spi will not change between minor releases, while we reserve the right and may quite likely change APIs in keycloak-server-spi-private between minor releases.</p> </div> </div> <div class="sect3"> <h4 id="key-encryption-algorithm-in-saml-assertions"><a class="anchor" href="#key-encryption-algorithm-in-saml-assertions"></a>Key encryption algorithm in SAML assertions</h4> <div class="paragraph"> <p>Key in SAML assertions and documents are now encrypted using RSA-OAEP encryption scheme. If you want to use encrypted assertions, make sure that service providers understand this encryption scheme. In the unlikely case that SP would not be able to handle the new scheme, Keycloak can be made to use legacy RSA-v1.5 encryption scheme when started with system property <code>keycloak.saml.key_trans.rsa_v1.5</code> set to <code>true</code>.</p> </div> </div> <div class="sect3"> <h4 id="infinispan-caches-realms-and-users-are-always-local"><a class="anchor" href="#infinispan-caches-realms-and-users-are-always-local"></a>Infinispan caches realms and users are always local</h4> <div class="paragraph"> <p>Even if you use Keycloak in cluster, the caches <code>realms</code> and <code>users</code> defined in infinispan subsystem in <code>standalone-ha.xml</code> are always local caches now. A separate cache <code>work</code> exists, which handles sending invalidation messages between cluster nodes and informing whole cluster what records in underlying <code>realms</code> and <code>users</code> caches should be invalidated.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-2-3-0"><a class="anchor" href="#migrating-to-2-3-0"></a>Migrating to 2.3.0</h3> <div class="sect3"> <h4 id="default-max-results-on-paginated-endpoints"><a class="anchor" href="#default-max-results-on-paginated-endpoints"></a>Default max results on paginated endpoints</h4> <div class="paragraph"> <p>All Admin REST API endpoints that support pagination now have a default max results set to 100. If you want to return more than 100 entries you need to explicitly specify that with <code>?max=&lt;RESULTS&gt;</code>.</p> </div> </div> <div class="sect3"> <h4 id="realm-public-key-adapter-property-not-recommended"><a class="anchor" href="#realm-public-key-adapter-property-not-recommended"></a><code>realm-public-key</code> adapter property not recommended</h4> <div class="paragraph"> <p>In 2.3.0 release we added support for Public Key Rotation. When admin rotates the realm keys in Keycloak admin console, the Client Adapter will be able to recognize it and automatically download new public key from Keycloak. However this automatic download of new keys is done just if you don&#8217;t have <code>realm-public-key</code> option in your adapter with the hardcoded public key. For this reason, we don&#8217;t recommend to use <code>realm-public-key</code> option in adapter configuration anymore.</p> </div> <div class="paragraph"> <p>Note this option is still supported, but it may be useful just if you really want to have hardcoded public key in your adapter configuration and never download the public key from Keycloak. In theory, one reason for this can be to avoid man-in-the-middle attack if you have untrusted network between adapter and Keycloak, however in that case, it is much better option to use HTTPS, which will secure all the requests between adapter and Keycloak.</p> </div> </div> <div class="sect3"> <h4 id="added-infinispan-cache-keys"><a class="anchor" href="#added-infinispan-cache-keys"></a>Added Infinispan cache <code>keys</code></h4> <div class="paragraph"> <p>In this release, we added new cache <code>keys</code> to the infinispan subsystem, which is defined in <code>standalone.xml</code> or <code>standalone-ha.xml</code> configuration file. It has also some eviction and expiration defined. This cache is internally used for caching the external public keys of the entities trusted by the server (Identity providers or clients, which uses authentication with signed JWT).</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-2-2-0"><a class="anchor" href="#migrating-to-2-2-0"></a>Migrating to 2.2.0</h3> <div class="sect3"> <h4 id="databaseschema-property-deprecated"><a class="anchor" href="#databaseschema-property-deprecated"></a><code>databaseSchema</code> property <strong>deprecated</strong></h4> <div class="paragraph"> <p>The <code>databaseSchema</code> property for both JPA and Mongo is now <strong>deprecated</strong> and is <strong>replaced with</strong> <code>initializeEmpty</code> and <code>migrationStrategy</code>. <code>initializeEmpty</code> can bet set to <code>true</code> or <code>false</code> and controls if an empty database should be initialized. <code>migrationStrategy</code> can be set to <code>update</code>, <code>validate</code> and <code>manual</code>. <code>manual</code> is only supported for relational databases and will write an SQL file with the required changes to the database schema. Please note that for Oracle database, the created SQL file contains <code>SET DEFINE OFF</code> command understood by Oracle SQL clients. Should the script be consumed by any other client, please replace the lines with equivalent command of the tool of your choice that disables variable expansion or remove it completely if such functionality is not applicable.</p> </div> </div> <div class="sect3"> <h4 id="changes-in-clients-valid-redirect-uris"><a class="anchor" href="#changes-in-clients-valid-redirect-uris"></a>Changes in Client&#8217;s Valid Redirect URIs</h4> <div class="paragraph"> <p>The following scenarios are affected:</p> </div> <div class="ulist"> <ul> <li> <p>When a Valid Redirect URI with query component is saved in a Client (e.g. <code>http://localhost/auth?foo=bar</code>), <code>redirect_uri</code> in authorization request must exactly match this URI (or other registered URI in this Client).</p> </li> <li> <p>When a Valid Redirect URI without a query component is saved in a Client, <code>redirect_uri</code> must exactly match as well.</p> </li> <li> <p>Wildcards in registered Valid Redirect URIs are no longer supported when query component is present in this URI, so the <code>redirect_uri</code> needs to exactly match this saved URI as well.</p> </li> <li> <p>Fragments in registered Valid Redirect URIs (like <code>http://localhost/auth#fragment</code>) are no longer allowed.</p> </li> </ul> </div> </div> <div class="sect3"> <h4 id="authenticate-by-default-removed-from-identity-providers"><a class="anchor" href="#authenticate-by-default-removed-from-identity-providers"></a>Authenticate by default removed from Identity Providers</h4> <div class="paragraph"> <p>Identity providers no longer has an option to set it as a default authentication provider. Instead go to Authentication, select the <code>Browser</code> flow and configure the <code>Identity Provider Redirector</code>. It has an option to set the default identity provider.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-2-0-0"><a class="anchor" href="#migrating-to-2-0-0"></a>Migrating to 2.0.0</h3> <div class="sect3"> <h4 id="upgrading-from-1-0-0-final-no-longer-supported"><a class="anchor" href="#upgrading-from-1-0-0-final-no-longer-supported"></a>Upgrading from 1.0.0.Final no longer supported</h4> <div class="paragraph"> <p>Upgrading from 1.0.0.Final is no longer supported. To upgrade to this version upgrade to 1.9.8.Final prior to upgrading to 2.0.0.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-1-9-5"><a class="anchor" href="#migrating-to-1-9-5"></a>Migrating to 1.9.5</h3> <div class="sect3"> <h4 id="default-password-hashing-interval-increased-to-20k"><a class="anchor" href="#default-password-hashing-interval-increased-to-20k"></a>Default password hashing interval increased to 20K</h4> <div class="paragraph"> <p>The default password hashing interval for new realms has been increased to 20K (from 1 previously). This change will have an impact on performance when users authenticate. For example with the old default (1) it takes less than 1 ms to hash a password, but with the new default (20K) the same operation can take 50-100 ms.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-1-9-3"><a class="anchor" href="#migrating-to-1-9-3"></a>Migrating to 1.9.3</h3> <div class="sect3"> <h4 id="add-user-script-renamed"><a class="anchor" href="#add-user-script-renamed"></a>Add User script renamed</h4> <div class="paragraph"> <p>The script to add admin users to Keycloak has been renamed to <code>add-user-keycloak</code>.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-1-9-2"><a class="anchor" href="#migrating-to-1-9-2"></a>Migrating to 1.9.2</h3> <div class="sect3"> <h4 id="adapter-option-auth-server-url-for-backend-requests-removed"><a class="anchor" href="#adapter-option-auth-server-url-for-backend-requests-removed"></a>Adapter option auth-server-url-for-backend-requests removed</h4> <div class="paragraph"> <p>We&#8217;ve removed the option auth-server-url-for-backend-requests due to issues in some scenarios when it was used. In more details, it was possible to access the Keycloak server from 2 different contexts (internal and external), which was causing issues in token validations etc.</p> </div> <div class="paragraph"> <p>If you still want to use the optimization of network, which this option provided (avoid the application to send backchannel requests through load balancer but send them to local Keycloak server directly) you may need to handle it at hosts configuration (DNS) level.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-1-9-0"><a class="anchor" href="#migrating-to-1-9-0"></a>Migrating to 1.9.0</h3> <div class="sect3"> <h4 id="themes-and-providers-directory-moved"><a class="anchor" href="#themes-and-providers-directory-moved"></a>Themes and providers directory moved</h4> <div class="paragraph"> <p>We&#8217;ve moved the themes and providers directories from <code>standalone/configuration/themes</code> and <code>standalone/configuration/providers</code> to <code>themes</code> and <code>providers</code> respectively. If you have added custom themes and providers you need to move them to the new location. You also need to update <code>keycloak-server.json</code> as it&#8217;s changed due to this.</p> </div> </div> <div class="sect3"> <h4 id="adapter-subsystems-only-bring-in-dependencies-if-keycloak-is-on"><a class="anchor" href="#adapter-subsystems-only-bring-in-dependencies-if-keycloak-is-on"></a>Adapter subsystems only bring in dependencies if Keycloak is on</h4> <div class="paragraph"> <p>Previously, if you had installed our SAML or OIDC Keycloak subsystem adapters into WildFly or JBoss EAP, we would automatically include Keycloak client jars into EVERY application regardless if you were using Keycloak or not. These libraries are now only added to your deployment if you have Keycloak authentication turned on for that adapter (via the subsystem, or auth-method in web.xml)</p> </div> </div> <div class="sect3"> <h4 id="client-registration-service-endpoints-moved"><a class="anchor" href="#client-registration-service-endpoints-moved"></a>Client Registration service endpoints moved</h4> <div class="paragraph"> <p>The Client Registration service endpoints have been moved from <code>{realm-name}/clients</code> to <code>{realm-name}/clients-registrations</code>.</p> </div> </div> <div class="sect3"> <h4 id="session-state-parameter-in-authentication-response-renamed"><a class="anchor" href="#session-state-parameter-in-authentication-response-renamed"></a>Session state parameter in authentication response renamed</h4> <div class="paragraph"> <p>In the OpenID Connect authentication response we used to return the session state as <code>session-state</code> this is not correct according to the specification and has been renamed to <code>session_state</code>.</p> </div> </div> <div class="sect3"> <h4 id="deprecated-openid-connect-endpoints"><a class="anchor" href="#deprecated-openid-connect-endpoints"></a>Deprecated OpenID Connect endpoints</h4> <div class="paragraph"> <p>In 1.2 we deprecated a number of endpoints that where not consistent with the OpenID Connect specifications, these have now been removed. This also applies to the validate token endpoint that is replaced with the new introspect endpoint in 1.8.</p> </div> </div> <div class="sect3"> <h4 id="updates-to-theme-templates"><a class="anchor" href="#updates-to-theme-templates"></a>Updates to theme templates</h4> <div class="paragraph"> <p>Feedback in template.ftl has been moved and format has changed slightly.</p> </div> </div> <div class="sect3"> <h4 id="module-and-source-code-reorganization"><a class="anchor" href="#module-and-source-code-reorganization"></a>Module and source code reorganization</h4> <div class="paragraph"> <p>Most of our modules and source code have been consolidated into two maven modules: keycloak-server-spi and keycloak-services. SPI interfaces are in server-spi, implementations are in keycloak-services. All JPA dependent modules have been consolidated under keycloak-model-jpa. Same goes with mongo and Infinispan under modules keycloak-model-mongo and keycloak-model-infinispan.</p> </div> </div> <div class="sect3"> <h4 id="for-adapters-session-id-changed-after-login"><a class="anchor" href="#for-adapters-session-id-changed-after-login"></a>For adapters, session id changed after login</h4> <div class="paragraph"> <p>To plug a security attack vector, for platforms that support it (Tomcat 8, Undertow/WildFly), the Keycloak OIDC and SAML adapters will change the session id after login. You can turn off this behavior check adapter config switches.</p> </div> </div> <div class="sect3"> <h4 id="saml-sp-client-adapter-changes"><a class="anchor" href="#saml-sp-client-adapter-changes"></a>SAML SP Client adapter changes</h4> <div class="paragraph"> <p>Keycloak SAML SP Client adapter now requires a specific endpoint, <code>/saml</code> to be registered with your IDP.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-1-8-0"><a class="anchor" href="#migrating-to-1-8-0"></a>Migrating to 1.8.0</h3> <div class="sect3"> <h4 id="admin-account"><a class="anchor" href="#admin-account"></a>Admin account</h4> <div class="paragraph"> <p>In previous releases we shipped with a default admin user with a default password, this has now been removed. If you are doing a new installation of 1.8 you will have to create an admin user as a first step.</p> </div> </div> <div class="sect3"> <h4 id="oauth2-token-introspection"><a class="anchor" href="#oauth2-token-introspection"></a>OAuth2 token introspection</h4> <div class="paragraph"> <p>In order to add more compliance with OAuth2 specification, we added a new endpoint for token introspection. The new endpoint can reached at <code>/realms/{realm-name}/protocols/openid-connect/token/introspect</code> and it is solely based on <code>RFC-7662</code>.</p> </div> <div class="paragraph"> <p>The <code>/realms/{realm-name}/protocols/openid-connect/validate</code> endpoint is now deprecated and we strongly recommend you to move to the new introspection endpoint as soon as possible. The reason for this change is that RFC-7662 provides a more standard and secure introspection endpoint.</p> </div> <div class="paragraph"> <p>The new token introspection URL can now be obtained from OpenID Connect Provider&#8217;s configuration at <code>/realms/{realm-name}/.well-known/openid-configuration</code>. There you will find a claim with name <code>token_introspection_endpoint</code> within the response. Only <code>confidential clients</code> are allowed to invoke the new endpoint, where these clients will be usually acting as a resource server and looking for token metadata in order to perform local authorization checks.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-1-7-0-cr1"><a class="anchor" href="#migrating-to-1-7-0-cr1"></a>Migrating to 1.7.0.CR1</h3> <div class="sect3"> <h4 id="direct-access-grants-disabled-by-default-for-clients"><a class="anchor" href="#direct-access-grants-disabled-by-default-for-clients"></a>Direct access grants disabled by default for clients</h4> <div class="paragraph"> <p>In order to add more compliance with OpenID Connect specification, we added flags into admin console to Client Settings page, where you can enable/disable various kinds of OpenID Connect/OAuth2 flows (Standard flow, Implicit flow, Direct Access Grants, Service Accounts). As part of this, we have <code>Direct Access Grants</code> (corresponds to OAuth2 <code>Resource Owner Password Credentials Grant</code>) disabled by default for new clients.</p> </div> <div class="paragraph"> <p>Clients migrated from previous version have <code>Direct Access Grants</code> enabled just if they had flag <code>Direct Grants Only</code> on. The <code>Direct Grants Only</code> flag was removed as if you enable Direct Access Grants and disable both Standard+Implicit flow, you will achieve same effect.</p> </div> <div class="paragraph"> <p>We also added built-in client <code>admin-cli</code> to each realm. This client has <code>Direct Access Grants</code> enabled. So if you&#8217;re using Admin REST API or Keycloak admin-client, you should update your configuration to use <code>admin-cli</code> instead of <code>security-admin-console</code> as the latter one doesn&#8217;t have direct access grants enabled anymore by default.</p> </div> </div> <div class="sect3"> <h4 id="option-update-profile-on-first-login-moved-from-identity-provider-to-review-profile-authenticator"><a class="anchor" href="#option-update-profile-on-first-login-moved-from-identity-provider-to-review-profile-authenticator"></a>Option 'Update Profile On First Login' moved from Identity provider to Review Profile authenticator</h4> <div class="paragraph"> <p>In this version, we added <code>First Broker Login</code>, which allows you to specify what exactly should be done when new user is logged through Identity provider (or Social provider), but no Keycloak user linked to the social account exists yet. As part of this work, we added option <code>First Login Flow</code> to identity providers where you can specify the flow and then you can configure this flow under <code>Authentication</code> tab in admin console.</p> </div> <div class="paragraph"> <p>We also removed the option <code>Update Profile On First Login</code> from the Identity provider settings and moved it to the configuration of <code>Review Profile</code> authenticator. So once you specify which flow should be used for your Identity provider (by default it&#8217;s <code>First Broker Login</code> flow), you go to <code>Authentication</code> tab, select the flow and then you configure the option under <code>Review Profile</code> authenticator.</p> </div> </div> <div class="sect3"> <h4 id="element-form-error-page-in-web-xml-not-supported-anymore"><a class="anchor" href="#element-form-error-page-in-web-xml-not-supported-anymore"></a>Element 'form-error-page' in web.xml not supported anymore</h4> <div class="paragraph"> <p>form-error-page in web.xml will no longer work for client adapter authentication errors. You must define an error-page for the various HTTP error codes. See documentation for more details if you want to catch and handle adapter error conditions.</p> </div> </div> <div class="sect3"> <h4 id="identityprovidermapper-changes"><a class="anchor" href="#identityprovidermapper-changes"></a>IdentityProviderMapper changes</h4> <div class="paragraph"> <p>The interface itself and method signatures did not change. However some changes in the behavior exist. We added <code>First Broker Login</code> flow in this release and the method <code>IdentityProviderMapper.importNewUser</code> is now called after <code>First Broker Login</code> flow is finished. So if you want to have any attribute available in <code>Review Profile</code> page, you would need to use the method <code>preprocessFederatedIdentity</code> instead of <code>importNewUser</code> . You can set any attribute by invoke <code>BrokeredIdentityContext.setUserAttribute</code> and that will be available on <code>Review profile</code> page.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-1-6-0-final"><a class="anchor" href="#migrating-to-1-6-0-final"></a>Migrating to 1.6.0.Final</h3> <div class="sect3"> <h4 id="option-that-refresh-tokens-are-not-reusable-anymore"><a class="anchor" href="#option-that-refresh-tokens-are-not-reusable-anymore"></a>Option that refresh tokens are not reusable anymore</h4> <div class="paragraph"> <p>Old versions of Keycloak allowed reusing refresh tokens multiple times. Keycloak still permits this, but also have an option <code>Revoke refresh token</code> to disallow it. Option is under token settings in admin console. When a refresh token is used to obtain a new access token a new refresh token is also included. When option is enabled, then this new refresh token should be used next time the access token is refreshed. It won&#8217;t be possible to reuse old refresh token multiple times.</p> </div> </div> <div class="sect3"> <h4 id="some-packages-renamed"><a class="anchor" href="#some-packages-renamed"></a>Some packages renamed</h4> <div class="paragraph"> <p>We did a bit of restructure and renamed some packages. It is mainly about renaming internal packages of util classes. The most important classes used in your application ( for example AccessToken or KeycloakSecurityContext ) as well as the SPI are still unchanged. However, a slight chance exists that you will be affected and will need to update imports of your classes. For example if you are using multitenancy and KeycloakConfigResolver, you will be affected as for example class HttpFacade was moved to different package - it is <code>org.keycloak.adapters.spi.HttpFacade</code> now.</p> </div> </div> <div class="sect3"> <h4 id="persisting-user-sessions"><a class="anchor" href="#persisting-user-sessions"></a>Persisting user sessions</h4> <div class="paragraph"> <p>We added support for offline tokens in this release, which means that we are persisting "offline" user sessions into database now. If you are not using offline tokens, nothing will be persisted for you, so you don&#8217;t need to care about worse performance for more DB writes. However in all cases, you will need to update <code>standalone/configuration/keycloak-server.json</code> and add <code>userSessionPersister</code> like this:</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">userSessionPersister</span><span class="delimiter">&quot;</span></span>: { <span class="key"><span class="delimiter">&quot;</span><span class="content">provider</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">jpa</span><span class="delimiter">&quot;</span></span> },</code></pre> </div> </div> <div class="paragraph"> <p>If you want sessions to be persisted in Mongo instead of classic RDBMS, use provider <code>mongo</code> instead.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-1-5-0-final"><a class="anchor" href="#migrating-to-1-5-0-final"></a>Migrating to 1.5.0.Final</h3> <div class="sect3"> <h4 id="realm-and-user-cache-providers"><a class="anchor" href="#realm-and-user-cache-providers"></a>Realm and User cache providers</h4> <div class="paragraph"> <p>Infinispan is now the default and only realm and user cache providers. In non-clustered mode a local Infinispan cache is used. We&#8217;ve also removed our custom in-memory cache and the no cache providers. If you have realmCache or userCache set in keycloak-server.json to mem or none please remove these. As Infinispan is the only provider the realmCache and userCache objects are no longer needed and can be removed.</p> </div> </div> <div class="sect3"> <h4 id="uses-session-providers"><a class="anchor" href="#uses-session-providers"></a>Uses Session providers</h4> <div class="paragraph"> <p>Infinispan is now the default and only user session provider. In non-clustered mode a local Infinispan cache is used. We&#8217;ve also removed the JPA and Mongo user session providers. If you have userSession set in keycloak-server.json to mem, jpa or mongo please remove it. As Infinispan is the only provider the userSession object is no longer needed and can be removed.</p> </div> <div class="paragraph"> <p>For anyone that wants to achieve increased durability of user sessions this can be achieved by configuring the user session cache with more than one owner or use a replicated cache. It&#8217;s also possible to configure Infinispan to persist caches, although that would have impacts on performance.</p> </div> </div> <div class="sect3"> <h4 id="contact-details-removed-from-registration-and-account-management"><a class="anchor" href="#contact-details-removed-from-registration-and-account-management"></a>Contact details removed from registration and account management</h4> <div class="paragraph"> <p>In the default theme we have now removed the contact details from the registration page and account management. The admin console now lists all the users attributes, not just contact specific attributes. The admin console also has the ability to add/remove attributes to a user. If you want to add contact details, please refer to the address theme included in the examples.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-to-1-3-0-final"><a class="anchor" href="#migrating-to-1-3-0-final"></a>Migrating to 1.3.0.Final</h3> <div class="sect3"> <h4 id="direct-grant-api-always-enabled"><a class="anchor" href="#direct-grant-api-always-enabled"></a>Direct Grant API always enabled</h4> <div class="paragraph"> <p>In the past Direct Grant API (or Resource Owner Password Credentials) was disabled by default and an option to enable it on a realm existed. The Direct Grant API is now always enabled and the option to enable/disable for a realm is removed.</p> </div> </div> <div class="sect3"> <h4 id="database-changed"><a class="anchor" href="#database-changed"></a>Database changed</h4> <div class="paragraph"> <p>There are again few database changes. Remember to back up your database prior to upgrading.</p> </div> </div> <div class="sect3"> <h4 id="userfederationprovider-changed"><a class="anchor" href="#userfederationprovider-changed"></a>UserFederationProvider changed</h4> <div class="paragraph"> <p>There are few minor changes in UserFederationProvider interface. You may need to sync your implementation when upgrade to newer version and upgrade few methods, which has changed signature. Changes are really minor, but were needed to improve performance of federation.</p> </div> </div> <div class="sect3"> <h4 id="wildfly-9-0-0-final"><a class="anchor" href="#wildfly-9-0-0-final"></a>WildFly 9.0.0.Final</h4> <div class="paragraph"> <p>Following on from the distribution changes that was done in the last release the standalone download of Keycloak is now based on WildFly 9.0.0.Final. This also affects the overlay which can only be deployed to WildFly 9.0.0.Final or JBoss EAP 6.4.0.GA. WildFly 8.2.0.Final is no longer supported for the server.</p> </div> </div> <div class="sect3"> <h4 id="wildfly-jboss-eap-and-jboss-as7-adapters"><a class="anchor" href="#wildfly-jboss-eap-and-jboss-as7-adapters"></a>WildFly, JBoss EAP and JBoss AS7 adapters</h4> <div class="paragraph"> <p>There are now 3 separate adapter downloads for WildFly, JBoss EAP and JBoss AS7:</p> </div> <div class="ulist"> <ul> <li> <p>eap6</p> </li> <li> <p>wf9</p> </li> <li> <p>wf8</p> </li> <li> <p>as7</p> </li> </ul> </div> <div class="paragraph"> <p>Make sure you grab the correct one.</p> </div> <div class="paragraph"> <p>You also need to update standalone.xml as the extension module and subsystem definition has changed. See <a href="https://www.keycloak.org/guides#securing-apps">Securing applications Guides</a> for details.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-from-1-2-0-beta1-to-1-2-0-rc1"><a class="anchor" href="#migrating-from-1-2-0-beta1-to-1-2-0-rc1"></a>Migrating from 1.2.0.Beta1 to 1.2.0.RC1</h3> <div class="sect3"> <h4 id="distribution-changes"><a class="anchor" href="#distribution-changes"></a>Distribution changes</h4> <div class="paragraph"> <p>Keycloak is now available in 3 downloads: standalone, overlay and demo bundle. The standalone is intended for production and non-JEE developers. Overlay is aimed at adding Keycloak to an existing WildFly 8.2 or EAP 6.4 installation and is mainly for development. Finally we have a demo (or dev) bundle that is aimed at developers getting started with Keycloak. This bundle contains a WildFly server, with Keycloak server and adapter included. It also contains all documentation and examples.</p> </div> </div> <div class="sect3"> <h4 id="database-changed-2"><a class="anchor" href="#database-changed-2"></a>Database changed</h4> <div class="paragraph"> <p>This release contains again a number of changes to the database. The biggest one is Application and OAuth client merge. Remember to back up your database prior to upgrading.</p> </div> </div> <div class="sect3"> <h4 id="application-and-oauth-client-merge"><a class="anchor" href="#application-and-oauth-client-merge"></a>Application and OAuth client merge</h4> <div class="paragraph"> <p>Application and OAuth clients are now merged into <code>Clients</code>. The UI of admin console is updated and database as well. Your data from database should be automatically updated. The previously set Applications will be converted into Clients with <code>Consent required</code> switch off and OAuth Clients will be converted into Clients with this switch on.</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-from-1-1-0-final-to-1-2-0-beta1"><a class="anchor" href="#migrating-from-1-1-0-final-to-1-2-0-beta1"></a>Migrating from 1.1.0.Final to 1.2.0.Beta1</h3> <div class="sect3"> <h4 id="database-changed-3"><a class="anchor" href="#database-changed-3"></a>Database changed</h4> <div class="paragraph"> <p>This release contains a number of changes to the database. Remember to back up your database prior to upgrading.</p> </div> </div> <div class="sect3"> <h4 id="iss-in-access-and-id-tokens"><a class="anchor" href="#iss-in-access-and-id-tokens"></a><code>iss</code> in access and id tokens</h4> <div class="paragraph"> <p>The value of <code>iss</code> claim in access and id tokens have changed from <code>realm name</code> to <code>realm url</code>. This is required by OpenID Connect specification. If you&#8217;re using our adapters no change is required, except if you&#8217;ve been using bearer-only without specifying the <code>auth-server-url</code>, you have to add it now. If you&#8217;re using another library (or RSATokenVerifier) you need to make the corresponding changes when verifying <code>iss</code>.</p> </div> </div> <div class="sect3"> <h4 id="openid-connect-endpoints"><a class="anchor" href="#openid-connect-endpoints"></a>OpenID Connect endpoints</h4> <div class="paragraph"> <p>To comply with OpenID Connect specification the authentication and token endpoints have been changed to having a single authentication endpoint and a single token endpoint. As per-spec <code>response_type</code> and <code>grant_type</code> parameters are used to select the required flow. The old endpoints (<code>/realms/{realm-name}/protocols/openid-connect/login</code>, <code>/realms/{realm-name}/protocols/openid-connect/grants/access</code>, <code>/realms/{realm-name}/protocols/openid-connect/refresh</code>, <code>/realms/{realm-name}/protocols/openid-connect/access/codes</code>) are now deprecated and will be removed in a future version.</p> </div> </div> <div class="sect3"> <h4 id="theme-changes"><a class="anchor" href="#theme-changes"></a>Theme changes</h4> <div class="paragraph"> <p>The layout of themes has changed. The directory hierarchy used to be <code>type/name</code> this is now changed to <code>name/type</code>. For example a login theme named <code>sunrise</code> used to be deployed to <code>standalone/configuration/themes/login/sunrise</code>, which is now moved to <code>standalone/configuration/themes/sunrise/login</code>. This change was done to make it easier to have groups of the different types for the same theme into one folder.</p> </div> <div class="paragraph"> <p>If you deployed themes as a JAR in the past you had to create a custom theme loader which required Java code. This has been simplified to only requiring a plain text file (<code>META-INF/keycloak-themes.json</code>) to describe the themes included in a JAR.</p> </div> </div> <div class="sect3"> <h4 id="claims-changes"><a class="anchor" href="#claims-changes"></a>Claims changes</h4> <div class="paragraph"> <p>Previously a dedicated <code>Claims</code> tab existed in the admin console for application and OAuth clients. This was used to configure which attributes should go into access token for particular application/client. This was removed and is replaced with protocol mappers which are more flexible.</p> </div> <div class="paragraph"> <p>You don&#8217;t need to care about migration of database from previous version. We did migration scripts for both RDBMS and Mongo, which should ensure that claims configured for particular application/client will be converted into corresponding protocol mappers (Still it&#8217;s safer to back up DB before migrating to newer version though). Same applies for exported JSON representation from previous version.</p> </div> </div> <div class="sect3"> <h4 id="social-migration-to-identity-brokering"><a class="anchor" href="#social-migration-to-identity-brokering"></a>Social migration to identity brokering</h4> <div class="paragraph"> <p>We refactored social providers SPI and replaced it with Identity Brokering SPI, which is more flexible. The <code>Social</code> tab in admin console is renamed to <code>Identity Provider</code> tab.</p> </div> <div class="paragraph"> <p>Again you don&#8217;t need to care about migration of database from previous version similarly like for Claims/protocol mappers. Both configuration of social providers and "social links" to your users will be converted to corresponding Identity providers.</p> </div> <div class="paragraph"> <p>Only required action from you would be to change allowed <code>Redirect URI</code> in the admin console of particular 3rd party social providers. You can first go to the Keycloak admin console and copy Redirect URI from the page where you configure the identity provider. Then you can simply paste this as allowed Redirect URI to the admin console of 3rd party provider (IE. Facebook admin console).</p> </div> </div> </div> <div class="sect2"> <h3 id="migrating-from-1-1-0-beta1-to-1-1-0-beta2"><a class="anchor" href="#migrating-from-1-1-0-beta1-to-1-1-0-beta2"></a>Migrating from 1.1.0.Beta1 to 1.1.0.Beta2</h3> <div class="ulist"> <ul> <li> <p>adapters are now a separate download. They are not included in appliance and war distribution. We have too many now and the distro is getting bloated.</p> </li> <li> <p><code>org.keycloak.adapters.tomcat7.KeycloakAuthenticatorValve</code> +<code>org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve</code></p> </li> <li> <p>JavaScript adapter now has idToken and idTokenParsed properties. If you use idToken to retrieve first name, email, etc. you need to change this to idTokenParsed.</p> </li> <li> <p>The as7-eap-subsystem and keycloak-wildfly-subsystem have been merged into one keycloak-subsystem. If you have an existing standalone.xml or domain.xml, you will need edit near the top of the file and change the extension module name to org.keycloak.keycloak-subsystem. For AS7 only, the extension module name is org.keycloak.keycloak-as7-subsystem.</p> </li> <li> <p>Server installation is no longer supported on AS7. You can still use AS7 as an application client.</p> </li> </ul> </div> </div> <div class="sect2"> <h3 id="migrating-from-1-0-x-final-to-1-1-0-beta1"><a class="anchor" href="#migrating-from-1-0-x-final-to-1-1-0-beta1"></a>Migrating from 1.0.x.Final to 1.1.0.Beta1</h3> <div class="ulist"> <ul> <li> <p>RealmModel JPA and Mongo storage schema has changed</p> </li> <li> <p>UserSessionModel JPA and Mongo storage schema has changed as these interfaces have been refactored</p> </li> <li> <p>Upgrade your adapters, old adapters are not compatible with Keycloak 1.1. We interpreted JSON Web Token and OIDC ID Token specification incorrectly. 'aud' claim must be the client id, we were storing the realm name in there and validating it.</p> </li> </ul> </div> </div> <div class="sect2"> <h3 id="migrating-from-1-0-rc-1-to-rc-2"><a class="anchor" href="#migrating-from-1-0-rc-1-to-rc-2"></a>Migrating from 1.0 RC-1 to RC-2</h3> <div class="ulist"> <ul> <li> <p>A lot of info level logging has been changed to debug. Also, a realm no longer has the jboss-logging audit listener by default. If you want log output when users login, logout, change passwords, etc. enable the jboss-logging audit listener through the admin console.</p> </li> </ul> </div> </div> <div class="sect2"> <h3 id="migrating-from-1-0-beta-4-to-rc-1"><a class="anchor" href="#migrating-from-1-0-beta-4-to-rc-1"></a>Migrating from 1.0 Beta 4 to RC-1</h3> <div class="ulist"> <ul> <li> <p>logout REST API has been refactored. The GET request on the logout URI does not take a session_state parameter anymore. You must be logged in in order to log out the session. You can also POST to the logout REST URI. This action requires a valid refresh token to perform the logout. The signature is the same as refresh token minus the grant type form parameter. See documentation for details.</p> </li> </ul> </div> </div> <div class="sect2"> <h3 id="migrating-from-1-0-beta-1-to-beta-4"><a class="anchor" href="#migrating-from-1-0-beta-1-to-beta-4"></a>Migrating from 1.0 Beta 1 to Beta 4</h3> <div class="ulist"> <ul> <li> <p>LDAP/AD configuration is changed. It is no longer under the "Settings" page. It is now under Users&#8594;Federation. Add Provider will show you an "ldap" option.</p> </li> <li> <p>Authentication SPI has been removed and rewritten. The new SPI is UserFederationProvider and is more flexible.</p> </li> <li> <p><code>ssl-not-required</code> +<code>ssl-required</code> +<code>all</code> +<code>external</code> +<code>none</code></p> </li> <li> <p>DB Schema has changed again.</p> </li> <li> <p>Created applications now have a full scope by default. This means that you don&#8217;t have to configure the scope of an application if you don&#8217;t want to.</p> </li> <li> <p>Format of JSON file for importing realm data was changed. Now role mappings is available under the JSON record of particular user.</p> </li> </ul> </div> </div> <div class="sect2"> <h3 id="migrating-from-1-0-alpha-4-to-beta-1"><a class="anchor" href="#migrating-from-1-0-alpha-4-to-beta-1"></a>Migrating from 1.0 Alpha 4 to Beta 1</h3> <div class="ulist"> <ul> <li> <p>DB Schema has changed. We have added export of the database to Beta 1, but not the ability to import the database from older versions. This will be supported in future releases.</p> </li> <li> <p>For all clients except bearer-only applications, you must specify at least one redirect URI. Keycloak will not allow you to log in unless you have specified a valid redirect URI for that application.</p> </li> <li> <p>Direct Grant API +<code>ON</code></p> </li> <li> <p>standalone/configuration/keycloak-server.json</p> </li> <li> <p>JavaScript adapter</p> </li> <li> <p>Session Timeout</p> </li> </ul> </div> </div> <div class="sect2"> <h3 id="migrating-from-1-0-alpha-2-to-alpha-3"><a class="anchor" href="#migrating-from-1-0-alpha-2-to-alpha-3"></a>Migrating from 1.0 Alpha 2 to Alpha 3</h3> <div class="ulist"> <ul> <li> <p>SkeletonKeyToken, SkeletonKeyScope, SkeletonKeyPrincipal, and SkeletonKeySession have been renamed to: AccessToken, AccessScope, KeycloakPrincipal, and KeycloakAuthenticatedSession respectively.</p> </li> <li> <p>ServletOAuthClient.getBearerToken() method signature has changed. It now returns an AccessTokenResponse so that you can obtain a refresh token too.</p> </li> <li> <p>adapters now check the access token expiration with every request. If the token is expired, they will attempt to invoke a refresh on the auth server using a saved refresh token.</p> </li> <li> <p>Subject in AccessToken has been changed to the User ID.</p> </li> </ul> </div> </div> <div class="sect2"> <h3 id="migrating-from-1-0-alpha-1-to-alpha-2"><a class="anchor" href="#migrating-from-1-0-alpha-1-to-alpha-2"></a>Migrating from 1.0 Alpha 1 to Alpha 2</h3> <div class="ulist"> <ul> <li> <p>DB Schema has changed. We don&#8217;t have any data migration utilities yet as of Alpha 2.</p> </li> <li> <p>JBoss and WildFly adapters are now installed via a WildFly subsystem. Please review the adapter installation documentation. Edits to standalone.xml are now required.</p> </li> <li> <p>A new credential type "secret" got introduced. Unlike other credential types, it is stored in plain text in the database and can be viewed in the admin console.</p> </li> <li> <p>Application and OAuth Client credentials are no longer required. These client types are now hard coded to use the "secret" credential type.</p> </li> <li> <p>Because of the "secret" credential change to Application and OAuth Client, you&#8217;ll have to update your keycloak.json configuration files and regenerate a secret within the Application or OAuth Client credentials tab in the administration console.</p> </li> </ul> </div> </div> </div> </div> <div class="sect1"> <h2 id="_upgrading"><a class="anchor" href="#_upgrading"></a>Upgrading the Keycloak server</h2> <div class="sectionbody"> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/upgrading.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/upgrading.adoc&amp;description=%0A%0AFile:%20upgrading/topics/upgrading.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 upgrade the server before you upgrade the adapters.</p> </div> <div class="sect2"> <h3 id="_prep_migration"><a class="anchor" href="#_prep_migration"></a>Preparing for upgrading</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/prep_migration.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/prep_migration.adoc&amp;description=%0A%0AFile:%20upgrading/topics/prep_migration.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>Perform the following steps before you upgrade the server.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Shutdown Keycloak.</p> </li> <li> <p>Back up the old installation, such as configuration, themes, and so on.</p> </li> <li> <p>If XA transaction is enabled, handle any open transactions and delete the <code>data/transaction-logs/</code> transaction directory.</p> </li> <li> <p>Back up the database using instructions in the documentation for your relational database.</p> <div class="paragraph"> <p>The database will no longer be compatible with the old server after you upgrade the server. If you need to revert the upgrade, first restore the old installation, and then restore the database from the backup copy.</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>In case the feature <code>persistent-user-sessions</code> is disabled in your current setup and the server is upgraded, all user sessions will be lost except for offline user sessions. Users owning these sessions will have to log in again. Note the feature <code>persistent-user-sessions</code> is disabled by default in the Keycloak server releases prior to 26.0.0.</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>Information about failed logins for the brute force detection and currently ongoing authentication flows is only stored in the internal caches that are cleared when Keycloak is shut down. Users currently authenticating, changing their passwords or resetting their password will need to restart the authentication flow once Keycloak is up and running again.</p> </div> </td> </tr> </table> </div> </div> <div class="sect2"> <h3 id="_install_new_version"><a class="anchor" href="#_install_new_version"></a>Downloading the Keycloak server</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/download.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/download.adoc&amp;description=%0A%0AFile:%20upgrading/topics/download.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 prepared for the upgrade, you can download the server.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Download and extract <a href="https://github.com/keycloak/keycloak/releases/download/26.0.6/keycloak-26.0.6.zip">keycloak-26.0.6.zip</a> from the Keycloak website.</p> <div class="paragraph"> <p>After extracting this file, you should have a directory that is named <code>keycloak-26.0.6</code>.</p> </div> </li> <li> <p>Move this directory to the desired location.</p> </li> <li> <p>Copy <code>conf/</code>, <code>providers/</code> and <code>themes/</code> from the previous installation to the new installation.</p> </li> </ol> </div> </div> <div class="sect2"> <h3 id="_migrate_db"><a class="anchor" href="#_migrate_db"></a>Migrating the database</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/migrate_db.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/migrate_db.adoc&amp;description=%0A%0AFile:%20upgrading/topics/migrate_db.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 automatically migrate the database schema, or you can choose to do it manually. By default the database is automatically migrated when you start the new installation for the first time.</p> </div> <div class="sect3"> <h4 id="automatic-relational-database-migration"><a class="anchor" href="#automatic-relational-database-migration"></a>Automatic relational database migration</h4> <div class="paragraph"> <p>To perform an automatic migration, start the server connected to the desired database. If the database schema has changed for the new server version, the migration starts automatically unless the database has too many records.</p> </div> <div class="paragraph"> <p>For example, creating an index on tables with millions of records can be time-consuming and cause a major service disruption. Therefore, a threshold of <code>300000</code> records exists for automatic migration. If the number of records exceeds this threshold, the index is not created. Instead, you find a warning in the server logs with the SQL commands that you can apply manually.</p> </div> <div class="paragraph"> <p>To change the threshold, set the <code>index-creation-threshold</code> property, value for the default <code>connections-liquibase</code> provider:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">kc.[sh|bat] start --spi-connections-liquibase-default-index-creation-threshold=300000</code></pre> </div> </div> </div> <div class="sect3"> <h4 id="manual-relational-database-migration"><a class="anchor" href="#manual-relational-database-migration"></a>Manual relational database migration</h4> <div class="paragraph"> <p>To enable manual upgrading of the database schema, set the <code>migration-strategy</code> property value to "manual" for the default <code>connections-jpa</code> provider:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">kc.[sh|bat] start --spi-connections-jpa-quarkus-migration-strategy=manual</code></pre> </div> </div> <div class="paragraph"> <p>When you start the server with this configuration, the server checks if the database needs to be migrated. The required changes are written to the <code>bin/keycloak-database-update.sql</code> SQL file that you can review and manually run against the database.</p> </div> <div class="paragraph"> <p>To change the path and name of the exported SQL file, set the <code>migration-export</code> property for the default <code>connections-jpa</code> provider:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">kc.[sh|bat] start --spi-connections-jpa-quarkus-migration-export=&lt;path&gt;/&lt;file.sql&gt;</code></pre> </div> </div> <div class="paragraph"> <p>For further details on how to apply this file to the database, see the documentation for your relational database. After the changes have been written to the file, the server exits.</p> </div> </div> </div> <div class="sect2"> <h3 id="_migrate_themes"><a class="anchor" href="#_migrate_themes"></a>Migrating themes</h3> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/migrate_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:%20upgrading/topics/migrate_themes.adoc&amp;description=%0A%0AFile:%20upgrading/topics/migrate_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>If you created custom themes, those themes must be migrated to the new server. Also, any changes to the built-in themes might need to be reflected in your custom themes, depending on which aspects you customized.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Copy your custom themes from the old server <code>themes</code> directory to the new server <code>themes</code> directory.</p> </li> <li> <p>Use the following sections to migrate templates, messages, and styles.</p> <div class="ulist"> <ul> <li> <p>If you customized any of the updated templates listed in <a href="#migration-changes">Migration Changes</a>, compare the template from the base theme to check for any changes you need to apply.</p> </li> <li> <p>If you customized messages, you might need to change the key or value or to add additional messages.</p> </li> <li> <p>If you customized any styles and you are extending the Keycloak themes, review the changes to the styles. If you are extending the base theme, you can skip this step.</p> </li> </ul> </div> </li> </ol> </div> <div class="sect3"> <h4 id="migrating-templates"><a class="anchor" href="#migrating-templates"></a>Migrating templates</h4> <div class="paragraph"> <p>If you customized any template, review the new version to decide about updating your customized template. If you made minor changes, you could compare the updated template to your customized template. However, if you made many changes, consider comparing the new template to your customized template. This comparison will show you what changes you need to make.</p> </div> <div class="paragraph"> <p>You can use a diff tool to compare the templates. The following screenshot compares the <code>info.ftl</code> template from the Login theme and an example custom theme:</p> </div> <div class="paragraph"> <div class="title">Updated version of a Login theme template versus a custom Login theme template</div> <p><span class="image"><img src="./images/theme-migration-meld-info-1.png" alt="Updated version of a Login theme template versus a custom Login theme template"></span></p> </div> <div class="paragraph"> <p>This comparison shows that the first change (<code>Hello world!!</code>) is a customization, while the second change (<code>if pageRedirectUri</code>) is a change to the base theme. By copying the second change to your custom template, you have successfully updated your customized template.</p> </div> <div class="paragraph"> <p>In an alternative approach, the following screenshot compares the <code>info.ftl</code> template from the old installation with the updated <code>info.ftl</code> template from the new installation:</p> </div> <div class="paragraph"> <div class="title">Login theme template from the old installation versus the updated Login theme template</div> <p><span class="image"><img src="./images/theme-migration-meld-info-2.png" alt="Login theme template from the old installation versus the updated Login theme template"></span></p> </div> <div class="paragraph"> <p>This comparison shows what has been changed in the base template. You can then manually make the same changes to your modified template. Since this approach is more complex, use this approach only if the first approach is not feasible.</p> </div> </div> <div class="sect3"> <h4 id="migrating-messages"><a class="anchor" href="#migrating-messages"></a>Migrating messages</h4> <div class="paragraph"> <p>If you added support for another language, you need to apply all the changes listed above. If you have not added support for another language, you might not need to change anything. You need to make changes only if you have changed an affected message in your theme.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>For added values, review the value of the message in the base theme to determine if you need to customize that message.</p> </li> <li> <p>For renamed keys, rename the key in your custom theme.</p> </li> <li> <p>For changed values, check the value in the base theme to determine if you need to make changes to your custom theme.</p> </li> </ol> </div> </div> <div class="sect3"> <h4 id="migrating-styles"><a class="anchor" href="#migrating-styles"></a>Migrating styles</h4> <div class="paragraph"> <p>You might need to update your custom styles to reflect changes made to the styles from the built-in themes. Consider using a diff tool to compare the changes to stylesheets between the old server installation and the new server installation.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">$ diff KEYCLOAK_HOME_OLD/themes/keycloak/login/resources/css/login.css \ KEYCLOAK_HOME_NEW/themes/keycloak/login/resources/css/login.css</code></pre> </div> </div> <div class="paragraph"> <p>Review the changes and determine if they affect your custom styling.</p> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="upgrading-keycloak-adapters"><a class="anchor" href="#upgrading-keycloak-adapters"></a>Upgrading Keycloak adapters</h2> <div class="sectionbody"> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/upgrade_adapters.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/upgrade_adapters.adoc&amp;description=%0A%0AFile:%20upgrading/topics/upgrade_adapters.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 id="_upgrade_adapters" class="paragraph"> <p>After you upgrade the Keycloak server, you can upgrade the adapters. Earlier versions of the adapter might work with later versions of the Keycloak server, but earlier versions of the Keycloak server might not work with later versions of the adapter.</p> </div> <div class="sect2"> <h3 id="_compatibility_with_older_adapters"><a class="anchor" href="#_compatibility_with_older_adapters"></a>Compatibility with older adapters</h3> <div class="paragraph"> <p>Newer versions of the Keycloak server potentially work with older versions of the adapters. However, some fixes of the Keycloak server may break compatibility with older versions of the adapters. For example, a new implementation of the OpenID Connect specification may not match older client adapter versions.</p> </div> <div class="paragraph"> <p>For this situation, you can use Compatibility modes. For OpenID Connect clients, the Admin Console includes <strong>OpenID Connect Compatibility Modes</strong> on the page with client details. With this option, you can disable some new aspects of the Keycloak server to preserve compatibility with older client adapters. For more details, see the tool tips of individual switches.</p> </div> </div> <div class="sect2"> <h3 id="_upgrade_eap_adapter"><a class="anchor" href="#_upgrade_eap_adapter"></a>Upgrading the EAP adapter</h3> <div class="paragraph"> <p>To upgrade the WildFly adapter, complete the following steps:</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Download the new adapter archive.</p> </li> <li> <p>Remove the previous adapter modules by deleting the <code>WILDFLY_HOME/modules/system/add-ons/keycloak/</code> directory.</p> </li> <li> <p>Unzip the downloaded archive into <code>WILDFLY_HOME</code>.</p> </li> </ol> </div> </div> <div class="sect2"> <h3 id="_upgrade_js_adapter"><a class="anchor" href="#_upgrade_js_adapter"></a>Upgrading the JavaScript adapter</h3> <div class="paragraph"> <p>To upgrade a JavaScript adapter, install the latest version <a href="https://www.npmjs.com/package/keycloak-js">from NPM</a>.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p><code>npm install keycloak-js@latest</code></p> </li> </ol> </div> </div> <div class="sect2"> <h3 id="_upgrade_nodejs_adapter"><a class="anchor" href="#_upgrade_nodejs_adapter"></a>Upgrading the <code>Node.js</code> adapter</h3> <div class="paragraph"> <p>To upgrade a <code>Node.js</code> adapter that has been copied to your web application, perform the following procedure.</p> </div> <div class="olist arabic"> <div class="title">Procedure</div> <ol class="arabic"> <li> <p>Download the new adapter archive.</p> </li> <li> <p>Remove the existing <code>Node.js</code> adapter directory</p> </li> <li> <p>Unzip the updated file into its place</p> </li> <li> <p>Change the dependency for keycloak-connect in the <code>package.json</code> of your application</p> </li> </ol> </div> </div> </div> </div> <div class="sect1"> <h2 id="upgrading-the-keycloak-client-libraries"><a class="anchor" href="#upgrading-the-keycloak-client-libraries"></a>Upgrading the Keycloak Client Libraries</h2> <div class="sectionbody"> <div class="sidebarblock page-links"> <div class="content"> <a href="https://github.com/keycloak/keycloak/tree/main/docs/documentation/upgrading/topics/upgrade_client_libs.adoc" target="_blank" rel="noopener">Edit this section</a> <a href="https://github.com/keycloak/keycloak/issues/new?template=bug.yml&amp;title=Docs:%20upgrading/topics/upgrade_client_libs.adoc&amp;description=%0A%0AFile:%20upgrading/topics/upgrade_client_libs.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 id="_upgrade_client_libraries" class="paragraph"> <p>The client libraries are those artifacts:</p> </div> <div class="ulist"> <ul> <li> <p>Java admin client - Maven artifact <code>org.keycloak:keycloak-admin-client</code></p> </li> <li> <p>Java authorization client - Maven artifact <code>org.keycloak:keycloak-authz-client</code></p> </li> <li> <p>Java policy enforcer - Maven artifact <code>org.keycloak:keycloak-policy-enforcer</code></p> </li> </ul> </div> <div class="paragraph"> <p>The client libraries are supported with the last supported Keycloak server version.</p> </div> <div class="paragraph"> <p>It is possible that client libraries may work even with the older releases of the Keycloak server, but it is not guaranteed and officially supported.</p> </div> <div class="paragraph"> <p>It may be needed to consult the javadoc of the client libraries like Java admin-client to see what endpoints and parameters are supported with which Keycloak server version.</p> </div> </div> </div> </div> <div id="footer"> <div id="footer-text"> Last updated 2024-11-22 05:31:23 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