Auth0 unable to get ID token / user metadata - javascript

I am currently working on adding Auth0 to a Vue.js/Node.js application and so far I have figured out how to allow users to register and log in (to /callback) and that seems to be working fine. However, I have manually added (will be automatic later on) some data to the user metadata section. I have the below code as a rule that is turned on. I can’t seem to get access to the data on the Vue.js end of things. What I’d like is to be able to get the user data and user metadata so I can store it in my front end.
Rule code
function (user, context, callback) {
const namespace = 'account_signup_type/';
const namespace2 = 'account_type';
context.idToken[namespace + 'is_new'] = (context.stats.loginsCount === 1);
context.idToken[namespace2] = user.account_type;
context.idToken.user = user;
callback(null, user, context);
}
Code I am trying in my Vue.js front end
getIdTokenClaims(o) {
return this.auth0Client.getIdTokenClaims(o);
}
Currently, this returns undefined

I ended up figuring it out, there was no namespace being created in the id_token which resulted in it not properly passing the data through to the Vue .js app. I added a namespace using a web address format with the domain extension cut off and it now works.

Related

How to store and retrieve private key - dapp

When a button is pressed, I send custom tokens to the user using the code below by signing and sending it from my account. The code works perfectly, however, how do I safely store and retrieve the "private key"? The code below is stored in a plain javascript file.
web3.eth.accounts.signTransaction(rawTransaction, "**MY PRIVATE KEY HERE**")
.then(signedTx => web3.eth.sendSignedTransaction(signedTx.rawTransaction))
.then(req => {
/* The trx was done. Write your actions here. For example, getBalance. */
getTokenBalanceOf(userAddress).then( balance => { console.log(userAddress + " Token Balance: " + balance); });
addCustomTokensToUsersMetaMask();
customTokenTransferCompleted();
return true;
})
I know there are ways like using .secret files, or storing it in environment variables, etc, but I can’t find a good tutorial on how to do it. I’m using regular html and javascript and no backend. If I use a backend to store the private key, how would I call it from within the js file?
Never mind, I figured it out. I created a .secret file, which contains my private key, which I imported into a nodejs file. I pasted the code above into the file, and the code was triggered when my smart contract event (Purchased) was emitted and captured (emitted on the front end, and captured in my nodejs file). And when using events in nodejs, I had to use:
var web3 = new Web3("ws://127.0.0.1:7545");
To connect to ganache with websockets.

How can I make Dialogflow agent greet user if they have used the action before?

I'm using Actions On Google / Dialogflow, and I'm trying to make a function that will greet a user by their name if they've used the action before, and if not, will ask for their name. I have tried to map this to the "Welcome intent" through fulfillment, but whenever I try to run the action on the simulator, I get this error:
Error 206: Webhook Error
Which Initially would make sense if this was mapped to another intent, but I'm wondering if I'm getting this error because you can't have a fulfillment with the welcome intent?
Here's the code I'm using in the inline editor which may be the problem:
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request,response) => {
const agent = new WebhookClient({ request, response });
function welcome(conv) {
if (conv.user.last.seen) {
conv.ask(`Welcome back ${name}!`);
} else {
conv.ask('Welcome to The app! My name is Atlas, could I get your name?');
}}
let intentMap = new Map();
intentMap.set('Welcome Intent', welcome);
agent.handleRequest(intentMap);
How come this isn't working? Do I need to implement user login? Do I need to use a function that would write to a firestore databbase?
Thanks for the help or suggestions!
Let's clear a few things up to start:
You can have fulfillment with your welcome intent.
You do not need user login. Although using Google Sign In for Assistant can certainly be used, it doesn't fundamentally change your problem here.
You do not need to use a function that writes to the firestore database. Again, you could use it, but this doesn't change your problems.
The specific reason this isn't working is because the conv parameter in this case contains a Dialogflow WebhookClient rather than an actions-on-google Conversation object.
To get the Conversation object with the parameter you have, you can call conv.getConv(), which will give you an object that has a user parameter. So this may look something like
function welcome(conv) {
let aog = conv.getConv();
if (aog.user.last.seen) {
conv.ask(`Welcome back ${name}!`);
} else {
conv.ask('Welcome to The app! My name is Atlas, could I get your name?');
}}
There are, however, still some issues with this. Most notably, it isn't clear where name will come from. I assume you will get it out of the user store object, but you don't seem to have done this.
For anyone who comes across this question in the future and just wants a straight forward answer without having to search through ambiguous answers / documentation, here is what to do step by step:
note: I ended up using the Google Sign in method, but even if this isn't your goal, i'll post the link to the alternative method.
1) Import the actions on google module. What people / tutorials don't to show is you have to import the library like this (for user login):
const {
dialogflow,
Permission,
SignIn
} = require('actions-on-google')
instead of
const dialogflow = require('actions-on-google')
2) Use this code:
const app = dialogflow({
clientId: '<YOUR CLIENT ID from Actions on Google>',
});
app.intent('Start Signin', conv => {
conv.ask(new SignIn('To get your account details'));
});
app.intent('Get Signin', (conv, params, signin) => {
if (signin.status === 'OK') {
const payload = conv.user.profile.payload;
conv.ask(`Welcome back ${payload.name}. What do you want to do next?`);
} else {
conv.ask(`I won't be able to save your data, but what do you want to do next?`);
}
});
This function will ask the user for a login, and next time you invoke the intent, it will say "Welcome back name", because google automatically saves it.
Here's the link to the alternative method:

