Secure authentication JS Client and Azure App - javascript

I have a JS client side application that sends a POST request to an Azure Endpoint, using hardcoded SPA client_id and most importantly client_secret as displayed below:
function(request, sender, sendResponse) {
let data = new FormData();
data.append('client_id', "xxx");
data.append("client_secret", "xxxx");
data.append("grant_type", "password");
data.append("scope", "https://management.azure.com/user_impersonation");
data.append("username", request.usr);
data.append("password", request.pass);
const myHeaders = new Headers({
Accept:"application/json"
});
let resp = fetch(url, {
headers : myHeaders,
method: "POST",
body: data,
mode: 'cors'
}).then( (response) => {
// do some stuff
})
}
I need to protect these secrets as they should never be accessed by the client directly, so i have created a backend node server in Azure, that listens for the JS client.
But i'm confronted to the same problem again :
How to authenticate the JS client app so that only it, can post requests to the node Azure service, without storing a secret / certificate in the client side ?
As of now the node service is only accessible through authenticated accounts, but if i have to load a token in the JS client again, i go back to the original problem ...
Is there a different way to look at this problem ? Or an other techique to achieve this sort of flow ?

The standard way to retrieve access tokens to call backend services from a client side app is to use an authorization code flow. Usually you'll use a library for this, such as MSAL.
Using authorization code flow, the user will go through the Oauth login process, and you'll write code to request an access token on the user's behalf using their security context.
The user will have to have access to the resources in question, and in AAD you'll have to enable the API permissions for management.azure.com.

Related

Using GitHub's REST API to list public repos from my external site deletes my token

