fredx87 / cypress-keycloak-commands Goto Github PK
View Code? Open in Web Editor NEWCypress commands for login with Keycloak
License: MIT License
Cypress commands for login with Keycloak
License: MIT License
Keycloak works great with Angular apps. I have had zero success testing my app due to Cypress.io's restriction of cross-domains. In a nutshell, I can log in using Keycloak (domain 1), using this cypress-keycloak-command (or by writing the steps out in a custom command).
BUT I cannot then make a call to my Angular app (domain 2) either using cy.visit('/') or cy.request('http://myAngularAppURL').
Has anyone successfully tested their application with this type of setup using Cypress?
Is anything in Cypress Keycloak Commands that addresses this issue?
I have searched endlessly and no solution is available. I have tried sending the auth-bearer when I make the request to my application, but this doesn't appear to be enough for Keycloak to accept as isAccessAllowed() in my Angular AuthGuard.
What am I missing?
The user file in the fixture folder is in my opinion outdated,
give the possibility to put the user info in the env like other parameters
"env": {
"auth_base_url": "https://auth.server/auth",
"auth_realm": "my_realm",
"auth_client_id": "my_client_id",
"username": "user",
"password": "password"
}
Our tests login via kcLogin, skipping the actual login screen. This worked fine in both Chrome, Firefox and Electon, right until the point we've upgraded to Chrome 94.
It looks like kcLogin still makes the correct rest calls, getting 200s, but the user isn't logged in anymore when the test opens the page.
It does still work fine in Firefox 91 and Electron 89.
Does anyone have an idea how to solve this issue?
Cypress.json:
{
"env": {
"url": "http://localhost:3097",
"auth_base_url": "http://vasiam.test.paas.vasdc.be/auth",
"auth_realm": "wzcmh",
"auth_client_id": "ui"
},
...
"chromeWebSecurity": false,
...
}
```
Wouldn't it be sensible to allow environment variables to determine the user, as is common in a CI context?
This solution requires one to commit user credentials into git ๐
In some KC configurations the client-secret is also required.
The quick fix below adds the client-secret from the cypress environment configuration (auth_client_secret) as client-secret (client_secret) in the token-request.
Maybe this value should be optional and only added if defined.
Index: node_modules/cypress-keycloak-commands/dist/kc-login.js
===================================================================
--- node_modules/cypress-keycloak-commands/dist/kc-login.js (date 1587028385032)
+++ node_modules/cypress-keycloak-commands/dist/kc-login.js (date 1587028385032)
@@ -7,6 +7,7 @@
var authBaseUrl = Cypress.env("auth_base_url");
var realm = Cypress.env("auth_realm");
var client_id = Cypress.env("auth_client_id");
+ var client_secret = Cypress.env("auth_client_secret");
cy.request({
url: authBaseUrl + "/realms/" + realm + "/protocol/openid-connect/auth",
followRedirect: false,
@@ -41,6 +42,7 @@
url: authBaseUrl + "/realms/" + realm + "/protocol/openid-connect/token",
body: {
client_id: client_id,
+ client_secret: client_secret,
redirect_uri: Cypress.config("baseUrl"),
code: code,
grant_type: "authorization_code"
In the docs the problem with the session status iframe is mentioned.
Besides from changing the frontend only for testing it is also possible to just provide a fake response for the iframe:
cy.intercept(`<yourKeycloakInstance>/login-status-iframe.html`,
{body: '<html><body><script>window.addEventListener("message",
(event) => {event.source.postMessage(\'unchanged\', event.origin);}, false);</script></body></html>'});
(see https://openid.net/specs/openid-connect-session-1_0.html#RPiframe)
I'm currently using this to avoid changing the frontend config only for testing.
That could be one possible fix for issues like issue #23.
Happy to provide a PR if this is helpful.
Hi, I'm trying to authenticate to my API which uses OTP to login, but I'm having a hard time figuring out where do i find the otp_secret
and the otp_credential_id
.
I'm not sure this would be the place to ask, it's more of a keycloak question, but since there is an example in the documentation I was hoping someone could give any kind of directions.
Thanks
cypress-keycloak-commands library is still using cy.sever()
and cy.route()
. These commands are deprecated in Cypress 12 version. the test cases fail with cypress 12.
the below code in file
cy.server();
cy.route(
"post",
`${authBaseUrl}/realms/${realm}/protocol/openid-connect/token`,
token
);
cy.route(`${authBaseUrl}/realms/${realm}/account`, account);
should be replaced with the below in order to work:
cy.intercept(
{method: 'post', url: authBaseUrl + "/realms/" + realm + "/protocol/openid-connect/token"},
token
);
cy.intercept({method: 'get', url: authBaseUrl + "/realms/" + realm + "/account"}, account);
Source: https://docs.cypress.io/guides/references/migration-guide
Hi,
Thanks a lot for your lib. Using the kcFakeLogin , we have speeded up our test execution.
When I run the tests against a local running application (ng serve
). It works like a charm. (See stubbing of the /token
request)
But if I run the tests against the production runtime (build with ng build --prod), the token request is not stubbed.
I though it was related to the fact that Cypress cannot stub fetch
request. See this issue.
The Cypress team recently added an experimental feature to allow fetch
request stubbing. (see doc here) but it doesn't seem to change anything. My fetch
request is still not stubbed.
Do you have any idea why it doesn't work?
I have a couple of projects running the tests in SauceLabs. They were working correctly for a long time, but from 04/29/2021 they start failing with the error:
Sauce Cypress Runner 5.9.1
Preparing npm environment
Installing packages: [email protected]
FetchError: request to https://registry.npmjs.org/cypress-keycloak-commands failed, reason: self signed certificate in certificate chain
at ClientRequest. (D:\sauce-cypress-runner\5.9.1\bundle\node_modules\npm\node_modules\node-fetch-npm\src\index.js:68:14)
at ClientRequest.emit (events.js:315:20)
at ClientRequest.EventEmitter.emit (domain.js:467:12)
at TLSSocket.socketErrorListener (_http_client.js:469:9)
at TLSSocket.emit (events.js:315:20)
at TLSSocket.EventEmitter.emit (domain.js:467:12)
at emitErrorNT (internal/streams/destroy.js:106:8)
at emitErrorCloseNT (internal/streams/destroy.js:74:3)
at processTicksAndRejections (internal/process/task_queues.js:80:21) {
type: 'system',
errno: 'SELF_SIGNED_CERT_IN_CHAIN',
code: 'SELF_SIGNED_CERT_IN_CHAIN'
}
Any idea what could be the problem?
Is it possible to login when you have PKCE enabled in your Keycloak client? https://oauth.net/2/pkce/
I have PKCE enabled and this gives errors when I try to login with this library. When I disable PKCE, the login works just fine. Am I doing something wrong or is it just not supported? If so, it would be nice if the documentation could be extended with the remark that PKCE is currently not supported. It would be even nicer if PKCE would be supported by the library.
I've been trying ot get cypress-keycloak-commands running both with kcFakeLogin and kcLogin (have not had any success with either).
Trying to do a real login with kcLogin results in the following error:
TypeError: Failed to construct 'URL': Invalid URL
at Object.getAuthCodeFromLocation (http://localhost:3000/__cypress/tests?p=cypress/support/index.js:327:15)
digging into the code, it's expecting to receive a response.headers["location"]
from keycloak. However that does not exist in the response I get from my keycloak instance:
{
"Request Body": "username=mark@*****.com&password=********",
"Request Headers": {
"Connection": "keep-alive",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36",
"accept": "*/*",
"cookie": "KC_RESTART=******.platform-keycloak-1",
"content-type": "application/x-www-form-urlencoded",
"accept-encoding": "gzip, deflate",
"content-length": 66
},
"Request URL": "https://sso.******.com/auth/realms/rogers/login-actions/authenticate?session_code=******&execution=7e758598-c100-441e-bc6d-b8afe5091585&client_id=react-admin&tab_id=3xiTIiDql64",
"Response Body": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" class=\"login-pf\">\n\n<head>\n <meta charset=\"utf-8\">\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n <meta name=\"robots\" content=\"noindex, nofollow\">\n\n <meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"/>\n <title>Log in to ****</title>\n <link rel=\"icon\" href=\"/auth/resources/4.8.3.final/login/keycloak-theme-colony/img/favicon.ico\" />\n <link href=\"/auth/resources/4.8.3.final/login/keycloak-theme-colony/css/styles.css\" rel=\"stylesheet\" />\n<SCRIPT> if (typeof history.replaceState === 'function') { history.replaceState({}, \"some title\", \"https://sso.******.com/auth/realms/****/login-actions/authenticate?execution=7e758598-c100-441e-bc6d-b8afe5091585&client_id=react-admin&tab_id=3xiTIiDql64\"); }</SCRIPT></head>\n\n<body class=\"\">\n <div class=\"login-pf-page\">\n <div id=\"kc-header\" class=\"login-pf-page-header\">\n <div id=\"kc-header-wrapper\" class=\"\">rogers</div>\n </div>\n <div class=\"card-pf login-pf-accounts\">\n <header class=\"login-pf-header\">\n <h1 id=\"kc-page-title\"> Log In\n\n</h1>\n </header>\n <div id=\"kc-content\">\n <div id=\"kc-content-wrapper\">\n\n <div class=\"alert alert-error\">\n \n \n <span class=\"pficon pficon-error-circle-o\"></span>\n \n <span class=\"kc-feedback-text\">Invalid username or password.</span>\n </div>\n\n <div id=\"kc-form\" class=\"row\">\n <div id=\"kc-form-wrapper\" class=\"col-xs-12 col-sm-6 login-pf-social-section\">\n <form id=\"kc-form-login\" onsubmit=\"login.disabled = true; return true;\" action=\"https://sso.*****.com/auth/realms/***/login-actions/authenticate?session_code=*****&execution=7e758598-c100-441e-bc6d-b8afe5091585&client_id=react-admin&tab_id=3xiTIiDql64\" method=\"post\">\n <div class=\"form-group\">\n <label for=\"username\" class=\"control-label\">Username or email</label>\n\n <input tabindex=\"1\" id=\"username\" class=\"form-control\" name=\"username\" value=\"mark@******.com\" type=\"text\" autofocus autocomplete=\"off\" />\n </div>\n\n <div class=\"form-group\">\n <label for=\"password\" class=\"control-label\">Password</label>\n <input tabindex=\"2\" id=\"password\" class=\"form-control\" name=\"password\" type=\"password\" autocomplete=\"off\" />\n </div>\n\n <div class=\"form-group login-pf-settings\">\n <div id=\"kc-form-options\">\n </div>\n <div class=\"\">\n </div>\n\n </div>\n\n <div id=\"kc-form-buttons\" class=\"form-group\">\n <input tabindex=\"4\" class=\"btn btn-primary btn-block btn-lg\" name=\"login\" id=\"kc-login\" type=\"submit\" value=\"Log In\"/>\n </div>\n </form>\n </div>\n <div id=\"kc-social-providers\" class=\"col-xs-12 col-sm-6 login-pf-social-section\">\n <ul class=\"login-pf-social list-unstyled login-pf-social-all \">\n <li class=\"login-pf-social-link\"><a href=\"/auth/realms/****/broker/r4b/login?client_id=react-admin&tab_id=3xiTIiDql64&session_code=jhQzUBJy4bKmcRGtDuR9MtsWzJKY3XiGy0wNVPO7f7U\" id=\"zocial-r4b\" class=\"zocial saml\"> <span>******</span></a></li>\n </ul>\n </div>\n </div>\n\n\n <div id=\"kc-info\" class=\"login-pf-signup\">\n <div id=\"kc-info-wrapper\" class=\"\">\n\n </div>\n </div>\n </div>\n </div>\n\n </div>\n </div>\n</body>\n</html>\n",
"Response Headers": {
"cache-control": "no-store, must-revalidate, max-age=0",
"x-xss-protection": "1; mode=block",
"x-frame-options": "SAMEORIGIN",
"content-security-policy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';",
"date": "Fri, 25 Sep 2020 22:00:13 GMT",
"x-robots-tag": "none",
"strict-transport-security": "max-age=31536000; includeSubDomains",
"x-content-type-options": "nosniff",
"content-type": "text/html;charset=utf-8",
"content-length": "3946",
"content-language": "en",
"via": "1.1 google",
"alt-svc": "clear"
},
"Response Status": 200
}
my initConfig:
{
responseMode: 'fragment',
flow: 'standard',
onLoad: 'login-required',
checkLoginIframe: false,
}
my users/user.json
fixture:
{
"username": "mark@******.com",
"password": "*******",
"fakeLogin": {
"access_token": "********",
"refreshToken": "********",
"id_token": "********",
"account": {
"allowed_company_uids": "1",
"aud": "account",
"auth_time": 1601067578,
"azp": "react-admin",
"colony_admin_sections": "device_v3,wifi_service_v3,captive_portal_v3,site,probe,dns_service,company,SignalTest",
"colony_available_products": "Sitehealth Failover,SecureBlock,Sitehealth Primary,Cloudfi,SignalTest",
"colony_role": "api_user",
"email": "mark@********.com",
"email_verified": true,
"exp": 1601068478,
"family_name": "***",
"given_name": "Mark",
"iat": 1601067578,
"iss": "https://sso.********.com/auth/realms/colony_internal",
"jti": "2f590383-b4f3-4353-8ca3-689da65e8bd0",
"name": "Mark ********",
"nbf": 0,
"nonce": "809a8adb-5b20-4326-8ecc-92c1190834ed",
"preferred_username": "mark",
"scope": "openid profile email",
"session_state": "28088320-d761-4f2a-8a5a-d138f9e0c47a",
"sub": "3f1af098-a974-4dac-af84-6262e506b330",
"typ": "Bearer",
"realm_access": {
"roles": ["viewer", "editor", "offline_access", "admin", "uma_authorization", "user"]
},
"resource_access": {
"account": {
"roles": ["manage-account", "manage-account-links", "view-profile"]
}
}
}
}
}
I'm not sure why it's trying to read a location header or what that's for?
if I hardcode it to use http://localhost:3000
as the location it gets past this part just fine, but I then get a different 400 error:
Body: {
"error": "unauthorized_client",
"error_description": "Client secret not provided in request"
}
I normally pass a secret to keycloak, but that doesn't seem to be an option with this module?
I'm having an issue with cookies and CSP violations with Chrome Version 87.0, Keycloak 11.
Running the same tests in the election
browser they work.
They also work when I set these flags to disabled in Chrome
or Chrome Edge
:
chrome://flags/#same-site-by-default-cookies
chrome://flags/#cookies-without-same-site-must-be-secure
I don't think its an issue with this plugin, just looking for advice if anyone noticed it and how they solved it.
When trying to login with kcFakeLogin, cypress just gets infinitely stuck on page loading.
my users/user.json
fixture:
{
"username": "mark@*****.com",
"password": "*****",
"fakeLogin": {
"access_token": "*****",
"refreshToken": "*****",
"id_token": "*****",
"account": {}
}
}
I've tripple checked the tokens and info above are correct (copied from a real login).
my test:
describe('Keycloak', () => {
it('Keycloak loads', () => {
cy.kcFakeLogin('user');
});
});
initConfig:
{
flow: 'implicit',
onLoad: 'check-sso',
checkLoginIframe: false,
}
(I have tried replacing this with the one from your docs, but that didn't work either).
cypress.json
{
"baseUrl": "http://localhost:3000",
"env": {
"auth_base_url": "https://sso.****.com/auth",
"auth_realm": "****",
"auth_client_id": "react-admin",
"auth_client_secret": "*****"
}
}
my normal keycloak.json looks like this:
{
"auth-server-url": "https://sso.*****.com/auth",
"confidential-port": 0,
"credentials": { "secret": "*****" },
"realm": "rogers",
"resource": "react-admin",
"ssl-required": "external"
}
I'm not sure if there's anything special here that this npm module isn't built to handle?
Visiting localhost:3000 of course works just fine in the browser.
I've been trying to get this working for 5 hours today with no luck.
Hello, feeling stuck and wondering if anyone has clues. Here is my setup, from what I can tell it's pretty standard.
Front end is Create React App. I'm using this library to handle login and watch auth state:
https://www.npmjs.com/package/@react-keycloak/web
I have created a fixture with user credentials that work when I log in manually.
I call cy.kcLogin('me')
but my app never makes it to a private route, it just bounces back to /login
If I run the following in a cypress test: cy.kcLogin('fixtureUsername').as('tokens')
and use the returned tokens against my API, I get data back from a protected route, so kcLogin is doing what it should, at least it's getting valid tokens.
A teammate figured this had something to do with cookies not being set, thus the application doesn't detect that KC is logged in. I put a bunch of cy.getCookies()
calls in my tests and sure enough there are never any cookies.
So then I tried preserving cookies in before(() => {})
beforeEach(() => {
cy.kcLogout()
cy.kcLogin('me').as('tokens')
Cypress.Cookies.preserveOnce(
'KC_RESTART',
'AUTH_SESSION_ID',
'AUTH_SESSION_LEGACY',
'KEYCLOAK_IDENTITY',
'KEYCLOAK_IDENTITY_LEGACY',
'KEYCLOAK_LOCALE',
'KEYCLOAK_REMEMBER_ME'
)
})
but still no luck. I've also written a test that manually logs in:
it('Logs in via keycloak', () => {
cy.visit('/')
cy.contains('Log In')
cy.get('button').click()
cy.url().should('include', 'auth/realms/court')
cy.url().should('include', 'keycloak')
cy.fixture('users/me.json').then(me => {
cy.get(`input[name='username']`)
.type(me.username)
cy.get(`input[name='password']`)
.type(me.password)
cy.get(`input[name='login']`).click()
cy.location('pathname').should('include', 'authenticate')
cy.location('search').should('include', 'session_code=')
})
})
All of those tests pass, but I'm never sent back to my application, it just remains on a keycloak url at the end, wondering if that's a clue as maybe this is more to do with my setup than with cypress-keycloak-commands
Can provide more code if anyone wants to see anything else!
Here are my init options at this point, I've tried the variations on these:
<KeycloakProvider
authClient={keycloakClient}
LoadingComponent={<Box p={2}><CircularProgress /></Box>}
initOptions={{
enableLogging: true,
checkLoginIframe: false,
silentCheckSsoFallback: false
}}
>
I'm authenticating to a 'public' client, btw, so no client secrets are in play.
Hello,
I am trying to implement the Fake Login for Integration testing
I am using angular 12 and cypress 4.4.1
I am done as described in the tutorial.
import "cypress-keycloak-commands";
in commands.ts and hence there is no error while using the commands in the vscode editor.when i run my e2e test, I get the following error when my cypress tests run
cy.kcFakeLogin is not a function
Could you please help as I am stuck
after kcLogin finishes and its('body')
is logged in Cypress (last step of kcLogin succeeds)
Cypress then navigates to /
and then fails with the following error:
Refused to frame 'https://sso.xxxxx.com/' because an ancestor violates the following Content Security Policy directive: "frame-ancestors 'self'".
After some googling I tried setting "chromeWebSecurity": false,
in cypress.json as recommended.
However doing that causes cypress to redirect to chrome-error://chromewebdata/
which there is a multi-year long discussion about here: cypress-io/cypress#4220
sadly this seems to have never been resolved.
There was 1 recommended solution "Using the Ignore X-Frame headers extension", which I tried, but that did not solve the problem for me.
I feel like I'm going down a rabbit hole for something completely unrelated, as no one else has reported the initial Iframe error on here?
I'm having the exact same error using kcFakeLogin
.
Versions on the frontend:
"keycloak-js": "9.0.3",
"@react-keycloak/web": "^2.1.1",
Keycloak server:
Server Version | 4.8.3.Final
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.