How to query firebase for many to many relationship?

It is my first time developing a SPA, and I am not using JS frameworks like React, Vue or Angular. My project just uses the firebase sdk and jquery to access the DOM elements.
In my app, the users can be associated with projects. Since that, I have a user-projects and project-users paths to represent that relationship.
When a user logs in my app I request users/uid to get the user data. After that I have to fetch the projects associated with the user. I will take the ids of the associated projects to finally request the data of each project.
I'm trying to use promises as described here, but I get nothing in the console.
function loadUserProjects() {
// Authenticated user
var user = firebase.auth().currentUser;
// General reference to the real time db
var ref = firebase.database().ref();
// Request the user data
ref.child('users/'+user.uid).on('value').then(function(snapshot) {
var user_data = snapshot.val(); console.log(user_data);
// Global variable to store the id of the selected project
project_selected_key = user_data.project_selected;
// Get the list of associated projects
return ref.child('user-projects/'+user.uid).on('value').then(function(snapshot) {
console.log(snapshot);
return snapshot;
});
}).then(function (projectsSnapshot) {
console.log(projectsSnapshot);
// List associated projects
var project_options = '';
projectsSnapshot.forEach(function (e) {
project_options += '<option value="'+e.key+'">'+e.val()+'</option>';
});
if (! project_options) {
project_options = '<option disabled selected value>- Ningún proyecto -</option>';
}
$('#project_selected').html(project_options);
}, function(error) {
// Something went wrong.
console.error(error);
});
}
I know that I have to use one additional request, because at this point the <select>will be populated with truevalues (the additional request have to query the full data of each project). But I am not getting messages in the console.
Thanks in advance.
After that, I need to define different levels of privilege in each project, and associate a level when a project is assigned to a specific user. Initially I was very excited about the real time, but it seems that firebase is getting more complicated than I supposed.
A Firebase on() listener can respond to multiple events. A promise can only resolve once, that's why it's only available when you use Firebase's once() operation.
return ref.child('user-projects/'+user.uid).once('value');

Authorizing xAPI interactions through Javascript triggers against my LRS

