setting js azure app service custom login authentication - javascript

I started implementing 2 years ago my custom authentication in azure mobile service with node.js to use it in my jquery/cordova appery.io app. I have a database with users, passwords, etc and a login api in node.js backend that generates a valid jwt like this:
http://www.thejoyofcode.com/Exploring_custom_identity_in_Mobile_Services_Day_12_.aspx
http://chrisrisner.com/Version-1-of-the-Mobile-Services-JWT-token-has-been-deprecated
But now i have been migrated to azure app service and don´t know how to implement custom authetication with javascript.
At the examples above:
"iss":"urn:microsoft:windows-azure:zumo",
"ver":2,
"aud":aud,
But i have read that "aud" and "iss" must be my azure website and "sub" my own userId, to generate a valid jwt in my custom auth to use it in azure. Is it right?
https://shellmonger.com/2016/04/08/30-days-of-zumo-v2-azure-mobile-apps-day-5-custom-authentication/
The important thing is the token. There are some requirements for using 3rd party tokens with an Azure Mobile App:
It must follow the Json Web Token format
The user Id must be in the subject (sub) field
The audience (aud) and issuer (iss) must be known and configured
I do a call to my login API with ajax post and obtain a valid JWT token (http://jwt.io), but i don´t know the correct process to login and use azure services because i don´t know the correct way to use it on my app. I have changed MobileServices.Web.min.js to azure-mobile-apps-client.js in the app.
https://github.com/Azure/azure-mobile-apps-js-client
Can i use the jwt token created in azure node.js or exchange it for a session token and use client.login() method by JS SDK?
EDIT:
I see the light again adding to ajax POST
headers: {'X-ZUMO-AUTH': usuarioToken},
So my "authenticated users only" api works again with the old MobileServices.Web.min.js! It also works perfect with invokeApi method:
var mobileClient = new WindowsAzure.MobileServiceClient(urlApp,keyApp);
mobileClient.currentUser = {
userId: myCustomUserId,
mobileServiceAuthenticationToken: myCustomToken
};
mobileClient
.invokeApi('data', {
method: 'POST',
headers: {'X-ZUMO-AUTH': myCustomToken},
body: JSON.stringify(theData)
}) //end invokeApi
.done(
function (response) {
alert(response);
},
function (error) {
alert("error"));
}
); //end done
The mobileClient generated contains this data:
mobileClient= {"applicationUrl":"https://xxx.azure-mobile.net/","applicationKey":"hGhzxxx","version":"ZUMO/1.2 (lang=Web; os=--; os_version=--; arch=--; version=1.2.21003.0)","currentUser":{"userId":"Custom:25F600BB-xxxx-xxxx-xxxx-8329BCCF31D2","mobileServiceAuthenticationToken":"ey__rest of jwt token"},"_serviceFilter":null,"_login":{"_loginState":{"inProcess":false,"cancelCallback":null},"ignoreFilters":true},"push":{"_apns":null,"_gcm":null,"_registrationManager":null}}
I will try again wiht the new azure-mobile-apps-client.js
Any comment will be welcome

Related

NotAllowedException when reading feeds on the client

Hi I'm new to GetStream and still learning. Here is a condensed version of what I'm using.
I have a python backend where I create user tokens:
client = stream.connect(...)
token = client.create_user_token(id)
return token
I then pass the token to the js frontend where it's used to retrieve feed activities for that user. I'm using the normal stream-js client and Jinja for the token and collection.id:
const client = stream.connect('apiKey', null, 'appID');
const collection = client.feed('collection', '{{ collection.id }}', '{{ token }}')
request = collection.get({ limit:10})
request.then((data) => {
...
)}
Here is my problem:
When I request activities for collection:4 everything works as would be expected. But when I do the exact same thing for collection:5 it suddenly gives
"You do not have permission to do this, you got this error because there are no policies allowing this request on this application." 403 NotAllowedException.
This only happens client-side, server-side it works fine. Could there be a problem in the jwt token used for authentication?
Thanks for any help.
By default, users can read their own feeds on the client side.
collection:4 is working because probably token is generated for the user with id 4 and it fails with permission error when that token is used for collection:5.
To have required policies in your app, please contact support with your app details and required policies/feed groups.

Migrating master user to service principal for authentication on power bi embedded

