-
Notifications
You must be signed in to change notification settings - Fork 39
Description
Describe the bug
Keycloak-js assumes that "refresh token" payload is JWT.
While the Keycloak Server does issue refresh tokens with JWT payload, many other OIDC servers do not, and the OIDC spec does not require this.
For example, our company uses keycloak-js with the Keycloak Server, but additionally with Ory Hydra OIDC Server. In the Hydra case, the refresh tokens look like this:
LaRIEB5jv-cnTmgEYEdAL8Uig2NoTCC2y_OJwWafMMY.-yn4F5AIdrDziEt4qp--0c-sfsTgnIQhQ6N0Mp8dZ54
Notice the payload is not JWT.
But keycloak.js tries to parse the payload as jwt:
https://github.com/keycloak/keycloak-js/blob/main/lib/keycloak.js#L1538
if (refreshToken) {
this.refreshToken = refreshToken;
this.refreshTokenParsed = decodeToken(refreshToken);
}This throws a parse error, and causes login to fail :(
An easy solution would be to add an option flag here:
if (refreshToken) {
this.refreshToken = refreshToken;
if (this.refreshTokenIsJWT === true) {
this.refreshTokenParsed = decodeToken(refreshToken);
}
}
Version
26.2.0
Expected behavior
Keycloak should support cases where the "refresh token" payload is not JWT.
.... i.e. Ory Hdra OIDC server issues refresh tokens that look like this:
LaRIEB5jv-cnTmgEYEdAL8Uig2NoTCC2y_OJwWafMMY.-yn4F5AIdrDziEt4qp--0c-sfsTgnIQhQ6N0Mp8dZ54
There should be an option so that keycloak.js does not try to parse the payload as JWT
Actual behavior
Currently keycloak.js assumes "refresh token" payload is always JWT, and it tries to parse this.
For example, an Ory Hydra refresh token looks like this:
LaRIEB5jv-cnTmgEYEdAL8Uig2NoTCC2y_OJwWafMMY.-yn4F5AIdrDziEt4qp--0c-sfsTgnIQhQ6N0Mp8dZ54
But keycloak.js tries to parse the payload as jwt:
https://github.com/keycloak/keycloak-js/blob/main/lib/keycloak.js#L1538
if (refreshToken) {
this.refreshToken = refreshToken;
this.refreshTokenParsed = decodeToken(refreshToken);
}This throws a parse error, and causes login to fail :(
How to Reproduce?
Pass a refresh token with non-JWT payload into Keycloak:
// Non-JWT payload
const REFRESH_TOKEN = "LaRIEB5jv-cnTmgEYEdAL8Uig2NoTCC2y_OJwWafMMY.-yn4F5AIdrDziEt4qp--0c-sfsTgnIQhQ6N0Mp8dZ54"
// JWT payload
const ACCESS_TOKEN = "eyJhbGciOiJSUzI1NiIsImtpZCI6InB1YmxpYzpjZTMyMzE5Ny0zZjE1LTQ5OTctOWJiNS01ZWNhYzkxYmUzNzciLCJ0eXAiOiJKV1QifQ.eyJhdWQiOltdLCJjbGllbnRfaWQiOiI5ZTAxMTBiOC0xYzFmLTQzZmItYTU4YS1lNzM2ZWY1Mjg3NjYiLCJleHAiOjE3Mjc4ODc2MjMsImV4dCI6e30sImlhdCI6MTcyNzg4NDAyMiwiaXNzIjoiaHR0cHM6Ly9jZGMxYy1sb2dpbi5sZXhpc25leGlzLmNvbS8iLCJqdGkiOiJiZDY4NTg5Yi1mMjY0LTRiNjAtOWFjNi0xODc2OGZhZDUyNjYiLCJuYmYiOjE3Mjc4ODQwMjIsInNjcCI6WyJvcGVuaWQiLCJvZmZsaW5lIiwiZW1haWwiLCJ0ZXN0Um9sZSJdLCJzdWIiOiJ1cm46dXNlcjpDQTIwMDMzODQ1NSJ9.fnLO1eDpQ2llUUbFx70yRA_sYEIQMVZAKUgIvgjl5l_PBajqEX9kV6GGtzihrnu4VOE2b-e5C6AyBbPNwOMz-sdoY7hGUebJ7AJVkrCIPlFzbZ8_WQILL1F2ff2Sghw95XrqosTeaU-6TxOJJqXQEd1LpQRI9e86TBJ6m6LjC-GYGPP3nGhjrlizLrNSsB8ZOZNnSldQ2alkO-_YK66L5hyicY_kZ3FsENS4jdTS24FOwQALry_Gj8CLBftoQKaWTLPoAyrlnDqK53z_2EadZUueexIFiapo3F1_P-_frdFEWqNbDZ8gHF5wy0Y40CIKpgoQNaSp7osbGFIYfTVswG-OWXV82DpvC_pm9BHQfh7DYQpj2jTr78ypPy6LzViffbIWAdnuJ8QCEW6aP1vOghHVF4P9wuT8Hs-d2nB0DdDDA-kJdjjvKULnuHjlO00iJRcliZOSyw71p52rnmiLmCfEgxezr4kPnyhlNBk75fx3OJjamFmB0tM0EolIogn6EC66kvygNoSSMl_E2u0MP01Ya8iuKqPirGIkO5YHJ2SZ4V3TgM8Uf9cADtQo5X0JqrfLMwUJXBtQTArsMQrHQQthsi5puDUUcLjo5-jCcqUVuF_tUzeNBMRWuUxGBWUth4qhe_MI8Ei5k2h7CMSsAEjKq94PMfz-guRxolxLns8"
keycloak = new Keycloak({
clientId: ...
realm: ....
url: ....
})
keycloak.init({
token: ACCESS_TOKEN,
refreshToken: REFRESH_TOKEN,
idToken: ID_TOKEN,
})This should trigger:
setToken(token, refreshToken)
which should then trigger:
this.refreshTokenParsed = decodeToken(refreshToken);
which will throw a ParseError
Anything else?
No response