I am setting up new cypress tests to test some functionalities in Dynamics 365 application. But, I'm left with a browser window with the url https://login.microsoftonline.com/__/ and the text Whoops, there is no test to run.
describe('Initial Cypress Tests', () => {
it('navigate to D365', () => {
cy.visit('https://wipropoc.crm8.dynamics.com')
})
})
Would suggest you to directly do a POST call for getting SSO authentication token and fire cy.visit('https://wipropoc.crm8.dynamics.com') with the obtained token.
Here are the steps to follow from official documentation,
Login when authentication is done on a 3rd party server.
Parse tokens using cy.request().
Manually set tokens on local storage.
Map external hosts and point to local servers.
cy.request('POST', 'https://sso.corp.com/auth', { username: 'foo', password: 'bar' })
.then((response) => {
// pull out the location redirect
const loc = response.headers['Location']
// parse out the token from the url (assuming its in there)
const token = parseOutMyToken(loc)
// do something with the token that your web application expects
// likely the same behavior as what your SSO does under the hood
// assuming it handles query string tokens like this
cy.visit('http://localhost:8080?token=' + token)
// if you don't need to work with the token you can sometimes
// just visit the location header directly
cy.visit(loc)
})
You can read more about this here - https://docs.cypress.io/guides/guides/web-security.html#Form-Submission-Redirects
Real time example - https://xebia.com/blog/how-to-use-azure-ad-single-sign-on-with-cypress/
Related
I have an application that uses Google APIs in some places, and I want to avoid having the user login every time. Currently, I only receive a Google access token in the response, not a refresh token. How can I obtain the refresh token?
This is the function I use to when the user click to login with google:
authenticate() {
const client = google.accounts.oauth2.initTokenClient({
client_id: 'MY_CLIENT_ID',
scope: [
"All_NECESSARY_SCOPES",
].join(" "),
callback: (res) => {
this.accessToken = res.access_token
this.loadClient()
}
})
client.requestAccessToken()
},
It works for getting the access token. And I need the refresh token, Please Help Me :)
Client side JavaScript does not return a refresh token. It would be a security risk.
If you want a refresh token you need to use a server sided language like Node.js
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 use firebase authentication to get a google access token in order to call the youtube API.
I am able to initially get the access token like this:
const provider = firebase.auth.GoogleAuthProvider();
cosnt scopes = []; // ...scopes
scopes.forEach(scope => provider.addScope(scope));
firebase.auth().signInWithPopUp(provider)
.then(userCredentials=> {
const oauthCredentials = userCredentials.credentials;
// using credentials for API calls
axios.get("some-google-api-path", { params: { access_token: oauthCredentials.accessToken } }); // and so on...
});
This works fine until the access token expires.
As far as I can tell, it seems like firebase automatically refreshes the session, but I can find a way to get the new access token.
I tried:
firebase.auth().onAuthStateChange(user => {
// could not find the access token on the user object
});
And since that failed, I tried to do it manually using:
const token = firebase.auth.GoogleAuthProvider.credential(
oauthCredentials.idToken,
oauthCredentials.accessToken
);
const authResult = await firebase.auth().signInWithCredential(token);
The issue is that authResult will only contain the idToken or the accessToken, but not both, depends on what I give the firebase.auth.GoogleAuthProvider.credential function.
Am I missing something?
Is there another/better way to do it?
There are two tokens in play here:
The refresh token, which is only available after the user actively signs in. Since it doesn't change, you can cache this token - which is what the Firebase SDKs actually also do.
The ID token, which is available at any moment from the current user. This token expires in an hour, and is auto-refreshed by the Firebase SDKs.
So if you want to retain access to the refresh token, you will have to store (typically in local storage) yourself when the user first actively signs in.
So apparently firebase doesn't refresh tokens of other providers for you (not event google) according to this (thank you Frank van Puffelen!)
So what I did instead, is authenticate manually to google (since I use react, I used react-google-login), and got all tokens from there.
Then, once the session is initiated/refreshed, I create a firebase session using:
const token = firebase.auth.GoogleAuthProvider.credential(
oauthCredentials.idToken,
oauthCredentials.accessToken
);
const authResult = await firebase.auth().signInWithCredential(token);
I hope that this helps anyone, and I will accept another answer if firebase ever changes this.
I am using Skype Web SDK to get a user's contact list in the following manner.
Skype.initialize({
apiKey: 'a42fcebd-5b43-4b89-a065-74450fb91255',
}, function (api) {
var Application = api.application;
var client = new Application();
client.signInManager.signIn({
username: sip,
password: pwd
})
This works fine when I provide the username(sip) and password. However, when I reload the page, I have to provide the credentials again because the app re-initializes. Is there a way to maintain the user's sessions for a while after the initial login so that the page refreshes wouldn't need ask for credentials again?
I have looked through the samples and docuementation that Microsoft has and couldn't find a way. I've also tried to store the client object in the localStorage after the initialization and sign in, but when I tried to reuse the object from localStorage to get the contact list, it did not work.
http://officedev.github.io/skype-docs/Skype/WebSDK/model/api/interfaces/jcafe.signinmanager.html#signin last example explains that you can store oauth token and use it as unexpired token.
To connect to an existing app's event channel, specify id of that app:
sm.signIn({
username: "user1#company.com",
password: "password1",
id: "273867-234235-45346345634-345"
});
To sign in to Skype for Business Online using OAuth while handling the
logic of retrieving OAuth tokens yourself:
sm.signIn({
client_id: '123-456',
origins: [ 'https://webdir.online.lync.com/AutoDiscover/AutoDiscoverservice.svc/root' ],
cors: true,
get_oauth_token: function(resource) {
// Return a valid unexpired token for the specified resource if you already have one.
// Else, return a promise and resolve it once you have obtained a token.
return 'Bearer eyJ0e...';
}
});
I need to retrieve some data from Google Search Console (Webmaster Tools) using a service account.
So far I've been able to retrieve an access_token for the service account which I need to append to the url of the request. The problem is that I can't find a way to do so, this is the code i'm using:
function retrieveSearchesByQuery(token)
{
gapi.client.webmasters.searchanalytics.query(
{
'access_token': token,
'siteUrl': 'http://www.WEBSITE.com',
'fields': 'responseAggregationType,rows',
'resource': {
'startDate': formatDate(cSDate),
'endDate': formatDate(cEDate),
'dimensions': [
'date'
]
}
})
.then(function(response) {
console.log(response);
})
.then(null, function(err) {
console.log(err);
});
}
This is the url called by the function:
https://content.googleapis.com/webmasters/v3/sites/http%3A%2F%2Fwww.WEBSITE.com/searchAnalytics/query?fields=responseAggregationType%2Crows&alt=json"
Instead it should be something like this:
https://content.googleapis.com/webmasters/v3/sites/http%3A%2F%2Fwww.WEBSITE.com/searchAnalytics/query?fields=responseAggregationType%2Crows&alt=json&access_token=XXX"
The gapi.client.webmasters.searchanalytics.query doesn't recognize 'access_token' as a valid key thus it doesn't append it to the url and that's why I get a 401 Unauthorized as response.
If I use 'key' instead of 'access_token' the parameter gets appended to the url but 'key' is used for OAuth2 authentication so the service account token I pass is not valid.
Does anyone have a solution or a workaround for this?
If your application requests private data, the request must be authorized by an authenticated user who has access to that data. As specified in the documentation of the Search Console API, your application must use OAuth 2.0 to authorize requests. No other authorization protocols are supported.
If you application is correctly configured, when using the Google API, an authenticated request looks exactly like an unauthenticated request. As stated in the documentation, if the application has received an OAuth 2.0 token, the JavaScript client library includes it in the request automatically.
You're mentioning that you have retrieved an access_token, if correctly received, the API client will automatically send this token for you, you don't have to append it yourself.
A very basic workflow to authenticate and once authenticated, send a request would looks like the following code. The Search Console API can use the following scopes: https://www.googleapis.com/auth/webmasters and https://www.googleapis.com/auth/webmasters.readonly.
var clientId = 'YOUR CLIENT ID';
var apiKey = 'YOUR API KEY';
var scopes = 'https://www.googleapis.com/auth/webmasters';
function auth() {
// Set the API key.
gapi.client.setApiKey(apiKey);
// Start the auth process using our client ID & the required scopes.
gapi.auth2.init({
client_id: clientId,
scope: scopes
})
.then(function () {
// We're authenticated, let's go...
// Load the webmasters API, then query the API
gapi.client.load('webmasters', 'v3')
.then(retrieveSearchesByQuery);
});
}
// Load the API client and auth library
gapi.load('client:auth2', auth);
At this point, your retrieveSearchesByQuery function will need to be modified since it doesn't need to get a token by argument anymore in order to pass it in the query. The JavaScript client library should include it in the request automatically.
You can also use the API Explorer to check what parameters are supported for a specific query and check the associated request.
If you need to use an externally generated access token, which should be the case with a Service Account, you need to use the gapi.auth.setToken method to sets the OAuth 2.0 token object yourself for the application:
gapi.auth.setToken(token_Object);