I am attempting to access a google service embedded into my website which uses accounts.google.com for the login.
I'm trying to use the session/origin commands to do this, but it's failing as if I'm doing nothing at all. I use this with success to login to my application (non google login), but google seems to require something more. I have spent a great deal of time browsing for answers with no luck
Code leading up to login:
cy.get('div [class="active carousel-item"]').find('button').first().click()
cy.loginGoogle(Cypress.env("GoogleUsername"),Cypress.env("GooglePassword"))
Login code:
Cypress.Commands.add('loginGoogle', (username, password) => {
const args = { username, password }
cy.session(args, () =>
{
cy.origin('https://accounts.google.com', { args }, ({ username, password }) => {
cy.visit('https://accounts.google.com/')
cy.get('input[type="email"]').type(username)
cy.get('div[id="identifierNext"]').find('button').click()
cy.get('#login-password').type(password)
cy.get('#btn-login').click()
})
cy.visit('/')
cy.url().should('contain', 'mydomain.com')
})
})
Try to use programmatic authentication as it's suggested in the documentation.
Related
I'm currently integrating a frontend with a 3rd party backend that offers sign-in with social media. I'm using the Google JS SDK https://accounts.google.com/gsi/client which works fine with the one-tap login as it returns an ID Token which the backend requires. However, the downside is, if the user doesn't have a Google session, the prompt won't show.
If the user isn't logged in to Google, I've managed to prompt a login form and request a token on successful login, however, it only returns an access token. Is any way to request an ID token?
Example:
google.accounts.id.prompt(async notification => {
if (notification.getNotDisplayedReason() === 'opt_out_or_no_session') {
const tokenClient = google.accounts.oauth2.initTokenClient({
client_id: googleClientId,
scope: 'openid email profile',
})
tokenClient.callback = response => {
// response only has access token and no ID Token
}
tokenClient.requestAccessToken({ prompt: 'consent' })
}
window.addEventListener('load', () => {
google.accounts.id.initialize({
client_id: googleClientId,
callback: (user: CredentialResponse) => {
const { credential: idToken } = user
// I need idToken in the above requestAccessToken too
},
})
})
})
You are initializing two different namespaces in the example you have provided. The first one initializes oauth2 namespace, which starts the authorisation flow. This flow results in the acquisition of an access_token as you've realised.
The second one initializes the id namespace, which is responsible from the authentication flow. This returns an id_token, which is what you need indeed.
To keep using authentication flow beyond the capability of one-tap log in, you can render a Sign-In with Google button using the authentication initialisation. Simple initialise google.account.id.initialize() as you would. Then call one-tap prompt.
google.accounts.id.prompt();
Then in addition to that, you can render the button:
google.accounts.id.renderButton(document.getElementById("g-btn"), {
type: "standard",
logo_alignment: "left"
});
And
<div class="google-button" id="g-btn"></div>
Regardless of how the user decides to sign-in, it'll lead to the same callback method you've defined in the initialize() call.
I am trying to visit /auth path and login in with cypress using the following code:
Cypress.Commands.add('login', (email, password) => {
cy.get('.auth').find('.login').should(($login) => {
expect($login).to.contain('auth.welcome')
})
cy.get('[name="email"]').type(email);
cy.get('[name="password"]').type(password);
cy.get('button.login')
.click();
})
But Cypress fails with the following error message:
AssertionError: Timed out retrying: Expected to find element: `.auth`, but never found it.
Sometimes the code works and sometimes it fails.
my login page url is (http://localhost:3000/) or (http://localhost:3000/auth)
this command will wait the element:
cy.get('.auth').should('be.visible');
Add this command before interacting with it.
Custom commands are very good utilities, but encapsulating multiple UI actions inside, make the overall test execution very slow and flaky especially for login actions.
It is not wrong at all your approach, however I would suggest doing it via API calls, so in result you will have a stable and robust login function.
Cypress.Commands.add('login', (username, password) => {
return cy
.request('POST', `${<YOUR_API_URL>}/auth`, {
username,
password,
})
.its('body.token')
.then(token => {
cy.visit(`/`, {
onBeforeLoad(win) {
win.sessionStorage.setItem('token', token);
},
});
});
});
I am building a react native application and am using Firebase, more specifically firestore, in order to manage my data. My current objective is to implement an auto login feature on my app, where if the user exits the app, I want them to stay signed in, unless they manually hit the Sign Out button before exiting the app. Here is my current process of doing this:
When the user logs into the app, I sign them in by:
firebase.auth().signInWithEmailAndPassword(email, password).
I then get their idToken by:
let authIdToken = "";
firebase
.auth()
.currentUser.getIdToken(true)
.then(function (idToken) {
authIdToken = idToken
})
.catch(function (error) {
console.log(error)
});
I then want to save this token into the phone, so when the user opens the app again, I can fetch this token and check its validity. If it is valid, then I can log the user in using their idToken. In react native, I can do this by doing:
AsyncStorage.setItem(
"userData",
JSON.stringify({
token: token,
})
);
Now when the app loads up:
const startScreen = props => {
useEffect(() => {
const tryLogin = async () => {
const userData = await AsyncStorage.getItem("userData");
const transformedData = JSON.parse(userData);
const { token } = transformedData;
await firebase
.auth()
.verifyIdToken(token, true)
.then((payload) => {
console.log(true)
})
.catch((error) => {
if (error.code == "auth/id-token-revoked") {
// Token has been revoked. Inform the user to reauthenticate or signOut() the user.
console.log("revoked")
} else {
console.log("error")
}
});
};
tryLogin();
}, []);
The Issue: When I try to verify the token this way, I am met with the following error: firebase.auth().verifyIdToken is not a function.
I read through the documentation and am unsure of how else to verify this token using JS. How do I verify it? Let me know if my verification process is incorrect and how it should be done. I am new to using firestore and doing authentication in general and hope to learn how to do it the right way.
Another helpful note: This is how I am configuring my firestore: !firebase.apps.length ? firebase.initializeApp(firebaseConfig) : {};
Thanks!
I then want to save this token into the phone, so when the user opens the app again, I can fetch this token and check its validity.
This is completely unnecessary. Firebase Auth with persist the signed in user, and automatically refresh the token without you having to do anything. All you need to do is listen to when updates to the token are made available, and act on the new token as needed. You can establish an ID token listener using onIdTokenChanged as shown in the linked API documentation:
firebase.auth().onIdTokenChanged(function(user) {
if (user) {
// User is signed in or token was refreshed.
}
});
Once you have this token, you know that the user is successfully signed in. There is nothing left to do. There is no need to use it to sign in.
Also, you can't verify the token on the frontend. The verifyIdToken method you're looking at is for the Admin SDK only, which only runs on the backend. The idea is that you get the token on the fronend, then pass it to the backend as described in the documentation for the Admin SDK. The backend uses this to securely determine if the user on the frontend is who they say they are.
Since you didn't say if you have a backend or not, dealing with this token might not be necessary at all. If you just want to know when the user is signed in (even if they are just returning to the page after being away, then you can skip everything above and just use an auth state observer. Again, Firebase Auth persists information about the user so you don't have to sign them in again. The observer will tell you when the automatic sign-in is complete, or if they are not signed in at all.
I’m trying to create a function to get a login token from Auth0 for a user for so I don’t have to use the login test before every test scenario (which isn’t working anyway), but rather I want to have a stored token and use that to authenticate the user so I can test the application.
I’m not a developer (or even a developer in Test). I’m a QA who is trying to learn enough Javascript in order to use Cypress to create test scenarios for our new internal risk assessment application.
We have a list of users for our new app which will all be verified through Auth0. All the users are internal to our company and are based on our emails which are linked to Microsoft accounts.
Below is my login test that presses the login button, which is then redirected to Auth0 and then enters my email address to verify the login. This is successful except for the fact that it doesn’t actually load the application.
```
describe('My Login Test', function (){
it('Visit Risk App Landing Page', function (){
const typedText = 'adam.allford#landmark.co.uk'
cy.visit('https://bvt-riskassessment.lmkcloud.net')
cy.get('button').click()
cy.get('input.auth0-lock-input').first()
.type(typedText)
.should('have.value', typedText)
cy.get('button').click()
cy.url().should('eq','http://bvt-riskassessment.lmkcloud.net/workflow')
})
})
```
I had a reply on a Gitter forum from someone who had a similar issue and used what is displayed below (or similar) to try and login. I edited it with relevant details for what I need and put this in the command.js with a loginuser.json (containing username and password) in the shown loacation, and then included the beforeEach in a test scenario.
```
Cypress.Commands.add('login', (userType, options = {}) =>
{cy.readFile(`cypress/fixtures/loginUser.json`).then((json) => {
const { email, password } = json
const dataToSend = {
email,
password,
}
cy.request({
url: `https://lmcorp.eu.auth0.com/userinfo`,
method: 'POST',
body: dataToSend,
form: true
}).then((response) => {
const { status, body } = response
expect(status).to.eq(200)
expect(body).to.have.property('success', 1)
cy.visit(url)
})
})
//and use it like :
beforeEach(() => { login('url') })
```
… and then included the beforeEach in a test scenario.
```
describe('My First Test', function (){
it('Visit Risk App Landing Page', function (){
beforeEach(() => { login('https://lmcorp.eu.auth0.com/')})
cy.visit('http://localhost:3000/workflow')
cy.contains('Site Solutions Combined Assessments')
cy.contains('To Do')
cy.contains('Assessing')
cy.contains('Reviewing')
cy.contains('Done')
cy.get('button').click()
cy.contains('Assessments')
cy.contains('Site Solutions Combined')
cy.contains('Flood')
cy.contains('Whatever Next')
})
})
```
But I get the following message on the command console.
![alt]https://i.imgur.com/cJljZzm.png
I’m completely stuck and don’t know where to go from here. My question is: I want to create a feature that will call our Auth0 url and get a login authentication token, which can be used to allow access the application for every test scenario. Can I change what I have here to make that work, or does anyone have any suggestions on how to create a new feature to get an Auth0 token?
i'm building the app using expo / react native and the firebase javascript web sdk. Could someone take a look at the code below and let me know whether they can figure out why my code isn't working? The code works fine when I'm using expo development mode, and the user profile gets set as expected. However in it's published state it is just not working. The new user is created and logged in, however it doesn't create the user profile.
firebase.auth().signInWithEmailAndPassword(email, password)
.then(user => loginUserSuccess(dispatch, user))
.catch(() => {
firebase.auth().createUserWithEmailAndPassword(email, password)
.then((newUser) => {
var userRef = firebase.firestore().collection("users").doc(newUser.uid);
userRef.set({name: name, email: email, company: company, number: number, user: newUser.uid, adminEmail: '' })
.then(function (){
dispatch({ type: LOGIN_USER_SUCCESS, payload: newUser });
})
.catch(() => loginUserFail(dispatch)
);
})
.catch(() => loginUserFail(dispatch));
I've tried lots of different methods but keep having the same problem. According to the docs, the createUserWithEmailAndPassword method returns the User credentials. I've confirmed this with a debug statement and checked that I am accessing the uid property of said object.
Thanks