How To Reuse Token From FireBase - javascript

I am implementing Firebase Web Notification using Firebase.
The whole process is:
There are two files: a) generate-token.js b) firebase-messaging.sw.js
Permission to get access token( By calling requestPermission).
After clicking Allow, token is generated.
An Ajax call is made to backend service to save the token correspond to that browser.
We have separate module for Notification-sender and Notification-Manager to schedule and send notification.
firebase-messaging.sw.js is at root. It is called when notification is called.
There are 2 main methods for this:
initMessaging.setBackgroundMessageHandler(function (payload) {
)}; ( For background handling of message)
and
messaging.onMessage(function(payload) {}); : This method is in generate-token.js for receiving foreground message.
When notification is received, an ajax call is made to api to track notification with actionId=1 and for clicking notification actionId=3.
My questions:
In step 1, once I make an ajax call to save the token, I have to reuse that token in my methods of firebase-messaging.sw.js to hit track api (Track api require token and deviceId)
Currently, I am making device_id using userAgent, which may clash with some other machine. Is there a better way?
How can I reuse my token, as service-worker dont have access to local storage, DOM, cookies,etc.?
My code:
generate-token.js:
firebase.initializeApp(config);
const messaging=firebase.messaging();
var postURL=null;
var gcmId=null;
var id=getUniqueId();
var id1=id.split('.').join("");
if ('serviceWorker' in navigator) {
// Register service worker
navigator.serviceWorker.register('/firebase-messaging-sw.js').then(function (reg) {
console.log("SW registration succeeded. Scope is " + reg.scope);
console.log("Updating service worker" +reg.update());
}).catch(function (err) {
console.error("SW registration failed with error " + err);
});
}
messaging.onMessage(function(payload) {
console.log("OnMessage called app is in foreground");
//tracking notification with actionid=1;
trackNotification(payload.data,1,postURL,gcmId);
});
function requestPermission(url) {
console.log('Requesting permission...');
postURL=url;
var firebaseRefUrl=firebase.database().ref().child(location.host.split('.').join("")+"/" + "url");
firebaseRefUrl.set(url);
messaging.requestPermission()
.then(function () {
console.log('Notification permission granted.');
return messaging.getToken();
})
.then(function(token){
userAction(token,url);
var firebaseRefToken=firebase.database().ref().child(location.host.split('.').join("") + "/" + id1);
firebaseRefToken.set(token);
gcmId=token;
})
.catch(function (err) {
console.log('Unable to get permission for notification.', err);
});
}
function getUniqueId(){
var Sys = {};
var ua = navigator.userAgent.toLowerCase();
return ua;
}
function userAction(token,url) {
try{
console.log("Calling wrapper interface to save gcm_id");
var obj = new Object();
obj.deviceId =getUniqueId();
obj.token=token;
var jsonString= JSON.stringify(obj);
var xhttp = new XMLHttpRequest();
xhttp.open("POST", url+ "/registerGCM", true);
xhttp.setRequestHeader("Content-type", "application/json");
xhttp.send(jsonString);
xhttp.onreadystatechange = function() {
if(xhttp.readyState == XMLHttpRequest.DONE && xhttp.status == 200) {
var jsonDeviceId=JSON.parse(xhttp.responseText);
localStorage.setItem("deviceId",jsonDeviceId.deviceId);
}
}
}catch(error) {
console.log('Error while calling apis.', error);
}}
firebase-messaging.sw.js:
firebase.initializeApp(config);
var click=null;
var url;
var token;
var obj=new Object();
//Initialise firebase messaging
const initMessaging = firebase.messaging();
var id=getUniqueId();
var id1=id.split('.').join("");
var firebaseRefToken=firebase.database().ref().child(location.host.split('.').join("") + "/" + id1);
firebaseRefToken.on('value',function(data){
token=data.val();
});
var firebaseRefUrl=firebase.database().ref().child(location.host.split('.').join("") +"/" + "url");
firebaseRefUrl.on('value',function(data){
url=data.val();
});
//Background push notification handler. It fires up when the browser or web page in which push notification is activated are closed.
initMessaging.setBackgroundMessageHandler(function (payload) {
//console.log("In background");
console.log("Tracking notification when the app is in background");
var gcmId;
var tokenRefCheck=firebase.database().ref().child(location.host.split('.').join("") + "/" + id1);
tokenRefCheck.on('value',function(data){
gcmId=data.val();
});
trackNotification(obj.data,1,url,null);
});
//Displays incoming push notification
self.addEventListener('push', function (event) {
console.log('Push Notification Received.');
var eventData = event.data.text();
obj = JSON.parse(eventData); //Parse the received JSON object.
//printing payload
console.log("PAyload is " + JSON.stringify(obj,2,null));
const title = obj.data.title;
click=obj.data.targetActionData;
const options = {
body: obj.data.body,
icon: obj.data.icon,
click_action:obj.data.targetActionData
};
event.preventDefault();
event.waitUntil(self.registration.showNotification(title, options));
});
//Take action when a user clicks on the received notification.
self.addEventListener('notificationclick', function (event) {
console.log("Notification clicked");
event.notification.close();
event.preventDefault(); // prevent the browser from focusing the Notification's tab
trackNotification(obj.data,3,url,null);
event.waitUntil(
clients.openWindow(click)
);
});
self.addEventListener('notificationclose', function (event) {
console.log("Notification closed");
event.notification.close();
event.preventDefault(); // prevent the browser from focusing the Notification's tab
trackNotification(obj.data,2,url,null);
});
function trackNotification(data,actionId,url,gcmId) {
try{
var obj=new Object();
console.log("Calling track notification api to save the data");
if(actionId===1){
console.log("Tracking for receving notification");
}
if(actionId===2){
console.log("Tracking for closing notification");
}
if(actionId===3){
console.log("Tracking for clicking notification");
}
obj.deviceId =getUniqueId();
obj.campaignId=data.campaignId;
obj.actionTime=new Date();
if(gcmId!=null)
obj.token=gcmId;
else
obj.token=token;
obj.actionId=actionId;
obj.scheduleId=data.scheduleId;
var jsonString= JSON.stringify(obj,2,null);
/*xhttp.open("POST", postURL+ "/trackNotification", true);
xhttp.setRequestHeader("Content-type", "application/json");
xhttp.send(jsonString);*/
console.log("Payload" + jsonString);
fetch(url + "/trackNotification", {
method: 'post',
headers: {
"Content-type": "application/json; charset=UTF-8"
},
body: jsonString
})
.then(function (data) {
})
.catch(function (error) {
console.log('Request failed', error);
});
}catch(error) {
console.log('Error while calling apis.', error);
}}
function getUniqueId(){
var Sys = {};
var ua = navigator.userAgent.toLowerCase();
return ua;
}
I am using Firebase Database, and save the token with useragent as a key, but it will sure collide with some other device.

