I'm trying to build a bot that sends proactive user recommendations regularly. They look similar to this one:
I have it all working in terms of user data coming from the backend, but I also want to add some additional things coming from the Graph API - one of which is the profile picture.
I've setup an Azure Bot Channel, got the Graph auth sample running, but I still can't figure how to mix the proactive messages with the OAuthPrompt dialog.
If I make the user sign in upon app registration, can I reliably get the graph token and use it in my proactive message handler? Note that these messages are going to be sent on a weekly basis. I'm afraid that the token is going to expire.
Has anyone done something similar?
If you just need the bot to make a call to Graph and retrieve user data, you can use Application Permissions to do this without having the user log in. First, you will need to enable the permissions in Azure Active Directory>App registrations>API permissions. The particular ones you need here is User.Read.All (or User.ReadWrite.All if you might want it to have write access for other use cases). There are also separate permissions for Group and Contact if you need that.
For the bot, you first need to get the token. There's a whole reference article here (which includes the app permissions as described above). The client ID and secret are the values for your application. So in javascript I do something like
var identityUrl = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
var formData = `client_id=${clientId}&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_secret=${clientSecret}&grant_type=client_credentials`
try {
var idResponse = await request({
url: identityUrl,
method: 'POST',
headers: {'Content-Type': 'application/x-www-urlencoded;charset=UTF-8'},
form: formData
});
var token = JSON.parse(idResponse).access_token;
} catch (err) {
await step.context.sendActivity(`Sorry, something went wrong. Please try again later.`);
console.log(err.message);
return step.endDialog();
}
I've got a lot going on where I'm making an actual call to graph, but my http call looks like this:
var userResponse = await request({
url: usersUrl + queryString,
method: 'GET',
headers: {'Authorization':`Bearer ${token}`, 'ConsistencyLevel':'eventual'}
});
userResponse = JSON.parse(userResponse);
Now in your case you're calling the Get Photo endpoint, which I haven't done, but should be basically the same as the above. Here is a link for the Get photo documentation. So now, you bot should be able to authenticate and grab the picture before sending the proactive message, without any need for the user to ever give any credentials.
Related
I'm not sure how to properly do JWT authentication on the front end, I didn't have almost any problems on the back end though.
with Javascript I didn't get too far past this snippet
as I had to redo stuff many times and it didn't work anyway
const submit = async (e) => {
e.preventDefault();
await axios('http://localhost:8080/api/login', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
credentials: 'include',
data:new URLSearchParams(`username=${username}&password=${password}`)
});
}
Which basically just displays the access&refresh tokens in the network info of the page.
how do I actually identify the user on a website from there on and actually be able to use the user's own data, such as files for example?
I need to just be able to identify the user, all their data, such profile-info, photos etc...
and the user to only be able to access its own data
You already have what you need. the access&refresh tokens are the ones needed for routes that require authorization. The token has the user details which identifies them to the back end who is making requests. after login you save the token on the browser and as long as the token is valid the user is logged in. The token are sent along with requests that need authorization to access as a header like this
let say to get user full profile we need to have been logged in ->
axios(' api/user/profile ', { method: 'POST', headers: {'Content-Type': 'application/json,'Authorization':'Bearer' + localStorage.getItem('user-token')}, });.
JWTs are used to encode what actions user is allowed to take and which pages to see. For example you could encode their role inside the token to indicate what they are allowed to access. In order to retrieve their data such as profile info, photos etc. you have to either send additional information, probably the user id or you have to encode the id field inside the token which is not there by default.
So let me first explain what I'm trying to achieve even though it's probably not the right way to go about this.
I make discord bots and my goal is to have the bot check with the website before starting/running commands. I (for obvious reasons) don't want to put the true/false in the code in the event I need to stop a bot from starting remotely.
I set something up on my Express app so that when the specific section of the response matches the client ID in the array, then grab the piece from the response where it says true or false. Act on it if it doesn't and do nothing if the object is equal to true. I have this part down, however the part that I don't know how to do is access this "object" from the bot.
Does anybody know how to do this?
app.get('/botAuthentication/getToken', (req, res) => {
if(['7838193829389238'].includes(req.query.authorization)) {
res.status(200)
res.send({
botAuth: true
})
} else {
return res
.status(401)
.send( { code: 401, message: "You can't view this page."})
}
});
This code returns the shown object when opened in the browser.
TLDR; How do I grab that object from the website using some sort of library or method?
I know this might not be the proper way to do this; I am new to web development.
Thank you in advance!
In your bot I suggest you use axios as it is a very easy to use fetch library, but you can use node-fetch, request or pick from many others....
const axios = require('axios')
// Somewhere in your bot...
axios.get('https://my-bot-command-and-control.example.com/botAuthentication/getToken', {
params: : {
authorization: '7838193829389238'
}
}).then((response) => {
if (response.botAuth) {
// do bot stuff
}
})
A couple of points... As a security perspective, it is imperative that you keep the secret authorization code a secret. That means no putting it in git and outside of your development environment, you must deploy the express server behind SSL termnination so the connection between your bot and the API is encrypted. Otherwise you will be transmitting the authorization code in plaintext.
I have created a slack bot who is having some interactive buttons. Once a button is clicked I am going to post a direct message to the user who clicked the interactive button. There i need to show the user profile not the bot profie image. for posting message i am using slack api chat. postmessage ().
When i call this method message is posted as the bot user ( it displays the bot user icon ). But i need to post this message as the user who clicks this buttons. i checked as_user: false property to do this thing. But it didnt work? i am using my app auth token for call this method.
var url = "https://slack.com/api/chat.postMessage";
var auth_token ='xoxb-518598944980-577890089556-0i753DBbVkigtyuhfbnmfhjn'; //Your Bot's auth token
var headers = {
"Authorization": "Bearer " + auth_token,
"Content-Type" : "application/json"
}
var body = {
channel: actionJSONPayload.channel.id,
text: "Your text goes here.",
as_user: false // Slack user or channel, where you want to send the message
}
request.post({
"url": url,
"headers": headers,
"body": JSON.stringify(body)
}, (err, response, body) => {
if (err) {
reject(err);
}
console.log("response: ", JSON.stringify(response));
console.log("body: ",body);
});
}
So is there any way to generate tokens specifically to the users who interact with the button dynamically and use that token to call this method? Will it solve this issue or is there anyother ways? i have added all related permissions when installing the application like chat:write:user
If you need to post the reply message as the user who clicked the button you app needs to call the API method with a token from that user to post the message. That is the only way how an app can impersonate a user on Slack.
So to make this work in your workspace you need to ask every user to install your app once and collect their tokens during the Ouath 2.0 installation process for later user.
This approach has some obvious security issues to consider, e.g. your app will get access to each and every message from every user in your workspace.
A workaround is to manually set the username and icon of a message send by your app (by setting icon_url and username accordingly and as_user = false when calling chat.postMessage). You can retrieve the icon and username from users.info. Messages will still carry the APP tag to mark them as coming from a bot though.
I am trying to develop a web-app based on girder platform (a data management platform). During development, I get some problem confused me for a long time. Let me briefly explain my work and if anything I understand worry, please point it out coz I just start.
The thing is that,
In the font end I am using AMI(a javascript library) to deal with image virtualization, and the way is to tell (make a request to girder server) AMI the URL address which contains image to display as attachment. (e.g.http://girderDomain:port/api/v1/file/imageID/download?contentDisposition=attachment API of girder)
When this URL does not have any permission, everything works fine. When it needs permission (which is a token generated when authorized user login), purely URL does not work, so I was trying to use ajax to make a request with requestHeader(token) something like below:
$.ajax({
type:'GET',
url:'http://girderDomain:port/api/v1/file/imageWithPermissionID/download?contentDisposition=attachment',
crossDomain:true,
processData: false,
beforeSend:function(xhr){
// xhr.setRequestHeader("Access-Control-Allow-Origin:", "*");
// xhr.setRequestHeader("girderToken", token);
},
success:function (d,s,xhr) {}
});
Although I still get some error not solving yet, but ajax is the only way that in my mind.
and the whole process is like pseudocode below:
//***AMI***//
var t2 = ["imageID",....]; //////No permission need image
files = t2.map(function(v) {
return 'http://girderDomain:port/api/v1/file/' + v+'/download?contentDisposition=attachment';
});
AMI.display(files)
As you can see no permission image display is simple and easy to do, and with permission image through ajax request would be something like:
//***ajax to download permission file first***//
$.ajax({
//url:'http://girderDomain:port/api/v1/file/imageWithPermissionID/download?contentDisposition=attachment'
//set requestHeader("girderToken",token);
//success:function(){
//download this permission file to request domain tempFolder as A
}
});
/***AMI***/
var t2 = ["A"];
files = t2.map(function(v) {
return 'http://requestDomain/tempFolder/A';
});
AMI.display(files);
and that looks stupid, so I am wondering does anyone have any idea to request a file with permission, like maybe save token in cookie or session and using some way to make request with cookie or session, or any other new methods, frameworks.
Since I just start that kind of client-server development, any help truly appreciated.
I'm trying to delete one user from _User table of parse.com but I get an error.
I'm sure that the syntax of the request is fine, I'm getting this error:
code: 206
error: "Parse::UserCannotBeAlteredWithoutSessionError"
I think I shouldn't to do log-in to delete users, because I'm doing it on API REST.
$scope.delete = function (id) {
$http({
method: "DELETE",
url: url_users + id,
headers: {'X-Parse-Application-Id': appId,
'X-Parse-REST-API-Key': restId}
}).success(function (data) {
debugger;
swal("Deleted!", "All user data has been deleted", "success");
}).error(function (data) {
debugger;
swal("Error!", "An unexpected error ocurred, try again!", "error");
});
}
You're trying to remove a user from a different user session to remove. This does not work from the REST API, even if you use the X-Parse-REST-API-Key in the headers. The solution is to use Clode Code Function to delete or update a user from another session.
For more information see the documentation Parse Cloud Code Guide
The following response is the Code Clode Function to delete a user:
Parse User Destroy - Javascript in Cloud Code
I haven't tried doing this, but I have these ideas:
Make sure your ACL allows this to the public
Is it not acceptable to call a cloud code function? This would feel more intuitive to me than using the API in this case. Can you explain why you must use the REST API?
If that doesn't work, look at this answer: https://www.parse.com/questions/delete-a-user-rest-api
Basically you might have to pass the Master Key header, which is less than ideal to expose to the public. Is it not accep