Teams Message Extension: Embedding Content from Tab App into Task Module with Authentication - authentication

I have created a Tab App in Teams. Now I want to make a dialog from one tab accessible via a Message Extension App. This works partially now through embedding the contentUrl of the specific tab as an iFrame in the Task Module of the Message Extension like here: https://learn.microsoft.com/en-us/microsoftteams/platform/messaging-extensions/how-to/action-commands/create-task-module?tabs=dotnet#create-a-task-module-with-an-embedded-web-view
. The issue is the authentication. Api Calls won't work and the dialog is not able to retreive or send data.
In the manifest.json of the Tab App are the contentUrls of the tabs in the "staticTabs" section:
"staticTabs": [
{
"entityId": "dashboard",
"name": "Dashboard",
"contentUrl": "https://cdne-stcsfeedbackuidev.azureedge.net/tabs/dashboard.html?app.locale={locale}&page.subPageId={subEntityId}&app.theme={theme}",
"scopes": [
"personal"
]
}
],
I gave the dialog a specific Route via React Router so that you can access the dialog via subPageId. This works fine.
The Problem is, if you access the contentUrl, you won't be authenticated and API calls to the Graph API and own API won't work. This issue does not go away if I embed the tab via contentUrl in a Task Module for the Message Extension to give it a Teams Context:
public async handleTeamsMessagingExtensionFetchTask(
context: any,
action: any
): Promise<any> {
return {
task: {
type: 'continue',
value: {
width: 925,
height: 925,
title: 'Feedback Dialog',
url: "https://2e70-37-201-241-91.ngrok.io/feedbackDialog.html",
fallbackUrl: "https://cdne-stcsfeedbackuidev.azureedge.net/tabs/dashboard.html?page.subPageId=feedbackDialog"
}
}
};
}
Directly embedding the url like in "fallbackUrl" will result in an empty Task Module so I embedded the Url in a like this in feedbackDialog.html:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hello World Feedback!</title>
</head>
<body>
<script src="https://statics.teams.microsoft.com/sdk/v1.7.0/js/MicrosoftTeams.min.js"></script>
<script>
microsoftTeams.initialize();
microsoftTeams.getContext((context) => {
console.log(context);
microsoftTeams.authentication.getAuthToken({
successCallback: (token) => {
console.log(token);
},
failureCallback: (reason) => {
console.error(reason);
}
});
});
</script>
<div style="padding:50px;">
<iframe id="feedbackDialog" width="800" height="800", frameBorder="0"
src="https://cdne-stcsfeedbackuidev.azureedge.net/tabs/dashboard.html?page.subPageId=feedbackDialog"></iframe>
</div>
</body>
</html>
The dialog gets displayed in the Task Module this way like if I open the contentUrl in the browser directly. But the Authentication does not work. The Teams context can be retreived but all API calls return with the Error: "Error: SDK initialization timed out".
Is there a simple way for me to authenticate the user here because this runs in Teams as a MessageExtension App and the embedded content in the Task Module comes from a Teams Tab App. Or do I need to manually implement something using MSAL?

Related

Show custom error message on passwordless Auth0 page

