Salesforce - Enhanced domain third party cookie issue - javascript

Anybody facing issue with the new Enhanced domain implementation, I am not able to get the handle to the cookies.
Any help will be much appreciated.
Below is my scenario/steps
salesforce sets the cookie value using an LWC component.
Re-directs the page to OKTA for authentication.
OKTA after authentication re-directs to a visual force page where the JavaScript tried to read the cookie already set in the step 1.
The value reading the while reading the cookie is 'undefined'
It's all working well without Enhanced domain implementation enabled, As Jan 10 2023 is the cutoff date of mandatory implementation of Enhanced Domain on Sandboxes, we are trying to resolve this issue before the cut-off date.
function getCookie(name) {
let cookieString = "; " + document.cookie;
let cookies = cookieString.split("; ");
let currentCookieVal;
cookies.forEach(cookie => {
let currentCookieArr = cookie.split('=__');
if(currentCookieArr.length && currentCookieArr.length === 2) {
if(currentCookieArr[0].includes(name)) {
currentCookieVal = currentCookieArr;
}
}
});
return currentCookieVal;
}
Thanks,
James

Related

How do I delete all cookies immediately after the browser is closed ( Using HTML and JavaScript )

What my site is and it's bare bones
A basic site made of HTML, CSS and Vanilla JavaScript. I am integrating front-end password protection to the site using JavaScript to check the credentials and assign a cookie which marks them as logged-in. It's just a side-project and security of the content isn't very necessary. The target audience also doesn't have the knowledge of adding cookies from the browser or manipulating the system in any way.
Once the user has signed in, they get redirected to the homepage, where the cookie is checked for. If the log-in cookie is present, they page loads, and if it's not present, the user gets redirected to the log-in page with a note asking to sign in. So far so good.
What's going wrong?
Like most web devs, I started testing the site before giving it a green signal, and turns out Chrome does not clear cookies after I close the browser. This is a spoilsport. Then, I tried using the onunload function on all the pages to delete the cookies, but the cookies are getting deleted even before the user reaches the homepage, and as a result, are directed to the homepage. I don't want to use Session Storage as opening the site in another tab does not take the Session Storage to the other tab.
Is there any way I could achieve deleting cookies when the browser is closed?
Since you're doing all this programming on the client-side, not the server-side, a cookie may not be the best approach - cookies are for transferring persistent information between the client and server. Local Storage may be a more appropriate choice, for controllable semi-persistent data stored on the client. Local Storage persists over different tabs on the same site.
A possible approach would be to have the saved data expire a certain amount of time after any page on your site has last been opened. For example, you could have, on every page, a script that runs every minute or five and sets the expiry time to an hour or 10 minutes in the future, or something like that - depends how much fine control you want over when logout occurs after inactivity. The code would look something like this:
// on pageload:
const advanceExpiry = () => {
localStorage.loginExpiry = Date.now() + 1000 * 60 * 10;
};
const loggedIn = localStorage.loginExpiry && localStorage.loginExpiry > Date.now();
if (loggedIn) {
advanceExpiry();
// every few minutes, push login expiry 10 minutes in the future:
setInterval(advanceExpiry, 1000 * 60 * 5);
} else {
// user has not logged in, or login has expired
localStorage.loginExpiry = 0;
// redirect to login page
}
and, on the login page, do localStorage.loginExpiry = Date.now() + 1000 * 60 * 10; followed by a redirect.
Just to point out, validation on the front-end is not remotely secure - but you already know about that and don't think it matters, which is fine.
There isn't a silver bullet readily available for your problem. However, using a Service Worker in conjunction with the Task Scheduling API and some JavaScript, you will reach close.
More info - Task Scheduling
Delete all cookies after an hour
function deleteAllCookies() {
var cookies = document.cookie.split(";");
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i];
var eqPos = cookie.indexOf("=");
var name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie;
document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT";
}
}
setTimeout for 1hour
function myFunction() {
myVar = setTimeout(deleteAllCookies, 3600000);
}
Call myFunction when user login's or when he or she starts the application.

