microsoftarchive / botauth Goto Github PK
View Code? Open in Web Editor NEWAuthentication middleware for the botframework
License: MIT License
Authentication middleware for the botframework
License: MIT License
Is this project using the Bot Framework State Service? Looking at the code, it seems like the AuthDialog and CallbackController are using it to pass back and forth the authentication values. Since the State Service is now deprecated, won't that cause problem using this code in production? Or am I mistaken?
Hey, i am running into issues #14 and #16 again.
It seems botauth in the current version is still incompatible with the express web server.
I am trying to connect to AADv2 and get a 500 server error when opening the AADv2 callback url https://somebot.eu.ngrok.io/botauth/aadv2/callback?code=OAQABAAIAAADX8GCi6Js6SK82TsD2Pb7r35MlsfImkvXuDJc9P6ppQOjkQYpAPSZhTklOid3MNSrt6D559VicvOWluX0ebmgkzYP3J3ZE3taFUvmWusaBP2WBHR7xhhzv_HiG3SeqyjNQK0bEp4D8OB5dO1E1nNYRr8prZEfcp7g8lAZn9vHoFoQv3NEJHEA9Vgn8Lu1FR7beCN3QoygJPhNA8R_WFqYUjILr9bNSTyPPrpcfh2RJT0xKAjiv-QgRZRoCNsgMwbmbUCEkDjdudC5qo0yxS44-BHgiRVkHNEi7J7jJXHn7Or2O2tg1tjZ5Kx2kENP134LQOXaYSz_W6-jniG2oHJNS4CjSjlwuFgjCPGt5P3E8H2CiGNv93TrTTR9DGgG2JHOekFMSn2j0STHnBMI5zRGYGrG0rzSbrQB8EmlaDhX_BcGlqh7WATSwkZdU0HKfASeWZt4nOoGmTdv5Pk54SPIpKOcMaPNUDI4jvxjqvBCphiK9Ao9lunlslkP6HqzAlS2sfsZO-gnuXFNLYKQ_n4bUJ-v1oolVCpgLFiy_PjCdJSAqHqBoJI9nE_GqUJJqxo1c1Gqtld-IVHZ7iOwLi39Ue8KbqTB7WGUCl6c3LHVqYyg-RwVeu2vV69Tz5PuJd1jI9NDG4ZkVYJJfjidycCDqmfvEhaLgaDKh2nf3gt7ISo_J9tmh_uCKWn4uUQRAGyhVLzJYgb8viQA1-86G9ocK6q9VOVXD2XJrgHClDxFOaiAA&state=sIVYMo3WaRNJ06TxPCqIYnFKcltosthu&session_state=b94b095c-6ab2-44b1-a4de-35965bcca1e5
.
Express Stacktrace:
at /projects/somebot/node_modules/botauth/lib/index.js:156:57
at Layer.handle [as handle_request] (/projects/somebot/node_modules/express/lib/router/layer.js:95:5)
at next (/projects/somebot/node_modules/express/lib/router/route.js:131:13)
at /projects/somebot/node_modules/botauth/lib/resumption.js:35:13
at Layer.handle [as handle_request] (/projects/somebot/node_modules/express/lib/router/layer.js:95:5)
at next (/projects/somebot/node_modules/express/lib/router/route.js:131:13)
at complete (/projects/somebot/node_modules/passport/lib/middleware/authenticate.js:250:13)
at /projects/somebot/node_modules/passport/lib/middleware/authenticate.js:257:15
at pass (/projects/somebot/node_modules/passport/lib/authenticator.js:421:14)
at Authenticator.transformAuthInfo (/projects/somebot/node_modules/passport/lib/authenticator.js:443:5)
TypeError: Cannot read property 'resumption' of undefined
The in #14 suggested botauth fork does not work, either.
Is there any workaround available besides switching to restify?
Regards
Most of the links on the Node and Node examples are broken.
Hey there,
Cool module! I'm looking at implementing an account linking example using a facebook messenger bot. I notice the example you've got around this is incomplete.
Have you had any success with trying to implement account linking with OAuth end to end?
Provide a default html page or view
Allow the html page to be overridden by the API consumer.
{
staticDirectory : __dirname + "/public",
magicPage : "magic.html"
}
Hi,
I saw from the CSharp code (https://github.com/MicrosoftDX/botauth/tree/master/CSharp) that there's a way to add a custom provider for botauth. Is there any documentation or sample code on how I can do the same thing in NodeJs using botauth?
Thanks
I may be missing something in my implementation, however, I've found what appears to be a mismatch the schema in IDialogContext for UserData and BotAuth.ContextConstants. The properties in ConstantContext seem to missing the precursor for the provider. For example:
BotAuth.ContextConstants.AuthResult returns _authMagicNumberValidated
Microsoft.Bot.Builder.Dialogs.IBotDataBag returns MSALAuthProvider_authMagicNumberValidated
Hello,
I'm trying to use botauth
to connect to an Auth0 client using the passport-auth0 strategy to authorize access to my api that sits behind an API gateway.
Using the Bot Framework Emulator, and commenting out lines 36-38 of index.js so I can use a an http
callback address (perhaps that is my issue), I am able to enter my credentials with Auth0 , click login and the bot logs my profile
However.... after authenticating in the browser, the bot redirects to http://WEB_HOSTNAME:PORT/botauth/auth0?state=...
hangs there for a bit, then redirects to http://WEB_HOSTNAME:PORT/botauth/auth0/callback?code=...
with the response:
{"message":"Invalid authorization code"}
and I never get my bot conversation resumed in the emulator.
I wrote up a quick test based on the project's pintrest example it it helps anyone work out what I am doing wrong...any help would be appreciated...
Notes:
server.use(clientSessions({ secret: BOTAUTH_SECRET }));
Regular Web Application
Non Interactive Client
Thanks in advance.
"use strict";
const restify = require("restify");
const builder = require("botbuilder");
const envx = require("envx");
const botauth = require("botauth");
const clientSessions = require("client-sessions");
const passport = require("passport");
const Auth0Strategy = require('passport-auth0')
//contextual service information
const WEBSITE_HOSTNAME = envx("WEB_HOSTNAME");
const PORT = envx("PORT", 3998);
//bot application identity
const MICROSOFT_APP_ID = envx("MICROSOFT_APP_ID");
const MICROSOFT_APP_PASSWORD = envx("MICROSOFT_APP_PASSWORD");
//oauth details for pinterest
const AUTH0_DOMAIN= envx("AUTH0_DOMAIN");
const AUTH0_CLIENT_ID = envx("AUTH0_CLIENT_ID");
const AUTH0_CLIENT_SECRET = envx("AUTH0_CLIENT_SECRET");
//encryption key for saved state
const BOTAUTH_SECRET = envx("BOTAUTH_SECRET");
var server = restify.createServer();
server.use(restify.bodyParser());
server.use(restify.queryParser());
server.use(clientSessions({ secret: BOTAUTH_SECRET }));
// Create chat connector with bot's Microsoft app identity
var connector = new builder.ChatConnector({
appId: MICROSOFT_APP_ID,
appPassword: MICROSOFT_APP_PASSWORD
});
// Create bot builder client and connect it to restify server
var bot = new builder.UniversalBot(connector);
server.post('/api/messages', connector.listen());
// Initialize with the strategies we want to use
var ba = new botauth.BotAuthenticator(server, bot, { baseUrl : "http://" + WEBSITE_HOSTNAME, secret : BOTAUTH_SECRET })
.provider("auth0", (options) => {
return new Auth0Strategy({
domain: AUTH0_DOMAIN,
clientID: AUTH0_CLIENT_ID,
clientSecret: AUTH0_CLIENT_SECRET,
scope: 'openid profile email identities',
//scope: ['openid', 'profile', 'email', 'identities'],
//scope: [ 'read_public', 'read_relationships' ],
callbackURL: options.callbackURL
//callbackURL: options.callbackURL
}, (accessToken, refreshToken, profile, done) => {
profile = profile || {};
profile.accessToken = accessToken;
profile.refreshToken = refreshToken;
profile.provider = "auth0"; // workaround
console.log('===========')
console.log(profile)
console.log('===========')
return done(null, profile);
});
});
/**
* Just a page to make sure the server is running
*/
server.get("/", (req, res) => {
res.send("auth0");
});
//=========================================================
// Bot Dialogs
//=========================================================
bot.dialog('/', new builder.IntentDialog()
.matches(/^hello/i, "/hello")
.matches(/^data/i, "/data")
.matches(/^logout/i, "/logout")
.onDefault((session, args) => {
session.endDialog("I didn't understand that. Try saying 'data'.");
})
);
bot.dialog("/hello", (session, args) => {
session.endDialog("Hello. I can help you get information from my service. Try saying 'data'.");
});
bot.dialog("/data", [].concat(
ba.authenticate("auth0"),
function(session, results) {
// --------- code omitted
// call my api behind gateway using jwt token... return data.
// --------- code omitted
// let's just log the user if we get here for now
var user = ba.profile(session, "auth0");
console.log(user)
));
bot.dialog("/logout", [
(session, args, next) => {
builder.Prompts.confirm(session, "are you sure you want to logout");
}, (session, args) => {
if(args.response) {
ba.logout(session, "auth0");
session.endDialog("you've been logged out.");
} else {
session.endDialog("you're still logged in");
}
}
]);
//start the server
server.listen(PORT, function () {
console.log('%s listening to %s', server.name, server.url);
});
After authentication is completed, next messages I type in are going to Resume method after Authenitcation instead of going into root dialogue. Please help.
I am building a bot App that connects to my enterprise O365 tenant. When using BotAuth.AADv2 to authenticate I get the a response from Azure that my app can't use the common endpoint and I should use my tenant endpoint.
I specified my tenant "Authority" endpoint in the "AuthenticationOptions" to be my tenant:
https://login.microsoftonline.com/{tenantId}/oauth2/token but the authentication still fails
I traced the code and the problem is not passing the "Authority" parameter to the "ConfidentialClientApplication" in the MSALAuthProvider
I updated the following two lines to make it work:
Line 57-58:
ConfidentialClientApplication client = new ConfidentialClientApplication(authOptions.ClientId,
**authOptions.Authority**, redirectUri.ToString(), new ClientCredential(authOptions.ClientSecret),
tokenCache, null);
Line 67-68:
ConfidentialClientApplication client = new ConfidentialClientApplication(authOptions.ClientId,
**authOptions.Authority**, authOptions.RedirectUrl, new ClientCredential(authOptions.ClientSecret),
tokenCache, null);
I can submit a pull request if you like.
Hello -
In my scenario, I',m using the authentication in the root dialogue and once the user successfully logged in I'm forwarding the user to the other dialogues. Once the users are in other dialogue, how can we verify that the user is still valid, is there a helper utility to validate the user token once we are on other dialogues?
Regards,
Sowmyan
Any ETA on when aadv1 for Node js will be released.
Has anyone used passport-drupal for their botbuilder bot (and botauth)? Would appreciate an example of this. I've activated oauth on my drupal site based on https://www.drupal.org/node/1871498 and https://github.com/mixmarket/passport-drupal/blob/master/README.md but haven't had success at using the passport-drupal strategy with botauth.
This issues comes in two parts:
Due to the lack of support of a SigninCard
, clicking the button doesn't open a URL, as one would expect. The C# AuthBot had also noted this issue and makes use of a ThumbnailCard
: https://github.com/MicrosoftDX/AuthBot/blob/master/AuthBot/Dialogs/AzureAuthDialog.cs with a button that has an associated openUrl
action.
I've just pulled the example and am attempting to get the auth flow working.
When redirected back to my site with the code issued by the v2 endpoint I'm presented with an Unauthorized message and an HTTP 401 status code.
Changes made to cloned code:
I've set WEBSITE_HOST to localhost:3978 and used the App Id and App Password I generated on apps.dev.microsoft.com
I have changed my local copy of botauth on line 36 so that an http address will work and set allowHttpForRedirectUrl: true so that I don't have to mess around getting an SSL cert or ngrok working locally.
This might feel like very basic question but I'm confused on what exactly the value of this variable would be. Will it be azure app service or some Sprint boot localhost ? According to the documentation here I used azure endpoint of bot service in AADv2 apps.dev portal as well as in apps.js but I get following error.
{"code":"ResourceNotFound","message":"/botauth/aadv2 does not exist"}
I am trying to authorise a Bot created via Azure Portal with AAD, however the instructions here do not work.
Specifically:
Whats the difference? And which one is the recommended to be used?
BotBuilder since release 3.15.1.0 supports generic OAuth flows and AADv1/v2 authentication methods out of the box. There are examples for each auth flow in official documentation. Integrated flows are also capable of making all the verifications in the background. This project even being presented on Build 2018 seem to be abandoned.
@mattdot should it be discontinued and marked as such?
I am trying to use the sample SampleGenericOAuth2Bot in my Chatbot, and implemented it by basically copying and pasting the code into my login dialog, but when running and after choosing the provider I get this exception:
Could not load type 'System.IdentityModel.Tokens.ISecurityTokenValidator' from assembly 'System.IdentityModel.Tokens.Jwt, Version=5.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'.
My packages look like this, am I missing anything?
<package id="Autofac" version="4.6.2" targetFramework="net46" />
<package id="Autofac.WebApi2" version="4.1.0" targetFramework="net46" />
<package id="AutoMapper" version="6.2.2" targetFramework="net46" />
<package id="BotAuth" version="3.9.0-alpha" targetFramework="net46" />
<package id="BotAuth.GenericOAuth2" version="3.9.0-alpha" targetFramework="net46" />
<package id="Chronic.Signed" version="0.3.2" targetFramework="net46" />
<package id="EntityFramework" version="6.2.0" targetFramework="net46" />
<package id="Microsoft.AspNet.WebApi" version="5.2.4-preview1" targetFramework="net46" />
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.4-preview1" targetFramework="net46" />
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.4-preview1" targetFramework="net46" />
<package id="Microsoft.AspNet.WebApi.WebHost" version="5.2.4-preview1" targetFramework="net46" />
<package id="Microsoft.Azure.DocumentDB" version="1.19.1" targetFramework="net46" />
<package id="Microsoft.Azure.KeyVault.Core" version="2.0.5-preview" targetFramework="net46" />
<package id="Microsoft.Bot.Builder" version="3.12.2.4" targetFramework="net46" />
<package id="Microsoft.Bot.Builder.Azure" version="3.2.5" targetFramework="net46" />
<package id="Microsoft.Bot.Builder.CognitiveServices" version="1.1.2" targetFramework="net46" />
<package id="Microsoft.Bot.Builder.History" version="3.12.2.4" targetFramework="net46" />
<package id="Microsoft.Bot.Connector" version="3.12.2.4" targetFramework="net46" />
<package id="Microsoft.Data.Edm" version="5.8.3" targetFramework="net46" />
<package id="Microsoft.Data.OData" version="5.8.3" targetFramework="net46" />
<package id="Microsoft.Data.Services.Client" version="5.8.3" targetFramework="net46" />
<package id="Microsoft.IdentityModel.Logging" version="5.2.0-preview2-41113220915" targetFramework="net46" />
<package id="Microsoft.IdentityModel.Protocols" version="5.2.0-preview2-41113220915" targetFramework="net46" />
<package id="Microsoft.IdentityModel.Protocols.OpenIdConnect" version="2.1.5" targetFramework="net46" />
<package id="Microsoft.IdentityModel.Tokens" version="5.2.0-preview2-41113220915" targetFramework="net46" />
<package id="Microsoft.Owin" version="4.0.0-preview1" targetFramework="net46" />
<package id="Microsoft.Owin.Security" version="4.0.0-preview1" targetFramework="net46" />
<package id="Microsoft.Owin.Security.Jwt" version="4.0.0-preview1" targetFramework="net46" />
<package id="Microsoft.Owin.Security.OAuth" version="4.0.0-preview1" targetFramework="net46" />
<package id="Microsoft.Rest.ClientRuntime" version="2.3.10" targetFramework="net46" />
<package id="Microsoft.WindowsAzure.ConfigurationManager" version="3.2.3" targetFramework="net46" />
<package id="Newtonsoft.Json" version="11.0.1-beta3" targetFramework="net46" />
<package id="OAuth2" version="0.8.40" targetFramework="net46" />
<package id="Owin" version="1.0" targetFramework="net46" />
<package id="QnAMakerDialog" version="1.1.1" targetFramework="net46" />
<package id="RestSharp" version="106.3.0-alpha0002" targetFramework="net46" />
<package id="System.IdentityModel.Tokens.Jwt" version="5.2.0-preview2-41113220915" targetFramework="net46" />
<package id="System.Spatial" version="5.8.3" targetFramework="net46" />
<package id="System.ValueTuple" version="4.4.0" targetFramework="net46" />
<package id="WindowsAzure.Storage" version="8.7.0" targetFramework="net46" />
Hi -
Not sure if this is expected here so want to check. During the authentication flow, after the successful authentication redirected to http://localhost:3984/magic.html#152210 with code suffixed. But getting the 404 error and for end user its confusing. So want to check am I missing anything ?
Regards,
Sowmyan
Hey Dudes,
Just wondering if in the case of authenticating against an Oauth2 based authentication mechanism (ie. Ping Federate), I need to implement a custom provider? I tried using the GenericOAuth2 provider, but can't seem to add a client to the authorizationroot object (https://github.com/MicrosoftDX/botauth/blob/master/CSharp/BotAuth.GenericOAuth2/GenericOAuth2Provider.cs, line 63).
Do I need to implement my own provider? Or just add to the list of genericOathProviders in the object above?
Hey I have 2 questions want to ask
Question 1: If I want authenticate my system via OAuth2, when user fill there loginID and password, the system will generate token, so which the stragety passport in this case
Question 2 : Could we use this solution when user communicate the bot via Mobile because as I imagine, the popup will be opened on mobile browse and Its may be hard to return token.
Thanks.
How does BotAuth compare to the implicit/silent auth flow in Teams Bot authentication?https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/authentication/auth-silent-aad
Because BotAuth seems to stress on the need for magic number validation; is not the latter a better workflow for better end user experience?
Adding localization should also allow consumers of botauth to override the default messages
Thanks a lot for the examples was battling with this for many days and had to switch to Microsoft bot builder because it's the only one where I could find a working example of account linking.
I'm trying to build a flow similar to the one used in foxsy bot https://www.messenger.com/t/foxsybot
Anyone knows how to use the default Authorization from facebook dialogue where it's asking for permission instead of the magic code? Was kind of taken aback when I didn't saw that appearing :D Didn't know it was possible to make oauth request without it.
When will this be available to ASP Net Core 2.0?
To get it working on ASP .NET Core 2.0 I've made a copy of Callbak controller with a few changes.
Changes I've made are HttpResponseMessage
changed to IActionResult
, modified routing to Microsoft.AspNetCore.Mvc.Route
.
Then I used Dependecy Injection to get MicrosoftAppCredentials and created new ConnectorClient
ConnectorClient client = new ConnectorClient(new Uri(message.ServiceUrl), credentials);
insted of using this await Conversation.ResumeAsync(conversationRef, message);
, and returned
new ContentResult();
Example:
[Microsoft.AspNetCore.Mvc.Route("[controller]")]
public class CallbackController : Controller
{
private static RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();
private static readonly uint MaxWriteAttempts = 5;
private readonly MicrosoftAppCredentials credentials;
public CallbackController(MicrosoftAppCredentials credentials)
{
this.credentials = credentials;
}
[Microsoft.AspNetCore.Mvc.HttpGet]
public async Task<IActionResult> Callback([FromQuery] string code, [FromQuery] string state, CancellationToken cancellationToken)
{
try
{
// Use the state parameter to get correct IAuthProvider and ResumptionCookie
var decoded = Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(state));
var queryString = HttpUtility.ParseQueryString(decoded);
var assembly = Assembly.Load(queryString["providerassembly"]);
var type = assembly.GetType(queryString["providertype"]);
var providername = queryString["providername"];
IAuthProvider authProvider;
if (type.GetConstructor(new Type[] { typeof(string) }) != null)
authProvider = (IAuthProvider)Activator.CreateInstance(type, providername);
else
authProvider = (IAuthProvider)Activator.CreateInstance(type);
var conversationRef = UrlToken.Decode<ConversationReference>(queryString["conversationRef"]);
Activity message = conversationRef.GetPostToBotMessage();
using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, message))
{
// Get the UserData from the original conversation
IBotDataStore<BotData> stateStore = scope.Resolve<IBotDataStore<BotData>>();
var key = Address.FromActivity(message);
var userData = await stateStore.LoadAsync(key, BotStoreType.BotUserData, CancellationToken.None);
// Get Access Token using authorization code
var authOptions = userData.GetProperty<AuthenticationOptions>($"{authProvider.Name}{ContextConstants.AuthOptions}");
var token = await authProvider.GetTokenByAuthCodeAsync(authOptions, code);
// Generate magic number and attempt to write to userdata
int magicNumber = GenerateRandomNumber();
bool writeSuccessful = false;
uint writeAttempts = 0;
while (!writeSuccessful && writeAttempts++ < MaxWriteAttempts)
{
try
{
userData.SetProperty($"{authProvider.Name}{ContextConstants.AuthResultKey}", token);
if (authOptions.UseMagicNumber)
{
userData.SetProperty($"{authProvider.Name}{ContextConstants.MagicNumberKey}", magicNumber);
userData.SetProperty($"{authProvider.Name}{ContextConstants.MagicNumberValidated}", "false");
}
await stateStore.SaveAsync(key, BotStoreType.BotUserData, userData, CancellationToken.None);
await stateStore.FlushAsync(key, CancellationToken.None);
writeSuccessful = true;
}
catch (Exception)
{
writeSuccessful = false;
}
}
var resp = new ContentResult();
if (!writeSuccessful)
{
message.Text = String.Empty; // fail the login process if we can't write UserData
ConnectorClient client = new ConnectorClient(new Uri(message.ServiceUrl), credentials);
await client.Conversations.SendToConversationAsync(message);
resp.ContentType = @"text/html";
resp.Content = "<html><body>Could not log you in at this time, please try again later</body></html>";
}
else
{
message.Text = String.Empty;
ConnectorClient client = new ConnectorClient(new Uri(message.ServiceUrl), credentials);
await client.Conversations.SendToConversationAsync(message);
resp.ContentType = @"text/html";
resp.Content = $"<html><body>Almost done! Please copy this number and paste it back to your chat so your authentication can complete:<br/> <h1>{magicNumber}</h1>.</body></html>";
}
return resp;
}
}
catch (Exception ex)
{
// Callback is called with no pending message as a result the login flow cannot be resumed.
return BadRequest();
}
}
private int GenerateRandomNumber()
{
int number = 0;
byte[] randomNumber = new byte[1];
do
{
rngCsp.GetBytes(randomNumber);
var digit = randomNumber[0] % 10;
number = number * 10 + digit;
} while (number.ToString().Length < 6);
return number;
}
}
I'm not sure if this lib is intended to work with Azure AD B2C but currently it does not support using it with a policy specified
It seems the underlying passport-azure-ad lib does support B2C but the button url generated does not include a policy parameter or a means in the options to specify one which means that the passport-azure-ad throws an error - see oidcstrategy.js
There needs to be some way to pass the policy as part of the options so that the button url can be created correctly
I raised an issue a few days ago about the bot not being compatible with Express JS. I found that the issue is that the cookie set in the redirect gets lost on the callback (my example is using the Facebook strategy).
I forked the repo to work in a solution. What I ended up doing was creating dynamic routes for the botauth endpoints, using the bot user id. For that to work I had to change the behaviour to set the callbackUrl dynamically, which is possible. With that id I was able to store the address in a closure map, that then I was able to retrieve in the callback endpoint.
So this worked for me (using express and Facebook strategy). But not sure if it would work for others. I know Restify is not that great handling dynamic routes.
If anybody is having the same issue, Im happy to share my solution (or just look at my fork)
Thanks for the hard work on this library, its awesome!
I have to run my bots in a kubernetes cluster behind a software gateway (not on a public host).
This software gateway simply proxies requests for my bot, it accepts requests at https://bot.domain.com and relays them to http://mybot. This works well enough for messages.
The problem comes in when we add botauth: the options.basePath
value is used for both route creation and as well as the generation of the callbackUrl
and authUrl
. So this means that our service endpoints can't be different from our auth and callback urls. Note that I can already do this with the code page by using options.successRedirect
.
I'm sure this is by design (as the documentation always says your bot has to be running on a public host), but I'd find it useful if you added another botAuth option, say options.baseServicePath
that can be used to define the routes on the server that do not necessarily match the externally exposed routes.
So for instance:
let options = {
baseUrl : 'https://bot.domain.com',
basePath: '/botauth',
baseServicePath: '/mybot',
//...,
successRedirect: `https://bot.domain.com/botauth/providerId/code`
};
let botAuth = new botauth.BotAuthenticator(server, bot, options);
//...
server.get(`/${server.name}/botauth/providerId/code`, serveStatic({'directory': path.join(__dirname, 'public'), 'file': 'code.html'}));
Would give me the following external URLS:
Which could easily be mapped in my gateway to my service routes:
Obviously, issue 61 not withstanding, I think this could easily be done with:
// botauth/lib/index.js
// .. line 40
if (!this.options.baseServicePath) {
this.options.baseServiceUrl = this.options.baseUrl
}
// update these three lines. (around line 59)
this.server.get(`/${this.options.baseServicePath}/:providerId`, this.options.resumption.persistHandler(), this.passport_redirect());
this.server.get(`/${this.options.baseServicePath}/:providerId/callback`, this.passport_callback(), this.options.resumption.restoreHandler(), this.credential_callback());
this.server.post(`/${this.options.baseServicePath}/:providerId/callback`, this.passport_callback(), this.options.resumption.restoreHandler(), this.credential_callback());
In any event, happy to contribute if that would work.
Looking at https://github.com/MicrosoftDX/AuthBot repo it suggests that the bot framework now has oauth based authN/authZ support provided [ https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-tutorial-authentication?view=azure-bot-service-3.0 ].
Can you provide insights on what functionality is this work providing that is not covered by the current bot framework support for oauth authN/authZ?
Is it possible to use the jwt passport strategy with botauth? Is it that only the defined strategies in the readme file work or we can use any strategy?
After logging in into Facebook and getting redirected I get this error:
TypeError: Cannot read property 'resumption' of undefined
at node_modules/botauth/lib/index.js:156:56
at Layer.handle [as handle_request] (node_modules/express/lib/router/layer.js:95:5)
at next (node_modules/express/lib/router/route.js:137:13)
at node_modules/botauth/lib/resumption.js:35:13
at Layer.handle [as handle_request] (node_modules/express/lib/router/layer.js:95:5)
at next (node_modules/express/lib/router/route.js:137:13)
at complete (node_modules/passport/lib/middleware/authenticate.js:250:13)
at node_modules/passport/lib/middleware/authenticate.js:257:15
at pass (node_modules/passport/lib/authenticator.js:421:14)
at Authenticator.transformAuthInfo (node_modules/passport/lib/authenticator.js:443:5)
Searched for AuthBot & BotAuth, nothing, nada.
It is not clear on how to set up the botAuth with Azure AD.
The documentation for AADv2 does not specify the following.
Is it possible to provide a detailed setup documentation or update the documentation?
The text:
Almost done! Please copy this number and paste it back to your chat so your authentication can complete:{magicNumber} is shown even when the UseMagicNumber option is set to false.
I noticed that in the CallbackContoller.cs in between lines 97 (else condition of !writeSuccessful) check for UseMagicNumber is missing causing this issue.
Unless I'm missing something the Azure AD v2 sample does not work.
I have followed all the steps described in the readme.md. The bot does respond properly to the inputs I give, then when I initiate the signin dialogue it renders the card with the oauth sign in button. However when I then try to log in it does redirect to the callbackpage (the html page in the public folder).
As far as how I've understood it, it should then show a "magic code" which I need to send to the bot to finish the authentication process. However this code
Things I've tried to send to the bot which didn't work at all:
What am I supposed to send to the bot after succesfully being redirected by the bot?
Also if I set the hostname to the botservice url the redirect to the callback 404's and signin never is able to reach the /code page. Am I supposed to do extra configuration for this or is this intended?
My bot is hosted using the Azure botservice.
on index.ts line 188 you are trying to do:
originalArgs: args.response
However, if this is the first step in the waterfall Im getting args
is undefined. The solution would be something on the lines of:
args ? args.response : {}
I forked the repo to try to work on a solution. But I'm having trouble building the library. Could you provide a development process description?
I installed typings
to download you type dependencies. But when I run gulp build
Im getting some errors (that might be related to getting different versions of the installed types, or not. Here are the errors:
10:03:14] Using gulpfile botauth/gulpfile.js [10:03:14] Starting 'build'... .../botauth/node_modules/typescript/lib/lib.es6.d.ts(4842,11): error TS2428: All declar ations of 'WeakMap' must have identical type parameters. .../botauth/node_modules/typescript/lib/lib.es6.d.ts(5049,11): error TS2428: All declar ations of 'WeakMap' must have identical type parameters. .../botauth/node_modules/typescript/lib/lib.es6.d.ts(5825,11): error TS2428: All declar ations of 'WeakMap' must have identical type parameters. .../botauth/typings/globals/node/index.d.ts(103,11): error TS2428: All declarations of 'WeakMap' must have identical type parameters. .../botauth/typings/globals/node/index.d.ts(113,25): error TS2344: Type 'K' does not sa tisfy the constraint 'object'. .../botauth/node_modules/typescript/lib/lib.es6.d.ts(4842,11): error TS2428: All declar ations of 'WeakMap' must have identical type parameters. .../botauth/node_modules/typescript/lib/lib.es6.d.ts(5049,11): error TS2428: All declar ations of 'WeakMap' must have identical type parameters. .../botauth/node_modules/typescript/lib/lib.es6.d.ts(5825,11): error TS2428: All declar ations of 'WeakMap' must have identical type parameters. .../botauth/typings/globals/node/index.d.ts(103,11): error TS2428: All declarations of 'WeakMap' must have identical type parameters. .../botauth/typings/globals/node/index.d.ts(113,25): error TS2344: Type 'K' does not sa tisfy the constraint 'object'. [10:03:16] TypeScript: 5 semantic errors [10:03:16] TypeScript: 5 emit errors [10:03:16] TypeScript: emit failed [10:03:16] Finished 'build' after 1.7 s
Hello,
I am currently able talk with my bot using Microsoft Bot Framework (Webapp & Messenger), it works, with different dialogs etc. I use ngrok endpoint on my Dev Messenger app and Microsoft Bot Framework bot. On my webapp (without bot), I implemented passport-facebook authentification to my MongoDB and it works well, I can connect choosing between local or Facebook authentication, and get back data.
What I want is now is one of these solutions:
From the bot client, my users have to login using Facebook channel (or locally on my webapp, using bot <iframe> webapp channel, or on localhost test with ngrok...) to my remote API, so with the bot I can get back some data from my MongoDB, as I do on my webapp. I need at least my Facebook ID.
Connect transparently to my remote API with Facebook authentication, so when users talk, they are directly connected, no webapp modal or anything, I can directly use their information from my remote MongoDB, and let's go.
I tried to implement 1) solution, because I really don't know how to do the second solution, which would be amazing for users.
But when I try to authenticate with Facebook using botauth, I have this error on:
TypeError: Cannot read property 'resumption' of undefined
at /Users/pierre/Desktop/Work/GitHub/alenvi-bot/node_modules/botauth/lib/index.js:156:56
at Layer.handle [as handle_request] (/Users/pierre/Desktop/Work/GitHub/alenvi-bot/node_modules/express/lib/router/layer.js:95:5)
at next (/Users/pierre/Desktop/Work/GitHub/alenvi-bot/node_modules/express/lib/router/route.js:137:13)
at /Users/pierre/Desktop/Work/GitHub/alenvi-bot/node_modules/botauth/lib/resumption.js:35:13
at Layer.handle [as handle_request] (/Users/pierre/Desktop/Work/GitHub/alenvi-bot/node_modules/express/lib/router/layer.js:95:5)
at next (/Users/pierre/Desktop/Work/GitHub/alenvi-bot/node_modules/express/lib/router/route.js:137:13)
at complete (/Users/pierre/Desktop/Work/GitHub/alenvi-bot/node_modules/passport/lib/middleware/authenticate.js:250:13)
at /Users/pierre/Desktop/Work/GitHub/alenvi-bot/node_modules/passport/lib/middleware/authenticate.js:257:15
at pass (/Users/pierre/Desktop/Work/GitHub/alenvi-bot/node_modules/passport/lib/authenticator.js:421:14)
at Authenticator.transformAuthInfo (/Users/pierre/Desktop/Work/GitHub/alenvi-bot/node_modules/passport/lib/authenticator.js:443:5)
at /Users/pierre/Desktop/Work/GitHub/alenvi-bot/node_modules/passport/lib/middleware/authenticate.js:254:22
at IncomingMessage.req.login.req.logIn (/Users/pierre/Desktop/Work/GitHub/alenvi-bot/node_modules/passport/lib/http/request.js:63:13)
at Strategy.strategy.success (/Users/pierre/Desktop/Work/GitHub/alenvi-bot/node_modules/passport/lib/middleware/authenticate.js:235:13)
at verified (/Users/pierre/Desktop/Work/GitHub/alenvi-bot/node_modules/passport-oauth2/lib/strategy.js:177:20)
at Strategy.FacebookStrategy [as _verify] (/Users/pierre/Desktop/Work/GitHub/alenvi-bot/app.js:82:12)
at /Users/pierre/Desktop/Work/GitHub/alenvi-bot/node_modules/passport-oauth2/lib/strategy.js:193:24
at /Users/pierre/Desktop/Work/GitHub/alenvi-bot/node_modules/passport-facebook/lib/strategy.js:181:5
at passBackControl (/Users/pierre/Desktop/Work/GitHub/alenvi-bot/node_modules/oauth/lib/oauth2.js:134:9)
at IncomingMessage.<anonymous> (/Users/pierre/Desktop/Work/GitHub/alenvi-bot/node_modules/oauth/lib/oauth2.js:157:7)
at emitNone (events.js:91:20)
at IncomingMessage.emit (events.js:185:7)
at endReadableNT (_stream_readable.js:974:12)
(picture here: https://puu.sh/vQPNb/917c710ff8.png )
I nearly copy / pasted your Facebook example, just removing Luis, and using Express instead of Restify.
I start by saying 'profile', then I click on 'connect', and then I have the error I described above. I have to cancel after.
(picture: https://puu.sh/vQQ7A/1a37693288.png)
Here is a bit of code:
var ba = new botauth.BotAuthenticator(app, bot, {
baseUrl: "https://" + WEBSITE_HOSTNAME, secret: BOTAUTH_SECRET
}).provider("facebook", (options) => {
return new FacebookStrategy({
clientID: process.env.FACEBOOK_APP_ID || FACEBOOK_APP_ID,
clientSecret: process.env.FACEBOOK_APP_SECRET || FACEBOOK_APP_SECRET,
callbackURL: options.callbackURL,
profileFields: ['id', 'emails', 'name', 'photos']
}, (accessToken, refreshToken, profile, done) => {
profile.accessToken = accessToken;
profile.refreshToken = refreshToken;
console.log(profile);
return done(null, profile);
});
});
console.log(profile);
code displays well all what I need in my console. So it seems to nearly work !
But:
bot.dialog("/profile", [].concat(
ba.authenticate("facebook"),
function(session, results) {
//get the facebook profile
var user = ba.profile(session, "facebook");
//var user = results.response;
console.log(user);
console.log("hello");
}
));
console.log(user);
and console.log("hello");
don't log anything (because it's in response of the callback I suppose)
Can you help me ? I feel really lost, after an entire day on this.
Do not hesitate to tell me if you need something more.
Thank you,
Pierre
The logout functionality is not shown in any samples as compared to that of AuthBot.
On seeing the code, this function does the logout
public async Task Logout(AuthenticationOptions authOptions, IDialogContext context)
{
context.UserData.RemoveValue($"{this.Name}{ContextConstants.AuthResultKey}");
context.UserData.RemoveValue($"{this.Name}{ContextConstants.MagicNumberKey}");
context.UserData.RemoveValue($"{this.Name}{ContextConstants.MagicNumberValidated}");
string signoutURl = "https://login.microsoftonline.com/common/oauth2/logout?post_logout_redirect_uri=" + System.Net.WebUtility.UrlEncode(authOptions.RedirectUrl);
await context.PostAsync($"In order to finish the sign out, please click at this [link]({signoutURl}).");
}
But on calling it, and clicking the link replied back, I get the following error message in browser:
Hi there, loving BotAuth, makes account linking a (relative) breeze! Just wondering if firstly, there are any plans to make it possible to use multiple authentication options in the dialog, which could be displayed using a carousel or something?
Also, can I set custom authentication text for the card, button and dialog?
Teams on the iPhone shows a blank message when authorization is required - the card is visible on the desktop platform, just doesn't render on the phone. Swapping the card type generated in AuthDialog.PromptToLogin to a HeroCard instead of a SigninCard does seem to be a workround - the card and login button render.
I wonder how the middleware works in bots that are not web-based (for example a Facebook or a Skype bot that wants to use oauth to authenticate the user).
The signin option does not work in 1:1 / private conversations. It works from within a teams channel. The signin card displays, but am not able to click the sign in button.
I think the problem is in the region of line 81 of botauth/dialogs/authdialog.cs, which strips off the Teams at-mention in a group chat. For 1:1 chats, there's no but there is extra whitespace around the number. I think a fix might be to always Trim() the message text, whether there's an or not.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.