I'm trying to migrating my authentication method from Power BI Master User to service principal.
on master user I'm using msal with authentication flow like bellow:
login to AAD --> request for AAD token --> importing pbix file with rest API using AAD token as credential
this is the code
$(document).ready(function () {
myMSALObj.loginPopup(requestObj).then(function (loginResponse) {
acquireTokenPopup();
});
Msal.UserAgentApplication
});
function acquireTokenPopup() {
myMSALObj.acquireTokenSilent(requestObj).then(function (tokenResponse) {
AADToken = tokenResponse.accessToken;
importPBIX(AADToken);
});
}
function importPBIX(accessToken) {
xmlHttp.open("GET", "./importPBIX?accessToken=" + accessToken + "&pbixTemplate=" + pbixTemplate, true);
//the rest of import process//
}
so there are two question:
1. what kind of flow would it be if I use service principal instead?
on my head and from the info which I read from microsoft document it would be simpler like:
request token using application secret key --> importing pbix file with rest API using token
is this correct?
2. what kind of code that I can use to do this on javascript?I think MSAL couldn't do token request by using service principal. would appreciate any info or tutorial for this.
bests,
what kind of flow would it be if I use service principal instead? on my head and from the info which I read from microsoft document it would be simpler like: request token using application secret key --> importing pbix file with rest API using token is this correct?
According to my research, if you want to use the service principal to get Azure AD access token, you can use the client credentials grant flow
The client application authenticates to the Azure AD token issuance endpoint and requests an access token.
The Azure AD token issuance endpoint issues the access token.
The access token is used to authenticate to the secured resource.
Data from the secured resource is returned to the client application.
Regarding how to get access token, please refer to the following steps
Register Azure AD application
Configure API permissions
Get access token
POST https://login.microsoftonline.com/<tenant id>/oauth2/token
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_id=<>
&client_secret=<>
&resource=https://analysis.windows.net/powerbi/api
2. what kind of code that I can use to do this on javascript?I think MSAL couldn't do token request by using service principal. would appreciate any info or tutorial for this.
If you want to implement client credentials grant flow with sdk, you can use adal-node. For more details, please refer to https://www.npmjs.com/package/adal-node.
For example
var AuthenticationContext = require('adal-node').AuthenticationContext;
var authorityHostUrl = 'https://login.microsoftonline.com/';
var tenant = 'myTenant.onmicrosoft.com'; // AAD Tenant name.
var authorityUrl = authorityHostUrl + '/' + tenant;
var applicationId = 'yourApplicationIdHere'; // Application Id of app registered under AAD.
var clientSecret = 'yourAADIssuedClientSecretHere'; // Secret generated for app. Read this environment variable.
var resource = ''; // URI that identifies the resource for which the token is valid.
var context = new AuthenticationContext(authorityUrl);
context.acquireTokenWithClientCredentials(resource, applicationId, clientSecret, function(err, tokenResponse) {
if (err) {
console.log('well that didn\'t work: ' + err.stack);
} else {
console.log(tokenResponse);
}
});
thanks to Jim's answer, I've tweaked my code a little bit and the token authentication process went smoothly.
As my apps using javascript at front-end and python as its back-end, I decided to do the process at python and used python msal library instead.
the code is just like :
authority_host_uri = 'https://login.microsoftonline.com'
tenant = 'myTenantId'
authority_uri = authority_host_uri + '/' + tenant
client_id = 'myClienId'
client_secret = 'myClientSecretKey'
config={"scope":["https://analysis.windows.net/powerbi/api/.default"]}
app = ConfidentialClientApplication(client_id, client_credential=client_secret, authority=authority_uri)
token = app.acquire_token_for_client(scopes=config['scope'])
once again thanks to Jim for helping me on this one.
bests,

Skype Web SDK - Maintain a user session

