Remove legacy Promise APIs from Keycloak JS (#19389)

This commit is contained in:
Jon Koops 2023-03-29 18:29:27 +02:00 committed by GitHub
parent df6b9f9d4b
commit 8f627517cb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 60 additions and 78 deletions

View file

@ -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]

View file

@ -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.

View file

@ -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.
`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');
}
```

View file

@ -277,35 +277,16 @@ export interface KeycloakAccountOptions {
*/
redirectUri?: string;
}
export type KeycloakPromiseCallback<T> = (result: T) => void;
export interface KeycloakPromise<TSuccess, TError> extends Promise<TSuccess> {
/**
* Function to call if the promised action succeeds.
*
* @deprecated Use `.then()` instead.
*/
success(callback: KeycloakPromiseCallback<TSuccess>): KeycloakPromise<TSuccess, TError>;
/**
* Function to call if the promised action throws an error.
*
* @deprecated Use `.catch()` instead.
*/
error(callback: KeycloakPromiseCallback<TError>): KeycloakPromise<TSuccess, TError>;
}
export interface KeycloakError {
error: string;
error_description: string;
}
export interface KeycloakAdapter {
login(options?: KeycloakLoginOptions): KeycloakPromise<void, void>;
logout(options?: KeycloakLogoutOptions): KeycloakPromise<void, void>;
register(options?: KeycloakRegisterOptions): KeycloakPromise<void, void>;
accountManagement(): KeycloakPromise<void, void>;
login(options?: KeycloakLoginOptions): Promise<void>;
logout(options?: KeycloakLogoutOptions): Promise<void>;
register(options?: KeycloakRegisterOptions): Promise<void>;
accountManagement(): Promise<void>;
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<boolean, KeycloakError>;
init(initOptions: KeycloakInitOptions): Promise<boolean>;
/**
* Redirects to login form.
* @param options Login options.
*/
login(options?: KeycloakLoginOptions): KeycloakPromise<void, void>;
login(options?: KeycloakLoginOptions): Promise<void>;
/**
* Redirects to logout.
* @param options Logout options.
*/
logout(options?: KeycloakLogoutOptions): KeycloakPromise<void, void>;
logout(options?: KeycloakLogoutOptions): Promise<void>;
/**
* Redirects to registration form.
* @param options The options used for the registration.
*/
register(options?: KeycloakRegisterOptions): KeycloakPromise<void, void>;
register(options?: KeycloakRegisterOptions): Promise<void>;
/**
* Redirects to the Account Management Console.
*/
accountManagement(): KeycloakPromise<void, void>;
accountManagement(): Promise<void>;
/**
* 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<boolean, boolean>;
updateToken(minValidity: number): Promise<boolean>;
/**
* 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<KeycloakProfile, void>;
loadUserProfile(): Promise<KeycloakProfile>;
/**
* @private Undocumented.
*/
loadUserInfo(): KeycloakPromise<{}, void>;
loadUserInfo(): Promise<{}>;
}
export default Keycloak;

View file

@ -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;
}

View file

@ -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)