KEYCLOAK-1033 Add PKCE support for JS Adapter
This adds support for the "S256" code_challenge_method to the JS Adapter. Note that the method "plain" was deliberately left out as is not recommended to be used in new applications. Note that this PR includes two libraries: - [base64-js]{@link https://github.com/beatgammit/base64-js} - [js-sha256]{@link https://github.com/emn178/js-sha256} `base64-js` is needed for cross-browser support for decoding the Uint8ArrayBuffer returned by `crypto.getRandomValues` to a PKCE compatible base64 string. `js-sha256` library is required because the `crypto.subtle.digest` support is not available for all browsers. The PKCE codeVerifier is stored in the callbackStore of the JS Adapter. Note: This PR is based on #5255 which got messed up during a rebase.
This commit is contained in:
parent
be2e1c333e
commit
2825619243
4 changed files with 127 additions and 12 deletions
|
@ -34,7 +34,8 @@ declare namespace Keycloak {
|
||||||
type KeycloakResponseMode = 'query'|'fragment';
|
type KeycloakResponseMode = 'query'|'fragment';
|
||||||
type KeycloakResponseType = 'code'|'id_token token'|'code id_token token';
|
type KeycloakResponseType = 'code'|'id_token token'|'code id_token token';
|
||||||
type KeycloakFlow = 'standard'|'implicit'|'hybrid';
|
type KeycloakFlow = 'standard'|'implicit'|'hybrid';
|
||||||
type KeycloakPromiseType = 'native'
|
type KeycloakPromiseType = 'native';
|
||||||
|
type KeycloakPkceMethod = 'S256';
|
||||||
|
|
||||||
interface KeycloakInitOptions {
|
interface KeycloakInitOptions {
|
||||||
/**
|
/**
|
||||||
|
@ -117,6 +118,13 @@ declare namespace Keycloak {
|
||||||
* Keycloak specific promise objects.
|
* Keycloak specific promise objects.
|
||||||
*/
|
*/
|
||||||
promiseType?: KeycloakPromiseType;
|
promiseType?: KeycloakPromiseType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the Proof Key for Code Exchange (PKCE) method to use.
|
||||||
|
* The currently allowed method is 'S256'.
|
||||||
|
* If not configured, PKCE will not be used.
|
||||||
|
*/
|
||||||
|
pkceMethod?: KeycloakPkceMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface KeycloakLoginOptions {
|
interface KeycloakLoginOptions {
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -69,6 +69,15 @@ public class JSObjectBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public JSObjectBuilder pkceS256() {
|
||||||
|
return pkceMethod("S256");
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSObjectBuilder pkceMethod(String method) {
|
||||||
|
arguments.put("pkceMethod", method);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public String build() {
|
public String build() {
|
||||||
StringBuilder argument = new StringBuilder("{");
|
StringBuilder argument = new StringBuilder("{");
|
||||||
String comma = "";
|
String comma = "";
|
||||||
|
|
|
@ -142,6 +142,17 @@ public class JavascriptAdapterTest extends AbstractJavascriptTest {
|
||||||
.login("{kcLocale: 'en'}", assertLocaleIsSet("en"));
|
.login("{kcLocale: 'en'}", assertLocaleIsSet("en"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLoginWithPkceS256() {
|
||||||
|
JSObjectBuilder pkceS256 = defaultArguments().pkceS256();
|
||||||
|
testExecutor.init(pkceS256, this::assertInitNotAuth)
|
||||||
|
.login(this::assertOnLoginPage)
|
||||||
|
.loginForm(testUser, this::assertOnTestAppUrl)
|
||||||
|
.init(pkceS256, this::assertSuccessfullyLoggedIn)
|
||||||
|
.logout(this::assertOnTestAppUrl)
|
||||||
|
.init(pkceS256, this::assertInitNotAuth);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRefreshToken() {
|
public void testRefreshToken() {
|
||||||
testExecutor.init(defaultArguments(), this::assertInitNotAuth)
|
testExecutor.init(defaultArguments(), this::assertInitNotAuth)
|
||||||
|
|
Loading…
Reference in a new issue