Is there any way i could inject a logged in github session in a electron window?
let win = new BrowserWindow({
width: 800,
height: 600,
})
win.loadURL('https://www.github.com')
Electron has a Cookies API that you can use to do just this. So for example you would have something like the following, and just set all the cookies you need to. (example taken from documentation)
const cookie = {
url: 'http://www.github.com',
name: 'dummy_name',
value: 'dummy'
}
session.defaultSession.cookies.set(cookie, (error) => {
if (error) console.error(error)
})
Also, when writing a feature such as this make sure you are being secure and responsible. Ensure this does not open a vulnerability for users and that user privacy is being respected.
Related
In the Single Sign-On for Teams
I have the call microsoftTeams.authentication.getAuthToken(authTokenRequest); working; that is, it successfully returns a token resolving to my Azure Active Directory (AAD) successfully. All good. Surprisingly easy. JWT returns with correct audience and scopes (as I have set in my tenant's AAD)
However what I get back when I decode the JWT this seems to just be an Authentication Token, not an Access Token.
Looking at the sample at Task Meow/teams.auth.service.js Does not seem to show how to swap the Auth for the Access Token.
I assume the code will look something like the method getToken() ... but since I have already spent 10+ working days on auth (old ADAL OH MY GOODNESS WAS THIS HORRIBLE) ...
Question:
I was wondering if there are any other good samples of MicrosoftTeams.js Authenticate / Auth Token / MSAL Access token out there?
Anyway, I did solve my problem by the following
Follow TaskMeow example through the abstractions ofauth.service.js > sso.auth.service.js > teams.auth.service.js
As I wanted additional AAD scopes (Files.ReadWrite.All to access the Sharepoint Online files in Teams and Groups.ReadWrite.All - to add Tabs) my getToken() method in teams.auth.service.js is something like the following:
getToken() {
if (!this.getTokenPromise) {
this.getTokenPromise = new Promise((resolve, reject) => {
this.ensureLoginHint().then(() => {
this.authContext.acquireToken(
'https://graph.microsoft.com',
(reason, token, error) => {
if (!error) {
resolve(token);
} else {
reject({ error, reason });
}
}
);
});
});
}
return this.getTokenPromise;
}
Editorial Comment:
Authentication in Microsoft Teams is too difficult
There seems to be many "approaches" in the documentation
The present "SSO" flow still has flaws, and is in "Developer Preview"
If you are an SPA developer it is just too difficult. I am (obviously) not an expert on Authentication -- so current "recipes" are imperative.
This is especially the case if you want more than the default "scopes" as described in Single Sign-on ... and most of the "good stuff" in Microsoft Graph is outside of these default scopes.
Also, this snippet may help.
If you follow the recommended Taskmeow in your Microsoft Teams app, you will get a quick appearance of the Redirect URI (aka /tab/silent-start)
To solve this, adal.js caches the user and access token.
So you can add a check in login()
login() {
if (!this.loginPromise) {
this.loginPromise = new Promise((resolve, reject) => {
this.ensureLoginHint().then(() => {
// Start the login flow
let cachedUser = this.authContext.getCachedUser();
let currentIdToken = this.authContext.getCachedToken(this.applicationConfig.clientId);
if (cachedUser && currentIdToken) {
resolve(this.getUser());
} else {
microsoftTeams.authentication.authenticate({
url: `${window.location.origin}/silent-start.html`,
width: 600,
height: 535,
successCallback: result => {
resolve(this.getUser());
},
failureCallback: reason => {
reject(reason);
}
});
}
});
});
}
return this.loginPromise;
}
Using the Bot Framework w/ Microsoft.Bot.Builder v4.6.3
Is it possible to have users sign in only once using the web-based authentication flow, doesn't matter if they sign in via tabs or via bot conversation? If they sign in via a link from a tab, I'd like to have the bot know about this.
I have tried the following for test, omitting any security checks:
All pages are with the following js files imported:
https://statics.teams.microsoft.com/sdk/v1.4.2/js/MicrosoftTeams.min.js
https://cdnjs.cloudflare.com/ajax/libs/oidc-client/1.9.1/oidc-client.min.js
On load, the tab page executes microsoftTeams.initialize();
Add a button to the tab page:
<button onclick="authenticate()">Authenticate</button>
The authenticate function contains the following:
function authenticate() {
microsoftTeams.authentication.authenticate({
url: window.location.origin + "/tabs/tabAuthStart",
width: 600,
height: 535,
successCallback: function (result) {
// The debug function just displays what's sent to it using document.write()
debug(result);
},
failureCallback: function (reason) {
debug(reason);
}
});
}
The tabAuthStart page contains the following script which is executed on page load:
microsoftTeams.initialize();
const mgr = new Oidc.UserManager({
userStore: new Oidc.WebStorageStateStore(),
authority: '<my-identity-server>',
client_id: '<my-id-srv-client>',
redirect_uri: window.location.origin + '/tabs/tabAuthCallback',
response_type: 'id_token token',
scope: '<my-requested-scopes>',
accessTokenExpiringNotificationTime: 10,
automaticSilentRenew: true,
filterProtocolClaims: true,
loadUserInfo: true
});
mgr.signinRedirect();
After a successful sign in at the identity provider, I'm redirected back to /tabs/tabAuthCallback
On load, the /tabs/tabAuthCallback executes the following code:
microsoftTeams.initialize();
var mgr = new Oidc.UserManager({ userStore: new Oidc.WebStorageStateStore(), loadUserInfo: true, filterProtocolClaims: true });
mgr.signinRedirectCallback().then(function (user) {
// I expected something involving a bot to happen after calling this
microsoftTeams.authentication.notifySuccess({
idToken: user.id_token,
accessToken: user.access_token,
tokenType: user.token_type,
expiresIn: user.expires_at
})
}).catch(function (err) {
microsoftTeams.authentication.notifyFailure("UnexpectedFailure: " + err);
});
The pop-up window is closed and the successCallback function from the tab is executed successfully with the user information that I have sent. However, the bot is not in any way notified about this (as far as I know). I have set a breakpoint in the bot controller action resolved by POST /api/messages but it's never hit.
Do I need to handle this manually? I.e. pass the user info to the back-end? But even if so, how do I know which Teams user to associate this user info (i.e. access token) to?
If this is possible to do in a reliable and secure way, would it also be possible in the opposite direction, i.e. having the user token available to the tab if they have already been authenticated from a bot conversation or a messaging extension? Is there a reliable way to identify a Teams user who's navigating tabs, in order to obtain their access token from the back-end, assuming the back-end already obtained them via the authentication mechanism?
I have developed a PWA application with google and microsoft oauth login integration.Now I want the PWA application to run as windows PWA app in windows mobile and desktop applications, so I tried registering the app using AppX as stated in the following link, https://blogs.windows.com/msedgedev/2018/02/06/welcoming-progressive-web-apps-edge-windows-10/#R6xvoOyZeLza5oGW.97
and ran the application in development mode using PowerShell in windows 10 OS version, the microsoft login works great, However when I try to login using google the application starts loading and exits after some time.[the popup to show the login window also doesn't come up].
Could anyone throw a light on what's happening ?.I researched but I couldn't get any solutions.
Edit
The following API is used for login with google, in the client[react]
gapi.load('auth2', () => {
this.auth2 = gapi.auth2.init({
client_id: constant.CLIENT_ID,
cookie_policy: 'single_host_origin',
scope: constant.SCOPE,
});
});
loginWithGoogle = () => {
const options = {
scope: constant.SCOPE,
};
options.prompt = 'select_account';
this.provider = 'google';
this.auth2.grantOfflineAccess(options).then((data) => {
this.loginUser(data.code);
});
}
Maybe is because your browser´s popup blocker, anyway you could use redirection instead popup mode, using ux_mode option (you have to configure the redirection url on OAuth 2.0 client IDs options)
gapi.load('auth2', () => {
this.auth2 = gapi.auth2.init({
ux_mode: 'redirect',
client_id: constant.CLIENT_ID,
cookie_policy: 'single_host_origin',
scope: constant.SCOPE,
});
});
I'm using Electron (v1.2.7) and I need session cookies to persist between app restarts (for auth).
Is it possible? I know in Chrome when you set "Continue where you left off", the session is kept but not sure if this works the same in Electron.
As a workaround, I tried storing the session cookies also as non session cookies but it failed with a generic error.
Clarification: I'm not setting the session cookies they are set by other webpages during authentication.
The default session is persistent, but if you set cookies using session.defaultSession.cookies.set() you must set the expiration date in order for the cookie to be persisted.
You can persist cookies setting the session and a expirationDate
This example was made on Angularjs
var session = require('electron').remote.session;
var ses = session.fromPartition('persist:name');
this.put = function (data, name) {
var expiration = new Date();
var hour = expiration.getHours();
hour = hour + 6;
expiration.setHours(hour);
ses.cookies.set({
url: BaseURL,
name: name,
value: data,
session: true,
expirationDate: expiration.getTime()
}, function (error) {
/*console.log(error);*/
});
};
PD: A problem that i had was if i didn't persist them, after a fews reloads my cookies get lost. So in this example i'd persist them 6 hours
If you are loading an external webpage, you should be using Electrons <webview> tag to disable nodeintegration and for other security reasons. Using a webview will give you easy access to the Partition attribute which can be set to persist (ex: persist:mypage). You can also set the partition attribute on an Electron window if needed.
I was loading an external webpage and the configuration below worked for me. By default the webpage is configured to use "session cookie" and thats why I change it to "persistent cookie" with expiration date of 2 weeks:
// Modules to control application life and create native browser window
const {app, BrowserWindow} = require('electron')
const path = require('path')
const util = require('util')
function createWindow () {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 700,
height: 500,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
partition: 'persist:infragistics'
},
icon: __dirname + '/assets/favicon.ico',
show:false
})
let cookies = mainWindow.webContents.session.cookies;
cookies.on('changed', function(event, cookie, cause, removed) {
if (cookie.session && !removed) {
let url = util.format('%s://%s%s', (!cookie.httpOnly && cookie.secure) ? 'https' : 'http', cookie.domain, cookie.path);
console.log('url', url);
cookies.set({
url: url,
name: cookie.name,
value: cookie.value,
domain: cookie.domain,
path: cookie.path,
secure: cookie.secure,
httpOnly: cookie.httpOnly,
expirationDate: new Date().setDate(new Date().getDate() + 14)
}, function(err) {
if (err) {
log.error('Error trying to persist cookie', err, cookie);
}
});
}
});
Note: Its important to ensure that you've set the "partition" webPreferences property as well.
A String that sets the session used by the page. If partition starts with persist:, the page will use a persistent session available to all pages in the app with the same partition. if there is no persist: prefix, the page will use an in-memory session
Origin source.
I got an app where I have to show an user profile image.
Some users are logged in by Facebook, so we are saving their Facebook profile image and when I try to render this image with React Native Image component, the image is not displayed.
What I got:
<Image style={ styles.userImage } source={{uri: "http://graph.facebook.com/{userID}/picture?type=small" }} />
And styles:
userInfoContainer: {
flex: 1,
alignItems: 'center',
paddingTop: 30,
paddingBottom: 30,
borderBottomWidth: 1,
borderBottomColor: '#e5e5e5',
backgroundColor: '#ffffff',
},
userImage: {
height: 100,
width: 100,
borderRadius: 50,
marginBottom: 20,
},
I don't know if the problem is that this Facebook image URL doesn't have image extension.
Any help is welcome.
Thanks :)
The issue is that the facebook graph url is not the actual url for where that image is stored. It is a redirect. There is an issue out on the react-native github which is tracking a similar issue (301 redirect). It looks like it is partially solved (working for 301's on iOS).
https://github.com/facebook/react-native/issues/4940
Some more details about this if you're curious:
Facebook gives you the graph url, but actually stores the image elsewhere on a cdn. This lets facebook move assets around without breaking the facebook graph url that they document. The graph url will redirect to the actual url, which means that the graph url returns a 302 (non-permanent redirect).
For example, currently my profile pic would be queried using this url:
https://graph.facebook.com/207537292916369/picture?type=large
But it will redirect (currently) to this actual location:
https://scontent.xx.fbcdn.net/v/t1.0-1/p200x200/15940479_407531822916914_4834858285678282755_n.jpg?oh=a49a86e0e8042e3df27ce3dfe871b958&oe=59327225
Looks like you have to remove one set of quotes from the uri string.
I think the problems lies in the picture url redirection. If you add &redirect=false at the end of your url and you use the url fields in the data object shown, the image should show properly.
I don't know the main reason for that but this workaround should help, even though it means writing more code.
It is possible and easy do this (get user profile's picture) using the Facebook React Native SDK.
1) Import the useful classes for this from react-native-fbsdk.
import { AccessToken, GraphRequest, GraphRequestManager } from 'react-native-fbsdk'
2) Implement the Facebook Graph Request in your method, like 'componentDidMount', as an example.
try {
const currentAccessToken = await AccessToken.getCurrentAccessToken()
const graphRequest = new GraphRequest('/me', {
accessToken: currentAccessToken.accessToken,
parameters: {
fields: {
string: 'picture.type(large)',
},
},
}, (error, result) => {
if (error) {
console.log(error)
} else {
this.setState({
picture: result.picture.data.url,
})
}
})
new GraphRequestManager().addRequest(graphRequest).start()
} catch (error) {
console.error(error)
}
3) Use the value of this.state.picture where you need.
<Image source={ { uri: this.state.picture } } />
I would recommend pass it by props, instead of handling as a stateful resource, but it will depend of your needs.
For those showing up to this thread years later like me, the thing that fixed it for me was just changing the Facebook Graph URL from http to https. React Native was able to display it properly after that.