I've constructed a course in Storyline2, and defined several triggers via javascript as xAPI (tincan) activities.
I have an LRS endpoint link and authorization token, but I'm yet to understand where these credentials should be embedded in order for the whole thing to function properly.
I was given this at another message board:
var tincan = new TinCan({url: window.location.href});
Which of these needs to be replaced by one of the above mentioned? I'm guessing another should be added via "+" after "href".
That example code (which I guess you got from the article I wrote here: http://tincanapi.com/share-statements-between-courses/ ) is envisaging that you will launch the Storyline content from something like an LMS. In that case you will enter the endpoint and authorization details in the LMS settings, and the LMS will pass those to Storyline.
See: http://tincanapi.com/share-statements-between-courses/
If you want to put the details directly in the package, see the example code here: http://rusticisoftware.github.io/TinCanJS/
(included below for convenience)
var lrs;
try {
lrs = new TinCan.LRS(
{
endpoint: "https://cloud.scorm.com/tc/public/",
username: "<Test User>",
password: "<Test Password>",
allowFail: false
}
);
}
catch (ex) {
console.log("Failed to setup LRS object: " + ex);
// TODO: do something with error, can't communicate with LRS
}

Ember - get target url of transition

I am creating an error hook in my Ember.js app to redirect you to the auth service if you are not allowed to view certain content (in other words, if the server returns a 401).
It looks like this:
Ember.Route = Ember.Route.extend({
error: function(error, transition){
if (error.status === 401) {
window.location.replace("https://auth.censored.co.za");
}
}
Our auth api works as follows: If you send it a parameter called target (which is a url), it will redirect you back to that target url after you've logged in.
So I want to somehow get the URL of the route the Ember app was trying to transition to.
Then my code will end up something like this
Ember.Route = Ember.Route.extend({
error: function(error, transition){
if (error.status === 401) {
var target = // Your answer here
window.location.replace("https://auth.censored.co.za?target=" + encodeURIComponent(target));
}
}
I came across a need for this too, and resorted to using some internal APIs. In my case, I wanted to reload the whole app so that if you're switching users there's not data left over from the other user. When I reload the app, I want to put the user at the URL they tried to transition to, but for which they had insufficient privileges. After they authenticate (and thus have the bearer token in localstorage) I wanted to use window.location.replace(url) to get a clean copy of the whole app with the user at the URL implied by the Ember Transition object. But the question was, how do I go from a Transition object to a URL? Here is my solution, which uses the generate method which is a private API of the router:
let paramsCount = 0;
let params = {};
let args = [transition.targetName];
// Iterate over route segments
for (let key1 in transition.params) {
if (transition.params.hasOwnProperty(key1)) {
let segment = transition.params[key1];
// Iterate over the params for the route segment.
for (let key2 in segment) {
if (segment.hasOwnProperty(key2)) {
if (segment[key2] != null) {
params[key2] = segment[key2];
paramsCount++;
}
}
}
}
}
if (paramsCount > 0) {
args.push(params);
}
let url = router.generate.apply(router, args);
You'll need to get the router somehow either with a container lookup or some other means. I got it by injecting the -routing service which is documented as an API that might be publically exposed in the future (used by link-to), and which happens to have the router as a property.
While messy, perhaps you might find this helpful.
I was able to use transition.intent.url to accomplish exactly this. I'm not sure if this is private or not -- relevant discussion: https://discuss.emberjs.com/t/getting-url-from-ember-router-transition-for-sso-login/7079/2.
After spending several hours searching for an answer to this question and using the Chrome debugger to try and reverse engineer the Ember 2.5 code, my conclusion is that what you are looking for is not possible at the present time.
For people who don't understand why someone wants to do this, the case arises when authentication (e.g the login page) is separated from the application. This is necessary if there is a requirement not to deliver any content (including the application itself) to the user if the user is not authenticated. In other words, the login page cannot be part of the application because the user is not allowed to access the application before logging in.
PS: I realize this is not a solution to the user's question and probably more suitable as a comment. However, I can't post comments.
Kevins answer is the most correct one, I came to a similar solution. Basically I found how the link-to component was populating the href attribute and used the same sort of code.
In your object inject -routing. I did so with:
'routing': Ember.inject.service('-routing'),
Then the code to generate the URL from the transition is as follows...
let routing = this.get('routing');
let params = Object.values(transition.params).filter(param => {
return Object.values(param).length;
});
let url = routing.generateURL(transition.targetName, params, transition.queryParams);

Categories

Resources