Integrate Salesforce registration page with VanillaJS oidc-client-js, getting the error - No matching state found in storage

Integrate Salesforce registration page with VanillaJS, getting the error - No matching state found in storage
We are redirecting the user to Salesforce registration page when Create Account button is created.
Once the User registers in Salesforce, the user is redirected to our site but we are getting this error. ('No matching state found in storage').
We tried the below solution but still getting the same error.
As I stated in my answer, the oidc client maintains state information
in the local storage so that it can verify that it got the response
back from the intended server. You can mimic this by generating a
secure random string and saving it in localStorage. Do this before
sending a request to your auth server to register a new user.
Reference- Integrate third party login in from my registration page with IdentityServer4 and Angular 6 - 'No matching state found in storage'
Is there a function related to creating registration? How to fix this issue?
Thanks.
Appreciate your help.
After spending days on this issue. Finally found the workaround as registration is not a feature of OIDC.
To overcome this issue, need to follow the Sign In process same as for Sign Up process, created the startSignupMainWindow method same as startSigninMainWindow and passing the signUpFlag:true as shown below in code.
/* This function is written to mimic the oidc library sign in process flow */
function startSignupMainWindow() {
var someState = {
message: window.location.href,
signUpFlag: true
};
mgr.signinRedirect({
state: someState,
useReplaceToNavigate: true
}).then(function() {
log("signinRedirect done");
}).catch(function(err) {
log(err);
});
}
Reading the signUpFlag:true in UserManager.js and swapping the Salesforce Sign In page Url with Sign Up page url and calling the Register function in Code.
UserManager.js(oidc - client - dev - js / src / UserManager.js)
//UserManager Customised Code :
return this.createSigninRequest(args).then(signinRequest => {
Log.debug("UserManager._signinStart: got signin request");
navigatorParams.url = signinRequest.url;
navigatorParams.id = signinRequest.state.id;
if (signinRequest.state._data.signUpFlag) {
register(signinRequest.state._id, signinRequest.state._code_challenge);
} else {
return handle.navigate(navigatorParams);
}
})
The below code is Register function written in code.
/* This function is written to send the code_challenge to salesforce server so that
salesforce server holds the code challenge and used to verify the further requests(token-request)
against the code_challenge it received initially.*/
//Customised register function written outside the library (Inside our App):
function register(_id, code_challenge) {
var date = new Date();
var baseUrl = "SALESFORCE_URL/login/SelfRegister?expid=id";
var expId = "id";
var userPage = encodeURIComponent(window.location.href);
var appDetails = "response_type=code&" +
"client_id=CLIENT_ID" +
"client_secret=CLIENT_SECRET&" +
"redirect_uri=CALLBACK_URL&" +
"state=" + _id + "&code_challenge=" + code_challenge + "&code_challenge_method=S256&response_mode=query";
var encodedapp = encodeURIComponent(appDetails);
var startUrl = "/services/oauth2/authorize/expid?" + encodedapp;
var signUpUrl = baseUrl + "&startURL=" + startUrl;
window.open(signUpUrl, "_self");
};

In TestCafe, Is there a way to fetch the token set by USER ROLE functionality?

Introduction
I'm using TestCafe and there are some redundant steps I'm using which can be easily replaced by making direct API calls to save a lot of time. Also, in my current tests, I'm using UserRole functionality of TestCafe to avoid login in every tests.
What's the problem?
To make API calls, I would need a token. UserRole already saves it in a cookie but I can't find a way to fetch it.
What I did so far?
I did debug test to look for cookies and I see there are a bunch of cookies in the browser but I can't see relevant which can be used as a token.
There is a way for me to get the cookie using this part of the code which I'm able to fetch when I don't use User Role functionality but unsuccessful in using the below with User Role functionality:
const getCookie = ClientFunction((name) => {
const nameEQ = `${name}=`;
const ca = document.cookie.split(';');
for (let i = 0; i < ca.length; i += 1) {
let c = ca[i];
while (c.charAt(0) === ' ') c = c.substring(1, c.length);
if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
}
return null;
});
but I need to know the name of the cookie which I'm not aware of how TestCafe had set it.
Usually, an authentication cookie has the httpOnly property. It means you cannot access such a cookie from the client side. TestCafe repeats the native browser behavior and restricts access to the httpOnly cookie from code inside of the ClientFunction. Also, at present, there is no public API to use httpOnly cookies in test code.
Note that the TestCafe team does not recommended you manually set up cookies. This may cause unstable tests.
The cookie management API was released in TestCafe v1.19.0. This API works in a cross-browser way and allows you to conveniently assign, delete, and receive cookies on a testing page, including httpOnly cookies.
await t.getCookies({
httpOnly: true
});
Read more in the Release notes.