I am trying to list my GitHub public repos on my public website using their REST API. I have been creating personal tokens so far. In localhost it works.
When I do the request from my site it responds a 401 and it deletes my token.
To get the repos I am doing this simple request:
async function loadRepositories() {
const token = 'my_token';
const response = await fetch("https://api.github.com/users/tauromachian/repos",
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
},
}
);
const repositories = await response.json();
return repositories;
},
How can I get this done?
Github is trying to protect you from someone stealing your identity here. There are ways to detect if a HTTP request is sent from the browser or a server (it's not 100% reliable though).
As you make the request from the browser which is a public client, meaning everyone can read the code and hence secrets you use within the code you are exposing your Personal Access Token (PAT). This PAT identifies you against Github, therefore if someone else could get hold of it, they can impersonate you and e.g. delete repos, steal code etc. (if the token has the correct scopes).
As Github wants to prevent that from happening, they delete tokens which are publicly exposed (they know it's exposed as the the request comes from a browser). Therefore attacks like that are not possible anymore.
To make your website work however you can simply make the request from your server as you can securely store secrets on the server-side and call the endpoint of your server from your website. Once you do that, Github won't delete the token, your token is save and you can display the data on the website.

How to extract status code of a protected web page with Node.js backend?

I am trying to only access a webpage's returned status code but the page is proctected by a login process. I already have the credentials but I cannot directly send http request and see the status code because it returns HTML of login page. I need to find a way such that when I send http request to that web service, it should go through those login process and return me only status code. An advised way is that using scripted browser, but still even if I successfully login to that page and display it, how can I send status code to my local backend ?
If the logon process consists of just giving the correct username and password, you can "fake" it with a single request like
fetch("https://protected.page/login", {
method: "POST",
headers: {"content-type": "application/x-www-form-urlencoded"},
body: "username=you_know_it&password=you_know_it&submit=Logon"
}).then(response => response.status);
But if login involves one-time tokens or captchas, this is of course not sufficient.

Access token getting 401 from Adal.JS for Azure Data Catalog

I am building an angular web application using ADAL.js that accesses other Azure APIs and I am successful in accessing custom web API, Power BI API, and the Graph API. Unfortunately I am unable to access the Azure Data Catalog, I am acquiring the token like all the other services by requesting by resource URI. I have added the users and the app service principal name as Catalog Users and the app registration has Azure Data Catalog delegated access. Below is the code that I use to get the token and then I attach it to the header like I do for the other APIs. This is the only Azure API I have had problems accessing. Thanks in advance if anyone is able to help.
var token = authContext.acquireToken('https://api.azuredatacatalog.com')
If you want to call the Azure Data Catalog rest api with adad.js, please refer to the following steps
Register an Azure AD application
Configure permissions
Code
var resource ="https://api.azuredatacatalog.com"
authContext.acquireToken(resource, function (error, token) {
// Handle ADAL Error
if (error || !token) {
printErrorMessage('ADAL Error Occurred: ' + error);
return;
}
// Get TodoList Data
$.ajax({
type: "GET",
url: "https://api.azuredatacatalog.com/catalogs/{catalog_name}/search/search?api-version={api-version}&searchTerms={search_terms}",
headers: {
'Authorization': 'Bearer ' + token,
},
});

Correct way to store this token

I'm writing my first flask app and using the spotify api. I want to pass the access token from this api into java script like so
var token = "{{ token }}";
fetch('https://api.spotify.com/v1/me/player/currently-
playing', {
headers: {
'Authorization': `Bearer ${token}`
}
I'm doing this outside the flask app so I can frequently update the json data to the webpage easier. This method doesn't seem secure so I was wondering what is the perferred method in a situation like this.
Since your example is almost literally straight out of the Spotify Authorization Documentation and it is in relation to accessing the Web API, you're good.
If you were auth'ing on behalf of a user for more serious actions then you wouldn't be making client side requests.
Since the token you're using can be revoked and does in fact expire, you can store it in your db in plaintext.
You can store keys/secrets using Microsoft's Azure Software. Once you register you'll have access to those resources. You can set the secret in the secrets file in your azure portal and reference the secrets from there in your application source code.

Using IdentityServer3 with Single Page App (UseIdentityServerBearerTokenAuthentication)

Background
I'm using these technologies to secure a WebApi application:
ThinkTecture.IdentityServer3
OWIN (Azure)
Single page app - javascript client
Refer to the Simple OAuth2 Walkthrough sample (github)
In the sample above the .NET console app client requests a token from IdentityServer and uses it to access the WebApi application. This works fine in the sample.
I want to change the .NET console app Client to a javascript single page app Client. I have tried adding a proxy login controller that does the request to IdentityServer on behalf of the javsacript Client and returns the token back to the client in a cookie.
Code
[HttpPost]
[Route("login")]
public HttpResponseMessage Login(LoginRequest request) // Proxy to IdentityServer3
{
var tokenClient = new TokenClient(
"https://localhost:44333/connect/token",
"javascript client",
"client secret");
var tokenResponse = _tokenClient.RequestResourceOwnerPasswordAsync(request.username, request.password, "api1").Result;
var cookie = new CookieHeaderValue("access_token", tokenResponse.AccessToken);
cookie.Expires = DateTimeOffset.Now.AddDays(1);
cookie.Domain = "localhost";
cookie.Path = "/";
var response = new HttpResponseMessage();
response.Headers.AddCookies(new CookieHeaderValue[] { cookie });
return response;
}
I get the access token back successfully in the javascript client, however the API doesn't recognise it.
Question
How should I pass the a token generated by IdentityServer to the javascript application, and how do I use it to access the WebApi?
Let's say your token end point is "https://localhost:44333/connect/token" (as you have mentioned). Hitting that endpoint with a POST request with a body like the following will return a token:
grant_type=password&client_id=youtclientid&client_secret=yourclientsecret&username=yourUserName&password=YourPassword&scope=list_of_requested_scopes
You use a JS variable to store your token, and then in order to use that token to access protected APIs, you have to send it as part of the header in the request, similar to the following: In your request's header, you will have:
Authorization: Bearer eyJ0eXAiOiJKV...
where "eyJ0eXAiOiJKV..." is the token you received in the first step.
Using oidc-client.js or creating something similar on those lines as the size of this js library is large.
Check this link out.
https://github.com/IdentityModel/oidc-client-js/tree/master/sample
and the video
https://vimeo.com/131636653
We are using the IdentityServer infrastructure to get to initial login and then the token(s) id/access for all further communications.

Categories