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?
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 have a scenario where I want to start running a test on chrome and at specific point I want my test to open different browser (firefox) and to do the same steps as in chrome then go back to chrome again and verify a change in ui. Is there anyway to do this using testcafe?
I am glad I asked.
In order to test if a login in another browser triggers a logout in the current browser, there is no need to run a different browser.
You can send the according login command from your test code.
node.js builtin standard http library is sufficient for that task. The official documentation has a specific section on http requests: https://nodejs.org/en/knowledge/HTTP/clients/how-to-create-a-HTTP-request/
I personally prefer the fetch API as available in the browser. node-fetch provides this API in node.
so your test code could look a little like this:
import 'node-fetch';
import { URLSearchParams } from 'url';
// we assume we get page state and interaction from this seperate module
import { loginAction, getIsLogged } from './page-actions';
fixture `login logut`
.page `http://your.app/`;
test('User is logged out if logged in somewhere else', async t => {
// perform the login actions to login as "username"
await loginAction(t, 'yourUsername', 'yourPassword');
await simulateLoginFromSomewhereElse('yourUsername', 'yourPassword');
await t.expect(getIsLoggedIn(t)).eql(false);
});
async function simulateLoginFromSomewhereElse(username, password) {
// build the (form) data to be sent to the server
const params = new URLSearchParams();
params.append('username', 'yourUsername');
params.append('password', 'yourPassword');
await fetch(`http://your.app/login`, { method: 'POST', body: params });
}
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.
When I try to login emodal.com (I assume it uses basic authentication because it just requires a user/pass) on the browser it works fine and lets me go to a certain page and lets me through. However when I try to go in the page that I want and authenticate programmatically (using request or request-promise) it gets denied because of "invalid credentials". It seems like I need to login manually through a browser or something by clicking the login button and THEN i would be able to go to the private protected page that I want (why doesn't it work programmatically whereas the browser (google chrome) works? Is it going through a second step in the authentication process that I am not aware of?)
Here I provided 3 screenshots of how the devtools console looks when I log in (it makes a request to ValidateWharfageUser, then Login, then GetStatus as shown, then I guess thats where it denies me programmatically).
import dotenv = require('dotenv');
dotenv.config({ path: '../logins.env' });
import rp = require('request-promise');
const jsonUrl = `http://availability.emodal.com/ImportAvailability/GetContainerInfoList?sgrdModel=%7B%22searchtext%22:%22%22,%22page%22:1,%22pageSize%22:280,%22sortBy%22:%221%22,%22sortDirection%22:%22asc%22,%22sortColumns%22:%22%22%7D`;
const authOpts = {
uri: jsonUrl,
auth: {
user: process.env.EMODAL_id,
pass: process.env.EMODAL_pw,
sendImmediately: false
},
method: 'get'
}
rp(authOpts)
.then(resp => {
console.log(resp);
}).catch(err => { throw Error(err)});
The 3 screenshots:
http://i.imgur.com/hjThLt1.png
http://i.imgur.com/0uPAMMs.png
http://i.imgur.com/xBF2DAV.png
I am studying the client-oauth2 npm package. The code sample from the link in the preceding sentence includes the word user. What does user refer to? Is user a built in type? Or does the developer need to create their own user model class? If so, please give a good example of how to create and integrate a user model class. Any links to documentation about user or code samples for user for this package would also be greatly appreciated.
Here is a code snipped from the link above which includes the word user:
app.get('/auth/github/callback', function (req, res) {
githubAuth.code.getToken(req.url)
.then(function (user) {
console.log(user) //=> { accessToken: '...', tokenType: 'bearer', ... }
// Refresh the current users access token.
user.refresh().then(function (updatedUser) {
console.log(updatedUser === user) //=> true
})
// Sign API requests on behalf of the current user.
user.sign({
method: 'get',
url: 'http://example.com'
})
// We should store the token into a database.
return res.send(user.accessToken)
})
}
The following methods and properties seem to be required of a user object:
user.refresh()
user.sign({method: 'get',
url: 'http://example.com'})
user.accessToken
It seems obvious that user.accessToken stores the user's OAuth2 access token in memory. But what specifically do the refresh() and sign(...) methods do? And what code should be used to implement them, if they are not built-in types?