I would like to only allow certain phone numbers when patients sign up to my application through a passwordless Auth0 page.
For this I added a custom Auth0 action to the Pre User Registration flow.
My custom action checks the phone prefix:
/**
* Handler that will be called during the execution of a PreUserRegistration flow.
*
* #param {Event} event - Details about the context and user that is attempting to register.
* #param {PreUserRegistrationAPI} api - Interface whose methods can be used to change the behavior of the signup.
*/
exports.onExecutePreUserRegistration = async (event, api) => {
if (!isAllowedPhoneNumber(event.user.phone_number)) {
api.access.deny('my_custom_identifier', 'My Custom Message');
}
};
const allowedPhonePrefixes = ["+43", "+32", "+420", "+45"];
const isAllowedPhoneNumber = (phoneNumber) =>
allowedPhonePrefixes.some((prefix) => phoneNumber.startsWith(prefix));
However, "My Custom Message" doesn't show up when I try a phone number outside those allowed. Instead, I see the default "We're sorry, something went wrong".
I then tried to edit the HTML code of my custom Auth0 login page adding this:
languageDictionary = {
...languageDictionary,
passwordless: {
"lock.fallback": "My Custom Message",
"no_signups_from_outside_schengen_area": "My Custom Message 2",
}
};
So the HTML code of my page now looks like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Sign In with Auth0</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<!--[if IE 8]>
<script src="//cdnjs.cloudflare.com/ajax/libs/ie8/0.2.5/ie8.js"></script>
<![endif]-->
<!--[if lte IE 9]>
<script src="https://cdn.auth0.com/js/base64.js"></script>
<script src="https://cdn.auth0.com/js/es5-shim.min.js"></script>
<![endif]-->
<script src="https://cdn.auth0.com/js/lock/11.30/lock.min.js"></script>
<script>
// Decode utf8 characters properly
var config = JSON.parse(decodeURIComponent(escape(window.atob('##config##'))));
config.extraParams = config.extraParams || {};
var connection = config.connection;
var prompt = config.prompt;
var languageDictionary;
var language;
if (config.dict && config.dict.signin && config.dict.signin.title) {
languageDictionary = { title: config.dict.signin.title };
} else if (typeof config.dict === 'string') {
language = config.dict;
}
var loginHint = config.extraParams.login_hint;
languageDictionary = {
...languageDictionary,
passwordless: {
"lock.fallback": "My Custom Message",
"no_signups_from_outside_schengen_area": "My Custom Message 2",
}
};
var lock = new Auth0LockPasswordless(config.clientID, config.auth0Domain, {
auth: {
redirectUrl: config.callbackURL,
responseType: (config.internalOptions || {}).response_type ||
(config.callbackOnLocationHash ? 'token' : 'code'),
params: config.internalOptions
},
configurationBaseUrl: config.clientConfigurationBaseUrl,
overrides: {
__tenant: config.auth0Tenant,
__token_issuer: config.authorizationServer.issuer
},
assetsUrl: config.assetsUrl,
allowedConnections: connection ? [connection] : null,
rememberLastLogin: !prompt,
language: language,
languageBaseUrl: config.languageBaseUrl,
languageDictionary: languageDictionary,
theme: {
logo: 'https://link-to-my-logo.something',
primaryColor: '#429db3'
},
closable: false,
showTerms: false
});
lock.show();
</script>
</body>
</html>
... but still neither "My Custom Message" nor "My Custom Message 2" show up. I still see "We're sorry, something went wrong".
How can I show a custom error message to users who enter a phone number from outside the list of allowed countries?
Note: I am pretty sure that the custom Auth0 action works, as I am able to prevent sign-ups for certain phone prefixes. What is probably wrong is the way I'm changing the code of the HTML page shown above, I suppose.
There is a partial solution that allows to show a custom message for all extensibility errors. (I haven't found a way to show different custom messages for different extensibility errors.)
This partial solution involves changing the structure in which the languageDictorionary variable above is structured:
languageDictionary = {
...languageDictionary,
error: {
passwordless: {
extensibility_error: "My Custom Message for all extensibility errors"
}
}
};
This way, any call to api.access.deny in the Pre User Registration flow will show "My Custom Message for all extensibility errors", no matter what identifier or message is passed to api.access.deny.

The skype client , Why can't I login successfully?

I want to call the interface of skype in my program,Implement the function of sending messages to friends, but the login is not successful,I followed Microsoft's operation documentation step by step, and I did not receive a prompt to log in successfully, nor did I receive any errors. The following is the address of the Microsoft document I refer to :
https://learn.microsoft.com/zh-cn/skype-sdk/websdk/docs/getapientrysignin
Below is a screenshot of my code:
<html>
<head>
<title>My Skype Web SDK app</title>
</head>
<body>
<iframe id="xFrame" src="about:blank" style="display:none;"></iframe>
<script src="https://swx.cdn.skype.com/shared/v/1.2.15/SkypeBootstrap.min.js"></script>
<script>
Skype.initialize({ apiKey: 'a42fcebd-5b43-4b89-a065-74450fb91255' }, api => {
var app = new api.application;
app.signInManager.signIn ({
username: 'yidian99880#163.com',
password: 'password'
}).then(() => {
console.log("signed in as", app.personsAndGroupsManager.mePerson.displayName());
}, err => {
console.log("cannot sign in", err);
});
}, err => {
console.log("cannot load the sdk package", err);
});
</script>
</body>
</html>
Below is the console output after I run:
I configured nginx locally on my computer, modified the host file, and added the domain name in it "test.my-skype.com"
The apikey in the code is provided in the Microsoft documentation, I can't find the entrance to apply for apikey
If you can tell me why I can't log in to skype then it would be greatly appreciated

OneDrive Picker not loading

The OneDriver Picker does not load after the authentication process but instead shows a spinner.
Steps to Reproduce
OneDrive Scripts Tested:
https://js.live.net/v7.2/OneDrive.debug.js
https://js.live.net/v7.2/OneDrive.js
Code used to Initiate the OneDriver Picker:
function launchOneDriverPicker() {
debugger;
var odOptions = {
clientId: "${clientId}",
action: "share",
multiSelect: true,
openInNewWindow: true,
advanced: {
redirectUri: "${redirectUri}"
},
success: function(r) {
},
cancel: function() {
},
error: function(error) {
}
};
OneDrive.open(odOptions);
}
Environments Tested:
- Chrome (Normal/Incognito)
- Firefox (Normal/Incognito)
Steps
The page hosting the OneDrive Picker and redirect URLs are served from the same domain
The redirect occurs to a redirect page with the following content hosted under the same domain (domain/redirect):
<html>
<head>
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
<script type="text/javascript" src="https://js.live.net/v7.2/OneDrive.debug.js"></script>
</head>
</html>
Additional Notes
The above setup works correctly with the OneDriver Picker 7.0 as noted in an earlier issue:
https://github.com/OneDrive/onedrive-api-docs/issues/824
While debugging the issue I noticed that the OneDriver Picker makes a cross document call to the parent window which opened the Picker. There are no errors up to this point but the parent page does not receive this message.
The domain specified in the cross document call is correct
Reference
[1] https://learn.microsoft.com/en-us/onedrive/developer/controls/file-pickers/js-v72/open-file?view=odsp-graph-online#using-a-custom-redirect-uri

Is it possible to add a custom Cloud file service (like OneDrive/Dropbox) to Outlook.com (Office 365)

I've seen that when you add an Attachment in Outlook, you can automaticly add an attachment from a cloud service.
Is there a possible way to add a custom entry to this list?
I offer to you to use OneDrive file picker , with this you can simply add button to your add-in html and then it's open the log-in page and after user is log-in he could choose the files from one drive.
The steps wrote in the link but I write the main steps here:
1.register your app in Microsoft Application Registration Portal .
2.Add the js refrence in your js file of your add-in:
<script type="text/javascript" src="https://js.live.net/v7.0/OneDrive.js">
</script>
3.Add button to your add-in html page:
<button class="oneDriveButton" id="btnOneDrive" ><img src="https://js.live.net/v5.0/images/SkyDrivePicker/SkyDriveIcon_white.png" style="margin-right: 10px; height: 20px;">Open from OneDrive</button>
4.In your js file of add-in open the picker:
$('#btnOneDrive').click(function () {
var odOptions = {
clientId: "your client id from your app registration ",
action: "download",
multiSelect: true,
openInNewWindow: true,
linkType: "query",
advanced: { redirectUri: "your redirect uri from app registration" },
success: function (files) {
},
cancel: function () { /* cancel handler */
},
error: function (e) { /* error handler */
}
};
OneDrive.open(odOptions); });
Put attention:
Your clientId and your redirectUri must be equal to this you
set when you register your app in the first step.
You could change the option by what you want ,look here under
picker options .
Thats all , you get the files in sucess handler function and you could do whatever you want with them.
Good luck!

Hyperlinks in Bing Maps infobox breaks Windows 8 App Navigation State

I have Bing Maps on a page in my WinJS Windows 8 Application.
The Map has a few pins each with its own Infobox. When clicking on the pin it displays the infobox correctly with its content. The content contains a hyperlink that links to a different page in the Windows 8 Application. The app navigates to this page correctly, however the back button stops working and the App Bar can't be accessed either. (Navigating to the page normally works fine)
I think something goes wrong with how the page navigates and how the navigator records the state. I am new to this so it might also just be a stupid question.
Here is the code in the page's .js file:
// For an introduction to the Page Control template, see the following documentation:
// http://go.microsoft.com/fwlink/?LinkId=232511
(function () {
"use strict";
WinJS.UI.Pages.define("/pages/testBing/testBing.html", {
// This function is called whenever a user navigates to this page. It
// populates the page elements with the app's data.
ready: function (element, options) {
// TODO: Initialize the page here.
Microsoft.Maps.loadModule('Microsoft.Maps.Map', { callback: initMap });
}
});
})();
var pinInfobox = null;
function initMap() {
try {
var mapOptions =
{
credentials: "credentials",
center: new Microsoft.Maps.Location(-33.961176, 22.420985),
mapTypeId: Microsoft.Maps.MapTypeId.road,
zoom: 5
};
var mapDiv = document.querySelector("#mapdiv");
map = new Microsoft.Maps.Map(mapDiv, mapOptions);
centerPosition();
}
catch (e) {
var md = new Windows.UI.Popups.MessageDialog(e.message);
md.showAsync();
}
}
function addPushPin(location) {
map.entities.clear();
var pushpin = new Microsoft.Maps.Pushpin(location, null);
pinInfobox = new Microsoft.Maps.Infobox(new Microsoft.Maps.Location(0, 0), { title: 'My Pushpin', visible: true, description: "<a href='/pages/player/player.html'>Profile</a>" });
Microsoft.Maps.Events.addHandler(pushpin, 'click', displayInfobox);
Microsoft.Maps.Events.addHandler(map, 'viewchange', hideInfobox);
map.entities.push(pushpin);
map.entities.push(pinInfobox);
}
function hideInfobox(e) {
pinInfobox.setOptions({ visible: false });
}
function centerPosition() {
var geolocator = new Windows.Devices.Geolocation.Geolocator();
geolocator.getGeopositionAsync().then(function (loc) {
var mapCenter = map.getCenter();
mapCenter.latitude = loc.coordinate.latitude;
mapCenter.longitude = loc.coordinate.longitude;
map.setView({ center: mapCenter, zoom: 15 });
addPushPin(mapCenter);
});
}
function displayInfobox(e) {
pinInfobox.setOptions({ title: e.target.Title, innerHTML: e.target.Description, visible: true, offset: new Microsoft.Maps.Point(0, 25) });
pinInfobox.setLocation(e.target.getLocation());
}
The HTML just has the following
<!-- WinJS references -->
<link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.1.0/js/base.js"></script>
<script src="//Microsoft.WinJS.1.0/js/ui.js"></script>
<!--Bing Mapps Reference -->
<script type="text/javascript" src="ms-appx:///Bing.Maps.JavaScript//js/veapicore.js"></script>
<link href="testBing.css" rel="stylesheet" />
<script src="testBing.js"></script>
</head>
<body>
<div class="testBing fragment">
<header aria-label="Header content" role="banner">
<button class="win-backbutton" aria-label="Back" disabled type="button"></button>
<h1 class="titlearea win-type-ellipsis">
<span class="pagetitle">Welcome to testBing</span>
</h1>
</header>
<section aria-label="Main content" role="main">
<div id="mapdiv"></div>
</section>
</div>
</body>
</html>
The comment by Dominic Hopton is correct: foo.html gets loaded as the whole page instead of as part of your app's navigation process. If the links are supposed to do an app navigation (as opposed to open in an external web browser), you can add this code to your page's ready function to convert the link click into a navigation event.
WinJS.Utilities.query("a").listen("click", function (e) {
e.preventDefault();
nav.navigate(e.target.href);
});
If you have some links that should navigate and some that should open in a browser, you can modify the query. For example, if can can add a CSS class to links that should open in a web browser, you could change the query to:
WinJS.Utilities.query("a:not(.defaultClick)")
You might also be able to modify the query to examine the href attribute of the link to check for "http" like so:
WinJS.Utilities.query("a:not([href^=http])")
I have not tested this last example yet, but if it works as I suspect it would, it would have a links that start with "http" (so including "https") behave normally, while all links that have a relative URL or a package URL will be converted to navigation events.
I don't recommend that you do this blindly, but depending on your app, this simple shortcut might change the behavior to match your expectations.