Facebook API - access token for web application

I am making a web app that pulls the latest posts from our Facebook page and processes them.
This is all working fine with a hard-coded access token generated from this page.
The problem is that this token expires, so i am looking for a solution to generate a new token every time the page loads or a non-expiring token - (i have read somewhere that non expiring tokens don't exist anymore).
So of course i did some research, here, here and here.
But non of these examples seem to be working.
Before any complaints of some code that i have tried so far, this is my working example - with an expiring access token:
var Facebook = function () {
this.token = 'MYTOKEN';
this.lastPost = parseInt((new Date().getTime()) / 1000);
this.posts = [];
};
Facebook.prototype.GetPosts = function () {
var self = this;
var deffered = $q.defer();
var url = 'https://graph.facebook.com/fql?q=SELECT created_time, message, attachment FROM stream WHERE created_time < ' + self.lastPost + ' AND source_id = 437526302958567 ORDER BY created_time desc LIMIT 5&?access_token=' + this.token + '';
$http.get(url)
.success(function (response) {
angular.forEach(response.data, function (post) {
self.posts.push(new Post(post.message, post.attachment.media, post.attachment.media[0].src, post.created_time, 'facebook'));
});
self.lastPost = response.data[response.data.length -1].created_time;
deffered.resolve(self.posts);
self.posts = [];
});
return deffered.promise;
};
return Facebook;
Any help / suggestion will be greatly appreciated.
First off, it is important to remember that Facebook has just launched the Version 2 of the Graph API. From April 2014 on, if you have issues with your app, you need to tell us when you created it on Facebook Developers (new apps use the Version 2 by default).
In order manage pages, your app needs to have manage_pages permission. Make sure that the user you want to manage fan pages for has authorized you. If your app uses the Version 2, make sure that Facebook (the Facebook staff) has authorized you to ask users that kind of permission, otherwise your app won't work.
Once you get your token, exchange it for a permanent token (or a token with long expiry date). Make sure you use the token of the fan page, not the token of the user.
If instead you want to read the stream of public fan pages, you need an access token with read_stream permissions. This permission needs to be approved by Facebook (see above) and this specific type of permission takes time to approve, if you're using the Version 2 of the Graph API. If you're using the old API (Version 1), you can still do that without pre-approval on Facebook's side.
The URL to ask for the permission to read the stream is as follows: https://www.facebook.com/dialog/oauth?client_id=$YOUR_APP_ID&redirect_uri=$YOUR_URL&scope=read_stream,manage_pages (i've added manage_pages in this case, you may not need it).
That url will prompt for authorization. Once the user has authorized the app, you'll be recirected to the URL you chose, with a code= variable.
At that point, call this other url:
https://graph.facebook.com/oauth/access_token?client_id={$app_id}&redirect_uri=$someurl&client_secret={$app_secret}&code={$code}
You'll get a response that has the access_token=variable in it. Grab that access token, exchange it for a long one, with the following URL:
https://graph.facebook.com/oauth/access_token?grant_type=fb_exchange_token&client_id={$app_id}&client_secret={$app_secret}&fb_exchange_token={$token_you_have_just_grabbed}
The response will give you a token that lasts for some time. Previously, Facebook had decided to have these "long duration tokens" expire after one month. I have found out, though, that they may have changed their mind: if you put a user token in the debugger, you'll see it never expires.
This is the authorization flow for users who visit with a browser. There's the app authorization flow too. If all you need is a stream from your own Fan page, you want to do the following (with Graph API V.1):
make an HTTP GET request using the following URL:
https://graph.facebook.com/oauth/access_token?type=client_cred&client_id={$app_id}&client_secret={$app_secret}
Use the resulting token to make another HTTP GET call, like so:
https://graph.facebook.com/{$your_page_id}/feed?{$authToken}&limit=10
//ten posts
Decode the json object
You're done.

Can't delete cookies in Angular JS

I'm having lot of troubles deleting a cookie using $cookies
On logout, my code does:
var deferred = $q.defer()
$http.post( REST.logout, {} )
.finally( function() {
// finally callback is triggered both on success and error,
// since I don't really care if the server is dead or whatever
console.log('out!')
console.log( $cookies['persistent'] )
delete $cookies['persistent']
$cookies['persistent'] = undefined
console.log( $cookies['persistent'] )
deferred.resolve()
})
return deferred.promise
And the output is:
out!
"441b5deca5da04cad774a3844b6865dac8a98e91-oi=11"
undefined
However, the cookie don't bother itself to go away...
As stated in this SO question Can't delete cookie with AngularJS's $cookies, I've checked the domain, which in my case are the the same, since my web app runs from domokun.zodiac.lan and the cookie has domain of .zodiac.lan
I can add that it cannot be set again on the server side because I've cut off the communication between the client and the server, in order to test this out.
Any chance that you could see something I'm missing out would be wonderful!
tested against angular 1.2.[2-5]
One more possibility is you may be running into what I was running into. In my case I wanted to delete a cookie that had been created outside my app so it wasn't in the same domain. We intercept customers' logins through a common portal to provide their username/password. This then creates an authentication cookie that can be later read by the app, and the request is then forwarded to the app.
Anyway, the problem was that you have to be specific in defining both the path and domain of the cookie to be removed. Angular was able to read this cookie without specifying a path or domain, I was able to read it with simply:
$cookies.get("MySSOCookie");
But to remove (which I did by just overwriting with undefined when I wanted the user to be re-directed back to the authentication landing screen, such as upon logout or timeout), I had to be precise:
$cookies.put('MySSOCookie', undefined, {domain: '.myCompanyName.com', path: '/'});
Use native javascript , here some functions will help you:
//set cookies that you need
function setCookie(name, value, expires){
document.cookie = name + "=" + escape(value) + "; ";
if(expires){
expires = setExpiration(expires);
document.cookie += "expires=" + expires + "; ";
}
}
//expiration of your cookie
function setExpiration(cookieLife){
var today = new Date();
var expr = new Date(today.getTime() + cookieLife * 24 * 60 * 60 * 1000);
return expr.toGMTString();
}
//get cookie with namecookie...
function getCookie(w){
cName = "";
pCOOKIES = new Array();
pCOOKIES = document.cookie.split('; ');
for(bb = 0; bb < pCOOKIES.length; bb++){
NmeVal = new Array();
NmeVal = pCOOKIES[bb].split('=');
if(NmeVal[0] == w){
cName = unescape(NmeVal[1]);
}
}
return cName;
}
For your problem use:
setCookie(nameyourcookie,'')
I have helped you...
Can you use:
$cookieStore.remove('persistent');
http://docs.angularjs.org/api/ngCookies/service/$cookieStore
A potential problem could be if your cookie is marked as httpOnly. HttpOnly cookies cant be read by any javascript. To see if you can read the cookie, try:
$ document.cookie
in your console. If it returns an empty string despite there being cookies present in the browser, then those cookies might be httpOnly. You could also look for the HTTP check mark in the Resources tab in chrome
To get rid of the httpOnly attribute you could see if the server framework has some option for that. In nodejs/express you can pass a flag like this:
app.use(express.cookieSession({cookie: { httpOnly: false }}));
However, I don't know if that's bad practice, seeing as it seems to be some sort of session cookie we are talking about and should be handled by the server.

Categories