diff --git a/docs/documentation/release_notes/index.adoc b/docs/documentation/release_notes/index.adoc index e7de48672fd..2e656815800 100644 --- a/docs/documentation/release_notes/index.adoc +++ b/docs/documentation/release_notes/index.adoc @@ -13,6 +13,9 @@ include::topics/templates/document-attributes.adoc[] :release_header_latest_link: {releasenotes_link_latest} include::topics/templates/release-header.adoc[] +== {project_name_full} 22.0.0 +include::topics/22_0_0.adoc[leveloffset=2] + == {project_name_full} 21.0.0 include::topics/21_0_0.adoc[leveloffset=2] diff --git a/docs/documentation/release_notes/topics/22_0_0.adoc b/docs/documentation/release_notes/topics/22_0_0.adoc new file mode 100644 index 00000000000..eddf3c26969 --- /dev/null +++ b/docs/documentation/release_notes/topics/22_0_0.adoc @@ -0,0 +1,3 @@ += Legacy Promise API removed from Keycloak JS adapter + +With this release, we have removed the legacy Promise API methods from the Keycloak JS adapter. This means that calling `.success()` and `.error()` on promises returned from the adapter is no longer possible. diff --git a/docs/documentation/upgrading/topics/keycloak/changes-22_0_0.adoc b/docs/documentation/upgrading/topics/keycloak/changes-22_0_0.adoc index 4f0c9cce7f7..7f2a012dc6a 100644 --- a/docs/documentation/upgrading/topics/keycloak/changes-22_0_0.adoc +++ b/docs/documentation/upgrading/topics/keycloak/changes-22_0_0.adoc @@ -7,4 +7,45 @@ Default `Client ID` mapper of `Service Account Client` has been changed. `Token - https://www.rfc-editor.org/rfc/rfc7662#section-2.2[OAuth 2.0 Token Introspection] - https://datatracker.ietf.org/doc/html/rfc8693#section-4.3[OAuth 2.0 Token Exchange] -`clientId` userSession note still exists. \ No newline at end of file +`clientId` userSession note still exists. + += Legacy Promise API removed from Keycloak JS adapter + +The legacy Promise API methods have been removed from the Keycloak JS adapter. This means that calling `.success()` and `.error()` on promises returned from the adapter is no longer possible. Instead standardized Promise methods such as https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then[`.then()`] and https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch[`.catch()`] should be used. + +*Before:* +```javascript +const keycloak = new Keycloak(); + +keycloak.init() + .success(function(authenticated) { + alert(authenticated ? 'authenticated' : 'not authenticated'); + }).error(function() { + alert('failed to initialize'); + }); +``` + +*After:* +```javascript +const keycloak = new Keycloak(); + +keycloak.init() + .then(function(authenticated) { + alert(authenticated ? 'authenticated' : 'not authenticated'); + }).catch(function() { + alert('failed to initialize'); + }); +``` + +Or alternatively, when using the https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await[`await`] keyword to unwrap these promises: + +```javascript +const keycloak = new Keycloak(); + +try { + const authenticated = await keycloak.init(); + alert(authenticated ? 'authenticated' : 'not authenticated'); +} catch (error) { + alert('failed to initialize'); +} +``` diff --git a/js/libs/keycloak-js/dist/keycloak.d.ts b/js/libs/keycloak-js/dist/keycloak.d.ts index 562676163e3..6052af7848b 100644 --- a/js/libs/keycloak-js/dist/keycloak.d.ts +++ b/js/libs/keycloak-js/dist/keycloak.d.ts @@ -277,35 +277,16 @@ export interface KeycloakAccountOptions { */ redirectUri?: string; } - -export type KeycloakPromiseCallback = (result: T) => void; - -export interface KeycloakPromise extends Promise { - /** - * Function to call if the promised action succeeds. - * - * @deprecated Use `.then()` instead. - */ - success(callback: KeycloakPromiseCallback): KeycloakPromise; - - /** - * Function to call if the promised action throws an error. - * - * @deprecated Use `.catch()` instead. - */ - error(callback: KeycloakPromiseCallback): KeycloakPromise; -} - export interface KeycloakError { error: string; error_description: string; } export interface KeycloakAdapter { - login(options?: KeycloakLoginOptions): KeycloakPromise; - logout(options?: KeycloakLogoutOptions): KeycloakPromise; - register(options?: KeycloakRegisterOptions): KeycloakPromise; - accountManagement(): KeycloakPromise; + login(options?: KeycloakLoginOptions): Promise; + logout(options?: KeycloakLogoutOptions): Promise; + register(options?: KeycloakRegisterOptions): Promise; + accountManagement(): Promise; redirectUri(options: { redirectUri: string; }, encodeHash: boolean): string; } @@ -536,30 +517,30 @@ declare class Keycloak { * @param initOptions Initialization options. * @returns A promise to set functions to be invoked on success or error. */ - init(initOptions: KeycloakInitOptions): KeycloakPromise; + init(initOptions: KeycloakInitOptions): Promise; /** * Redirects to login form. * @param options Login options. */ - login(options?: KeycloakLoginOptions): KeycloakPromise; + login(options?: KeycloakLoginOptions): Promise; /** * Redirects to logout. * @param options Logout options. */ - logout(options?: KeycloakLogoutOptions): KeycloakPromise; + logout(options?: KeycloakLogoutOptions): Promise; /** * Redirects to registration form. * @param options The options used for the registration. */ - register(options?: KeycloakRegisterOptions): KeycloakPromise; + register(options?: KeycloakRegisterOptions): Promise; /** * Redirects to the Account Management Console. */ - accountManagement(): KeycloakPromise; + accountManagement(): Promise; /** * Returns the URL to login form. @@ -610,7 +591,7 @@ declare class Keycloak { * alert('Failed to refresh the token, or the session has expired'); * }); */ - updateToken(minValidity: number): KeycloakPromise; + updateToken(minValidity: number): Promise; /** * Clears authentication state, including tokens. This can be useful if @@ -637,12 +618,12 @@ declare class Keycloak { * Loads the user's profile. * @returns A promise to set functions to be invoked on success or error. */ - loadUserProfile(): KeycloakPromise; + loadUserProfile(): Promise; /** * @private Undocumented. */ - loadUserInfo(): KeycloakPromise<{}, void>; + loadUserInfo(): Promise<{}>; } export default Keycloak; diff --git a/js/libs/keycloak-js/src/keycloak.js b/js/libs/keycloak-js/src/keycloak.js index ab284cd29f7..3b1af3c0080 100755 --- a/js/libs/keycloak-js/src/keycloak.js +++ b/js/libs/keycloak-js/src/keycloak.js @@ -21,15 +21,6 @@ if (typeof Promise === 'undefined') { throw Error('Keycloak requires an environment that supports Promises. Make sure that you include the appropriate polyfill.'); } -var loggedPromiseDeprecation = false; - -function logPromiseDeprecation() { - if (!loggedPromiseDeprecation) { - loggedPromiseDeprecation = true; - console.warn('[KEYCLOAK] Usage of legacy style promise methods such as `.error()` and `.success()` has been deprecated and support will be removed in future versions. Use standard style promise methods such as `.then() and `.catch()` instead.'); - } -} - function Keycloak (config) { if (!(this instanceof Keycloak)) { return new Keycloak(config); @@ -1166,26 +1157,6 @@ function Keycloak (config) { p.reject = reject; }); - p.promise.success = function(callback) { - logPromiseDeprecation(); - - this.then(function handleSuccess(value) { - callback(value); - }); - - return this; - } - - p.promise.error = function(callback) { - logPromiseDeprecation(); - - this.catch(function handleError(error) { - callback(error); - }); - - return this; - } - return p; } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/javascript/JavascriptAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/javascript/JavascriptAdapterTest.java index d97a51ac3b9..15c48144784 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/javascript/JavascriptAdapterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/javascript/JavascriptAdapterTest.java @@ -811,23 +811,6 @@ public class JavascriptAdapterTest extends AbstractJavascriptTest { }); } - @Test - public void testRefreshTokenWithDeprecatedPromiseHandles() { - String refreshWithDeprecatedHandles = "var callback = arguments[arguments.length - 1];" + - " window.keycloak.updateToken(9999).success(function (refreshed) {" + - " callback('Success handle');" + - " }).error(function () {" + - " callback('Error handle');" + - " });"; - - testExecutor.init(defaultArguments(), this::assertInitNotAuth) - .executeAsyncScript(refreshWithDeprecatedHandles, assertOutputContains("Error handle")) - .login(this::assertOnLoginPage) - .loginForm(testUser, this::assertOnTestAppUrl) - .init(defaultArguments(), this::assertInitAuth) - .executeAsyncScript(refreshWithDeprecatedHandles, assertOutputContains("Success handle")); - } - @Test public void testAIAFromJavascriptAdapterSuccess() { testExecutor.init(defaultArguments(), this::assertInitNotAuth)