I am using Skype Web SDK to get a user's contact list in the following manner.
Skype.initialize({
apiKey: 'a42fcebd-5b43-4b89-a065-74450fb91255',
}, function (api) {
var Application = api.application;
var client = new Application();
client.signInManager.signIn({
username: sip,
password: pwd
})
This works fine when I provide the username(sip) and password. However, when I reload the page, I have to provide the credentials again because the app re-initializes. Is there a way to maintain the user's sessions for a while after the initial login so that the page refreshes wouldn't need ask for credentials again?
I have looked through the samples and docuementation that Microsoft has and couldn't find a way. I've also tried to store the client object in the localStorage after the initialization and sign in, but when I tried to reuse the object from localStorage to get the contact list, it did not work.
http://officedev.github.io/skype-docs/Skype/WebSDK/model/api/interfaces/jcafe.signinmanager.html#signin last example explains that you can store oauth token and use it as unexpired token.
To connect to an existing app's event channel, specify id of that app:
sm.signIn({
username: "user1#company.com",
password: "password1",
id: "273867-234235-45346345634-345"
});
To sign in to Skype for Business Online using OAuth while handling the
logic of retrieving OAuth tokens yourself:
sm.signIn({
client_id: '123-456',
origins: [ 'https://webdir.online.lync.com/AutoDiscover/AutoDiscoverservice.svc/root' ],
cors: true,
get_oauth_token: function(resource) {
// Return a valid unexpired token for the specified resource if you already have one.
// Else, return a promise and resolve it once you have obtained a token.
return 'Bearer eyJ0e...';
}
});

Unable to query Google Search Console API using a Service Account

I need to retrieve some data from Google Search Console (Webmaster Tools) using a service account.
So far I've been able to retrieve an access_token for the service account which I need to append to the url of the request. The problem is that I can't find a way to do so, this is the code i'm using:
function retrieveSearchesByQuery(token)
{
gapi.client.webmasters.searchanalytics.query(
{
'access_token': token,
'siteUrl': 'http://www.WEBSITE.com',
'fields': 'responseAggregationType,rows',
'resource': {
'startDate': formatDate(cSDate),
'endDate': formatDate(cEDate),
'dimensions': [
'date'
]
}
})
.then(function(response) {
console.log(response);
})
.then(null, function(err) {
console.log(err);
});
}
This is the url called by the function:
https://content.googleapis.com/webmasters/v3/sites/http%3A%2F%2Fwww.WEBSITE.com/searchAnalytics/query?fields=responseAggregationType%2Crows&alt=json"
Instead it should be something like this:
https://content.googleapis.com/webmasters/v3/sites/http%3A%2F%2Fwww.WEBSITE.com/searchAnalytics/query?fields=responseAggregationType%2Crows&alt=json&access_token=XXX"
The gapi.client.webmasters.searchanalytics.query doesn't recognize 'access_token' as a valid key thus it doesn't append it to the url and that's why I get a 401 Unauthorized as response.
If I use 'key' instead of 'access_token' the parameter gets appended to the url but 'key' is used for OAuth2 authentication so the service account token I pass is not valid.
Does anyone have a solution or a workaround for this?
If your application requests private data, the request must be authorized by an authenticated user who has access to that data. As specified in the documentation of the Search Console API, your application must use OAuth 2.0 to authorize requests. No other authorization protocols are supported.
If you application is correctly configured, when using the Google API, an authenticated request looks exactly like an unauthenticated request. As stated in the documentation, if the application has received an OAuth 2.0 token, the JavaScript client library includes it in the request automatically.
You're mentioning that you have retrieved an access_token, if correctly received, the API client will automatically send this token for you, you don't have to append it yourself.
A very basic workflow to authenticate and once authenticated, send a request would looks like the following code. The Search Console API can use the following scopes: https://www.googleapis.com/auth/webmasters and https://www.googleapis.com/auth/webmasters.readonly.
var clientId = 'YOUR CLIENT ID';
var apiKey = 'YOUR API KEY';
var scopes = 'https://www.googleapis.com/auth/webmasters';
function auth() {
// Set the API key.
gapi.client.setApiKey(apiKey);
// Start the auth process using our client ID & the required scopes.
gapi.auth2.init({
client_id: clientId,
scope: scopes
})
.then(function () {
// We're authenticated, let's go...
// Load the webmasters API, then query the API
gapi.client.load('webmasters', 'v3')
.then(retrieveSearchesByQuery);
});
}
// Load the API client and auth library
gapi.load('client:auth2', auth);
At this point, your retrieveSearchesByQuery function will need to be modified since it doesn't need to get a token by argument anymore in order to pass it in the query. The JavaScript client library should include it in the request automatically.
You can also use the API Explorer to check what parameters are supported for a specific query and check the associated request.
If you need to use an externally generated access token, which should be the case with a Service Account, you need to use the gapi.auth.setToken method to sets the OAuth 2.0 token object yourself for the application:
gapi.auth.setToken(token_Object);

Can an access token returned by Facebook to the Javascript SDK work server-side with the PHP SDK?

I'm building a website that makes use of Facebook connect. I'm authenticating users client-side with the javascript SDK and calling an AJAX method on my server every time a user logs in to check if the user is known to my app, and if the user is new to store their FBID in my database to register them as a new user.
My question is: Can the access token returned by Facebook to the Javascript SDK be used server-side (with the PHP SDK for example)? Can I send the access token string to the server via an AJAX call, store it in my database (along with a timestamp so I know how long it's valid for) and then use it to make calls to the graph API server-side? Is this even a logical thing to do?
Yes, this should work. Look at this question: How to properly handle session and access token with Facebook PHP SDK 3.0?
This is a workaround for the old JS and new PHP SDK. In my app I send the access token generated by the JS SDK via a form to my PHP. I have no doubts that this also works by sending the access token via ajax!
Using Jquery:
//Set an error message
var oops = ("Put your something went wrong message here.");
//Function to post the data to the server
function save(uid, accessToken){
$.post("../foo/bar", { uid: uid, access_token: accessToken, etc, etc }, function(data){
alert("Successfully connected to Facebook.");
location.reload();
}, "text");
}
function handler(x){
if (x.authResponse){
var token = x.authResponse.accessToken;
var uid = x.authResponse.id;
FB.api("/me/accounts", {access_token: token},
function(response){
if(response.data.length == 0) {
//Regular facebook user with one account (profile)
save(uid, token);
}else{
//Handle multiple accounts (if you want access to pages, groups, etc)
}
});
}else{
alert(oops);
}
}
FB.login(handler, {scope: 'The list of permissions you are requesting goes here'});
Any improvement suggestions are always appreciated.

Categories