I am trying to setup Cognito UnAuthenticated creds for users coming to my site. However, I am encountering "Error Converting Circular Structure to JSON" after the user id is assigned from Cognito and I am calling the synchronize method on the Sync Manager... please see the code below..
Any help in resolving this is greatly appreciated
// Initialize the Amazon Cognito credentials provider
AWS.config.region = 'us-east-1'; // Region
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-east-1:my-id-pool-id'
});
function getMeACognito() {
AWS.config.credentials.get(function(){
var syncClient = new AWS.CognitoSyncManager();
syncClient.openOrCreateDataset('yaHeardPrefs', function(err, dataset) {
dataset.put('userPrefs', 'samplePrefs', function(err, record){
if(err)
{
console.log('(Sync error)Received error while saving prefs = ' + err);
}
dataset.synchronize({
onSuccess: function(data, newRecords) {
console.log('success');
},
onFailure: function(err){
console.log('Error while sync = ' + err);
},
onConflict: function(err) {
console.log('error / conflict = ' + err);
}
});
});
});
});
}
and the error i am getting is -
aws-sdk-2.3.15.min.js:25 Uncaught TypeError: Converting circular structure to JSON
Note that I do understand what a circular structure conversion error in JSON is based on few google searches... However, I am not in control of the JSON object being created by Cognito library here... and hence, need help in figuring out a path to resolution. If any of you have faced this before and had a solution for this, please reply.
In my application above, for every new Cognito user created at the browser client, I was creating a new dataset and adding some info to it.
I had also setup Cognito to trigger a Lambda function for user creates.
Hence, during new user creations, Cognito was triggering the Lambda function and was synchronously waiting for the function to return successfully before marking the user dataset update operation as "complete" / "successful".
Within the Lambda function, I was also trying to update the same dataset for the user that was created at the browser with some additional information. This seems to have triggered a update back to the Cognito browser client. Afterall the prime functionality of Cognito is to keep its various clients at sync as user's info changes.
As stated in the SO answer here, this went away when I stopped trying to update the same dataset at client and the lambda function at the same time.
Related
I am implementing a Network Test for my Web-application using OpenTok's js library.
To do that, I create a publisher, connect to session, then make a subscriber connect to the publisher's stream.
The Test is working on other browsers (I have tested Chrome and Internet Explorer) but on Firefox version 57.0.1 I get an error - 'The stream was unable to connect due to a network error. Make sure you have a stable network connection and that it isn't blocked by a firewall.'
Make sure when you create the OpenTok Session you are using a 'routed' Session, not a 'relayed' one. Also make sure you are passing the 'testNetwork' property to the subscribe method. Here is a working sample:
// Sample code
var session = OT.initSession(APIKEY, SESSIONID);
session.connect(TOKEN, function(err) {
if (err) {
alert(err.message);
return;
}
var publisher = session.publish();
publisher.on('streamCreated', function(event) {
session.subscribe(event.stream, null, {
testNetwork: true
}, function(err) {
if (err) alert(err.message);
});
});
});
https://jsbin.com/quruzac/edit
The website that I'm working on uses Firebase authentication and different users that login have different permissions as to which pages they can visit.
The way signing in is setup is similar to this post:
User Logins in with two parameters - "id" and "email"
Server uses these to create a custom "uid", then uses the Firebase Admin SDK to create a custom token that is sent back to the client.
The client logs in with the Javascript Firebase SDK - firebase.auth().signInWithCustomToken()
Now that the user is logged in, they can click different pages - i.e. '/foo', '/bar'
The issue I'm running into is that when they visit new pages, I'm trying to pass the token from the client back to the server (almost identical to how its done in this Firebase Doc ), verify the token & check if it has permission to view the webpage.
I'm trying to figure out the best (& most secure) way to do this. I've considered the following option:
Construct a URL with the token, but I've heard this isn't good practice because the token is getting exposed and session hijacking becomes a lot easier.
I've been trying to pass the token in the request header, but from my understanding you can't add headers when the user clicks on a link to a different page (or if its redirected in javascript). The same issue applies to using POST.
What can I do to securely pass this information to the server and check permissions when a user clicks on a link to a different page?
You can get the accessToken (idToken) on client side by:
var accessToken = null;
firebase.auth().currentUser
.getIdToken()
.then(function (token) {
accessToken = token;
});
and pass it in your request headers:
request.headers['Authorization'] = 'Bearer ' + accessToken;
and on your server side get the token with your prefered method and authenticate the request with Firebase Admin SDK, like (Node.js):
firebaseAdmin.auth()
.verifyIdToken(accessToken)
.then(decodedIdToken => {
return firebaseAdmin.auth().getUser(decodedIdToken.uid);
})
.then(user => {
// Do whatever you want with the user.
});
Nowadays, it looks like we're meant to use httpsCallable() client-side to get an object pre-authorized to talk to your endpoint.
eg:
// # ./functions/index.js
exports.yourFunc = functions.https.onCall((data, context) => {
// Checking that the user is authenticated.
if (!context.auth) {
// Throwing an HttpsError so that the client gets the error details.
throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' +
'while authenticated.');
}
// ... rest of your method
});
// ./src/models/addMessage.js
const firebase = require("firebase");
require("firebase/functions");
firebase.initializeApp({
apiKey: '### FIREBASE API KEY ###',
authDomain: '### FIREBASE AUTH DOMAIN ###',
projectId: '### CLOUD FUNCTIONS PROJECT ID ###'
databaseURL: 'https://### YOUR DATABASE NAME ###.firebaseio.com',
});
var functions = firebase.functions();
// This is the new code:
var yourFunc = firebase.functions().httpsCallable('yourFunc');
yourFunc({foo: bar}).then(function(result) {
// ...
});
From firebase documentation
I have written an adapter procedure in MFP V8.0. This procedure is secured bu a security check. I want to check that user is already logged-in before calling this adapter procedure:
Procedure is mapped to scope as below:
<procedure name="searchData" scope="restrictedResource"/>
Security Check is defined as below:
<securityCheckDefinition name="UserValidationSecurityCheck" class="com.sample.UserValidationSecurityCheck">
I have done the the Scope Element mapping the server also.
I have written below method which calls the adapter method:
function callAdapterProcedure(invocationData){
var procedureName = invocationData.procedure;
var successHandler = invocationData.successHandler;
var failureHandler = invocationData.failureHandler;
var parameters = invocationData.parameters;
var isuserLoggedIn = checkForLoggedInUser();
alert('is logged in' + isuserLoggedIn);
if(isuserLoggedIn){
var dataRequest = new WLResourceRequest(getAdapterPath(procedureName), WLResourceRequest.GET);
dataRequest.setQueryParameter("params", [JSON.stringify(parameters)]);
dataRequest.send().then(successHandler,failureHandler);
}else{
hideProgressBar();
showAlert(Messages.ALERT_SESSION_TIME_OUT);
logoutWithoutConfirmation();
openLogin();
}
}
Below is the implementation of checkForLoggedInUser() method:
function checkForLoggedInUser(){
var userAlreadyLoggedIn = undefined;//WL.Client.isUserAuthenticated(mrmGlobal.realms.authenticationRealm,null);
WLAuthorizationManager.obtainAccessToken("restrictedResource").then(
function (accessToken) {
alert("obtainAccessToken onSuccess");
userAlreadyLoggedIn = true;
},
function (response) {
alert("obtainAccessToken onFailure: " + JSON.stringify(response));
userAlreadyLoggedIn = false;
});
return userAlreadyLoggedIn;
}
I know that WLAuthorizationManager.obtainAccessToken sends the asynchronous call to the server that's why userAlreadyLoggedIn is always coming as undefined. Is there any way through which I can check that the user session is not timed out before making the adapter call? Basically I want to implement something like WL.Client.isUserAuthenticated (which was there in earlier versions).
--Update--
Plus I have observed one more thing that the handlers method of WLAuthorizationManager.obtainAccessToken are also not getting called.
From your code:
WLAuthorizationManager.obtainAccessToken("restrictedResource").then(
function (accessToken) {
alert("obtainAccessToken onSuccess");
userAlreadyLoggedIn = true;
},
function (response) {
alert("obtainAccessToken onFailure: " + JSON.stringify(response));
userAlreadyLoggedIn = false;
});
It is a common misconception to think that obtainAccessToken's onFailure means the user is not logged in. But that's not exactly how it works.
When you call obtainAccessToken, there are 3 possible outcomes:
Success: The user is logged in, and obtainAccessToken onSuccess is called (along with the challenge handler's success method).
Challenge: The user is not logged in, the security check sent a challenge to the client. This challenge will be received by your challenge handler. obtain will remain on hold until you answer the challenge. This is probably what happens in your case, this would not explain why none of the obtain's handlers are being called.
Failure: Something went wrong during the authentication. It could be that the server is down, networking issue, the scope does not exist, or the user is blocked, etc. In this case, obtainAccessToken's onFailure will be called.
There currently is no API to check if a scope is granted without triggering a challenge. I have opened an internal feature request, feel free to submit your own (https://www.ibm.com/developerworks/rfe ).
In the meantime you could add your own internal boolean flag, that you set to true whenever you login and false whenever you logout.
I have a working oauth2 authentication process where I get an access token (eg from facebook) using ember simple auth, send it to the back end which calls fb.me() and then uses JWT to create a token. This token is then sent back to the ember app, which then has to send it with every server request, include those requests made by ember-data.
I also need to have this token available after a browser reload.
I have tried many options, where I set a property 'authToken' on the session - I believe that this uses local storage to persist the authenticated session.
But I always seem to have trouble with coordinating the retrieval of this token - either I don't have access to the session, or the token is no longer on the session, or I can't change the ember data headers.
Does anyone have a working simple example of how this can be done - I think it should be easy, but I'm obviously missing something!
Thanks.
Update
The only thing I've been able to get working is to use torii as shown below, but the session content is still lost on refresh - I can see its still authenticated, but its lost the token I set here. So I'm still looking for a real solution.
authenticateWithGooglePlus: function () {
var self = this;
this.get('session').authenticate('simple-auth-authenticator:torii', 'google-oauth2')
.then(function () {
resolveCodeToToken(self.get('session'), self);
});
}
resolveCodeToToken gets the bearer token from the server, sets it on the session and then transitions to the protected page:
function resolveCodeToToken(session, route) {
var authCode = session.content.authorizationCode;
var type = session.content.provider.split('-')[0];
$.ajax({
url: 'http://localhost:4200/api/1/user/auth/' + type,
data: {authCode: authCode}
}).done(function (response) {
// todo handle invalid cases - where user is denied access eg user is disabled
session.set('authToken', response.token);
route.transitionTo('activity', moment().format('DDMMYYYY'));
});
}
And I have a custom authorizer for putting the token (stored in the session) on every request:
import Base from 'simple-auth/authorizers/base';
export default Base.extend({
authorize: function(jqXHR, requestOptions) {
var accessToken = this.get('session.content.authToken');
if (this.get('session.isAuthenticated') && !Ember.isEmpty(accessToken)) {
jqXHR.setRequestHeader('Authorization', accessToken);
}
}
});
I'm not sure why this.get('session.content.authToken') would be undefined after a refresh, I thought by default the session was persisted in local storage. The fact that it is authenticated is persisted, but thats useless without the token since the server will reject calls to protected endpoints.
You'd want to implement your own custom authenticator that first gets a token from Facebook and then sends that to your own server to exchange it for a token for your app. Once you have that you get authorization of ember-data requests as well as session persistence etc. for free.
Have a look at this example: https://github.com/simplabs/ember-simple-auth/blob/master/examples/7-multiple-external-providers.html
I've done some things using firebase (so cool).
I'm doing the custom login, I've generated a AUTH_TOKEN (using nodejs).
My question is if I need to pass in all my page that I wanna to protect the code below?
Peace,
Tulio Cruz
var dataRef = new Firebase("https://example.firebaseio.com");
// Log me in.
dataRef.auth(AUTH_TOKEN, function(error, result) {
if(error) {
console.log("Login Failed!", error);
} else {
console.log('Authenticated successfully with payload:', result.auth);
console.log('Auth expires at:', new Date(result.expires * 1000));
}
});
I'm not sure I fully understand your question. If you want to know if you need to call auth every time a page is loaded -- yes you do. When using custom login with the low-level auth() api call, we don't do any session management for you.
You only need to call auth() once per page load though -- not once for each Firebase reference.