You can save the data in the service worker cache.
The Service Worker API comes with a Cache interface, that lets you
create stores of responses keyed by request. While this interface was
intended for service workers it is actually exposed on the window, and
can be accessed from anywhere in your scripts. The entry point is
caches.
https://developers.google.com/web/ilt/pwa/caching-files-with-service-worker

Related

Querying the API via JavaScript / CORS (teamup.com calendar)

I am currently trying to figure out how to query the API of a calendar on teamup.com and retrieve data (events in the calendar) from it.
There's a code example on their website: Querying the API via JavaScript / CORS
I tried to make it work in Visual Studio, so I had to install XMLHttpRequest via npm and add a require code line:
var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
// Creates a CORS request in a cross-browser manner
function createCORSRequest(method, url) {
var apiKey = 'API_KEY'; //placeholder for api key
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
// XHR for Chrome/Firefox/Opera/Safari/IE10+.
xhr.open(method, url, true);
xhr.setRequestHeader('Teamup-Token', apiKey);
} else if (typeof XDomainRequest != "undefined") {
// XDomainRequest for IE8/IE9.
xhr = new XDomainRequest();
// XDomainRequest does not support querying HTTPS from HTTP pages
if (window.location.protocol === 'http:') {
url = url.replace('https://', 'http://');
}
if (-1 === ['GET', 'POST'].indexOf(method)) {
alert('XDomainRequest only supports GET and POST methods');
return;
}
if (-1 === url.indexOf('?')) {
url += '?_teamup_token=' + apiKey;
} else {
url += '&_teamup_token=' + apiKey;
}
xhr.open(method, url);
} else {
// CORS not supported.
xhr = null;
}
return xhr;
}
// Sends the actual CORS request.
function makeCorsRequest(url, successCallback, errorCallback) {
var xhr = createCORSRequest('GET', url);
if (!xhr) {
alert('CORS not supported');
return;
}
// Response handlers.
xhr.onload = function (xhr) {
if (xhr.target.status < 400) {
if (successCallback) successCallback(xhr.target);
} else if (errorCallback) {
errorCallback(xhr.target);
}
};
xhr.onerror = function (xhr) {
if (errorCallback) {
errorCallback(xhr.target);
}
};
xhr.send();
}
// Send a GET request for all events in a date range
makeCorsRequest(
'https://api.teamup.com/ks73ad7816e7a61b3a/events?startDate=2015-06-01&endDate=2015-06-05',
function(xhr) {
var data = JSON.parse(xhr.responseText);
alert('Successfully Received: ' + JSON.stringify(data));
},
function(xhr) {
var data = JSON.parse(xhr.responseText);
alert('Request failed with code '+ xhr.status +': ' + JSON.stringify(data));
}
);
When I try to run the program per node I get this terminal output:
PS C:\Users\...\Documents\GitHub\teamup-test> node team-up-test.js
C:\Users\...\Documents\GitHub\teamup-test\team-up-test.js:45
if (xhr.target.status < 400) {
^
TypeError: Cannot read properties of undefined (reading 'target')
at exports.XMLHttpRequest.xhr.onload (C:\Users\...\Documents\GitHub\teamup-test\team-up-test.js:45:17)
at exports.XMLHttpRequest.dispatchEvent (C:\Users\...\Documents\GitHub\teamup-test\node_modules\xmlhttprequest\lib\XMLHttpRequest.js:591:25)
at setState (C:\Users\...\Documents\GitHub\teamup-test\node_modules\xmlhttprequest\lib\XMLHttpRequest.js:614:14)
at IncomingMessage.<anonymous> (C:\Users\...\Documents\GitHub\teamup-test\node_modules\xmlhttprequest\lib\XMLHttpRequest.js:447:13)
at IncomingMessage.emit (node:events:539:35)
at endReadableNT (node:internal/streams/readable:1345:12)
at processTicksAndRejections (node:internal/process/task_queues:83:21)
So it seems like the program cannot read xhr.target.status, but why?
Summarized: I want to fetch calendar event data from my calendar on team-up per JS and display that data on a discord bot.
I am wondering if I even do need CORS since it's only for browsers. Hoping someone could guide me into the right direction please.
The code tutorial here: https://apidocs.teamup.com/#querying-the-api-via-javascript--cors is to be executed in the browser, in the client. I don't think it can be used in the server. Remember, Node.js is a back-end language, it runs on the server, not on the browser.
You can make an API call in Node.js with the code below, but you should study Axios later
const https = require('https');
const options = {
hostname: 'api.teamup.com',
path: '/ks73ad7816e7a61b3a/events?startDate=2015-06-01&endDate=2015-06-05',
headers: {
"Teamup-Token" : "API_KEY"
},
};
https.get(options, (resp) => {
let data = '';
resp.on('data', (receivedDataBuffer) => {
data += receivedDataBuffer;
});
resp.on('end', () => {
let receivedDataAsJSON = JSON.parse(data);
//do what you need with the json
});
}).on("error", (err) => {
console.log("Error: " + err.message);
});

How to Send POST data to Laravel in IE 8+ CORS (with XDomainRequest)

xdr = new XDomainRequest(); // Creates a new XDR object.
xdr.timeout = 3000;//Set the timeout time to 3 second.
xdr.onload = function(){
try {
var res = $.parseJSON(xdr.responseText);
callback(res)
} catch(e) {
console.log("Json format");
//throw 'Invalid JSON: ' + xdr.responseText;
}
};
xdr.onerror = function(){
console.log("can't get data from server")
$('#ServerMessage').show();
};
xdr.ontimeout = function () {
$('#ServerMessage').show();
};
xdr.open(method,this.url); // Creates a cross-domain connection with our target server using GET method.
xdr.send(JSON.stringify(object)); //Send string data to server
I've been able to make a simple POST request, but haven't been able to add POST data to it.

keycloak js automatic token refesh

I have a piece of code working with keycloak and JS.
The code working perfectly except refresh token method have to call externally when the token is expired. How can I refresh token automatically when expired.
var keycloak = Keycloak('keycloak.json');
keycloak.init({ onLoad: 'login-required' })
.success(reloadData)
.error(function(errorData) {
document.getElementById('customers').innerHTML = '<b>Failed to load data. Error: ' + JSON.stringify(errorData) + '</b>';
});
var loadData = function () {
document.getElementById('subject').innerHTML = keycloak.subject;
if (keycloak.idToken) {
document.getElementById('profileType').innerHTML = 'IDToken';
document.getElementById('username').innerHTML = keycloak.idTokenParsed.preferred_username;
document.getElementById('email').innerHTML = keycloak.idTokenParsed.email;
document.getElementById('name').innerHTML = keycloak.idTokenParsed.name;
document.getElementById('givenName').innerHTML = keycloak.idTokenParsed.given_name;
document.getElementById('familyName').innerHTML = keycloak.idTokenParsed.family_name;
} else {
keycloak.loadUserProfile(function() {
document.getElementById('profileType').innerHTML = 'Account Service';
document.getElementById('username').innerHTML = keycloak.profile.username;
document.getElementById('email').innerHTML = keycloak.profile.email;
document.getElementById('name').innerHTML = keycloak.profile.firstName + ' ' + keycloak.profile.lastName;
document.getElementById('givenName').innerHTML = keycloak.profile.firstName;
document.getElementById('familyName').innerHTML = keycloak.profile.lastName;
}, function() {
document.getElementById('profileType').innerHTML = 'Failed to retrieve user details. Please enable claims or account role';
});
}
var url = '/database/customers';
var req = new XMLHttpRequest();
req.open('GET', url, true);
req.setRequestHeader('Accept', 'application/json');
req.setRequestHeader('Authorization', 'Bearer ' + keycloak.token);
req.onreadystatechange = function () {
if (req.readyState == 4) {
if (req.status == 200) {
var users = JSON.parse(req.responseText);
var html = '';
for (var i = 0; i < users.length; i++) {
html += '<p>' + users[i] + '</p>';
}
document.getElementById('customers').innerHTML = html;
console.log('finished loading data');
}
}
}
req.send();
};
var loadFailure = function () {
document.getElementById('customers').innerHTML = '<b>Failed to load data. Check console log</b>';
};
var reloadData = function () {
keycloak.updateToken(10)
.success(loadData)
.error(function() {
document.getElementById('customers').innerHTML = '<b>Failed to load data. User is logged out.</b>';
});
}
I know it's very late, but this answer is just for a future reference.
Don't know if it's just new and this handler was not implemented in 2017 but I use keycloak.onTokenExpired to do this.
Just an example:
keycloak.onTokenExpired = () => {
console.log('token expired', keycloak.token);
keycloak.updateToken(30).success(() => {
console.log('successfully get a new token', keycloak.token);
...
}).error(() => {...});
}
This is only works in Standard flow or Hybrid. There is no possibility to refresh token during implicit flow.
Token (Access Token Lifespan) will be refreshed as long as refreshed token (SSO Session Idle) has not expired. This will work for the duration of SSO Session Max.
Example Token (Access Token Lifespan) will expire in 2 min you can refresh it during 5 min with refreshed token (SSO Session Idle). And it will work maximum during 10 hours SSO Session Max
Access Token Lifespan could be overwritten in Clients (see right nav) Settings tab scroll down to Advanced Settings

Azure Mobile Service and Javascript

Hi there i am stuck and somehow don't find the solution. It seems simple but, well ok. Here it goes. I have a mobile service in Azure and i want to reach that one with javascript. How do i get around the 401 Unauthorized? I tried with the documentation supplied from MS but no luck. This is what i got so far (adding the key to the url is not working of course) what can i add to get it to work?
var client = new WindowsAzure.MobileServiceClient(
"https://cdshop.azure-mobile.net/",
"vGpqzyApJXXXXXXXXblQCWne73"
);
var getJSON = function (url, callback) {
var xhr = new XMLHttpRequest();
xhr.open('get', url, true);
xhr.responseType = 'json';
xhr.onload = function () {
var status = xhr.status;
if (status == 200) {
callback(null, xhr.response);
} else {
callback(status);
}
};
xhr.send();
};
$(function () {
$('#clickme').click(function () {
getJSON('http://cdshop.azure-mobile.net/api/cds/total?key=vGpqzyApJXXXXXXXXblQCWne73', function (err, data) {
if (err != null) {
alert('Something went wrong: ' + err);
} else {
alert('Your Json result is: ' + data.result);
result.innerText = data.result;
}
});
});
});
If you are creating your own HTTP requests, you need to set a request header called X-ZUMO-APPLICATION with your Application Key, e.g. "vGpqzyApJXXXXXXXXblQCWne73", for tables and APIs that are set to "application" or "users". (Assuming you are still using Mobile Services; the newer App Service does not use this X-ZUMO-APPLICATION header.) Tables and APIs set for "users" also need an X-ZUMO-AUTH request header with the user's authentication token.
Alternatively, you can use the MobileServiceClient you created in the first line, and it will do this for you. This page has examples for calling APIs and tables. For your example:
client.invokeApi("cds", {
body: null,
method: "get"
}).done(function (data) {
alert('Your Json result is: ' + data.result);
result.innerText = data.result;
}, function(error) {
alert('Something went wrong: ' + error);
});

backbone.js sync using websocket

I'm trying to use WebSocket for replacing Backbone.sync method.
Then I created three instance of "Sample" model named sample1, sample2 and sample3 and call fetch() method. Each request was successfully sent to the server.
However, when response data coming from the server, every response is set to the sample1. In other word, backbone.js triggered change event and only sample1 instance catch it.
I know there's good library named backbone.WS. However i would like to know why below code didn't work properly. Please give me any comments.
$(document).ready(function() {
var ws;
var url = ws://localhost:8080/application/sample;
Backbone.sync = function(method, model, options) {
var data = JSON.stringify({
'method' : method,
'data' : model.attributes}
);
if(ws == null) {
console.log("Create a new connection to the server.");
ws = new WebSocket(url);
console.log("Binding callback methods.");
ws.onopen = onOpen;
ws.onmessage = onMessage;
ws.onclose = onClose;
ws.onerror = onError;
}
function send(message) {
// Wait until the state of the socket is not ready and send the message when it is...
waitForSocketConnection(ws, function(){
console.log("message sent!!!");
ws.send(message);
});
}
// Make the function wait until the connection is made...
function waitForSocketConnection(socket, callback){
setTimeout(
function () {
if (socket.readyState === 1) {
console.log("Connection is made")
if(callback != null){
callback();
}
return;
} else {
console.log("Waiting for connecting...")
waitForSocketConnection(socket, callback);
}
}, 10); // wait 5 milisecond for the connection...
}
function onOpen(event) {
console.info("Connection established to " + url);
};
function onMessage(event) {
console.info("Message Received!");
var message = JSON.parse(event.data);
console.log("model: " + JSON.stringify(model.attributes));
model.set(message);
};
function onClose(event) {
console.log(event.code);
};
function onError() {
console.warn("There was an error with your websocket.");
}
send(data);
console.log("Request is sent to the server.");
options.success(message);
};
var Sample = Backbone.Model.extend({
defaults : {
id : 0,
name : "default"
}
});
var sample1 = new Sample({id:1});
var sample2 = new Sample({id:2});
var sample3 = new Sample({id:3});
sample1.fetch();
sample2.fetch();
sample3.fetch();
sample1.on("change", function(model) {
console.log("--- onChange method in sample 1");
});
sample2.on("change", function(model) {
console.log("+++ onChange method in sample 2");
});
sample3.on("change", function(model) {
console.log("=== onChange method in sample 3");
});
}

Categories