So I am building a face recognition based login system. I am using React on the Frontend and a Python based API for the backend.
I am using the "react-webcam" package to click a photo of the user and sending it to the backend endpoint to login. The code for this is
const face_uri = face.canvas.toDataURL("image/jpeg")
const request = new Request('/api/login',{
method: 'POST',
body: JSON.stringify({
face:face_uri
}),
headers: {
accept: 'application/json',
},
})
const response = await fetch(request);
I do face detecting and matching on the server side and return a JWT if a face is found and matched.
My problem is anyone could get a base64 encoded image of another person and post that to my endpoint '/api/login' and gain access to someone else's account.
How do I ensure that the image being sent to the backend was clicked right now from the camera?
Please let me know of any suggestions you have, even if it involves using a completely different approach, language, framework etc.
Related
I'm making the front of an app in react and i need to upload images to cloudinary passing the key and secret. I tried this:
function handleFiles(files) {
const url = CLOUDINARY_URL
const formData = new FormData()
formData.append("file",files[0])
formData.append('upload_preset',IMAGE_FOLDER)
fetch(url,{
method: "POST",
//headers: {
// 'Authorization': 'Basic ' + CLOUDINARY_KEY + ":" + CLOUDINARY_SECRET,
//},
body: formData
}).then(response => {console.log("resp ",response); return response.text()})
.then(data => console.log("data ", data))
}
This code works fine with a cloud name that doesn't need authorization but when i uncomment the header part give me the next error
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at CLOUDINARY_URL. (Reason: header ‘authorization’ is not allowed according to header ‘Access-Control-Allow-Headers’ from CORS preflight response)
How can i achieve this? Or is there other way to upload images from react?
Thanks in advance.
Cloudinary Upload API does not use Basic Authorization method to signed your upload. However it can be uploaded using Signed Upload preset that signed with your backend or unsigned upload preset. I suggest to check their documentation to learn the difference.
The easiest to upload via web, although it's not specific to React, is to use Cloudinary's Upload Widget. This is JavaScript based solution that you can integrate with your React App
On a last note, just keep in mind that your API credential, specifically API Secret should be treated as if it's your password. Since React is a client-side application, you should not put your API secret there.
I have created a simple REACT application that is ONLY run on a local PC attached to a large screen on our network. Internal use only! It is like a billboard or dashboard. There is ZERO user interaction. The screen is NOT a touch screen and there is no keyboard and mouse attached. Therefore NO users to login.
The REACT application is build and then deployed to a folder on the PC. All automated. The initial deployment includes all current data. Then at windows startup a command something like this is executed:
"python -m http.server 3000" (just example...)
The application has initial data that was deployed with the application, however, I would like it to also be able to call a secure Azure WebAPI service to get updated statistics every few minutes. Very small data. Mostly integer values. I just want to provide some real time updates.
I have the REACT app fully working (if the WEBAPI is not secure) or the individual calls allow anonymous. However, we have business rules that require all endpoints to be secure.
This app runs locally, but the API is an Azure App Service.
I have setup the REACT application in Azure AD as a registered application and configured it to have permissions to call the WEBAPI service.
I have many console applications that are setup and work basically the same way as this REACT application. With the C# daemon applications, there is a MSAL package that makes it easy.
I am trying to learn REACT, and instead of building this as another WPF or UWP application, I wanted to try using REACT.
So, I know I need an access token somehow. I was thinking with a client ID and Secret just like I do in my C# daemon clients that are written in C#.
I cannot find any REACT nor Angular examples that do this without a user login first. Remember, the PC does not have input devices. Display ONLY. Again, my app does not have users. It calls a secure API to get data. That's it.
Thanks for your help.
Using Joy Wang's comments and this page from documentation:
Service-to-Service Access Token Request
This is my new code:
const adalConfig = {
tenant: '...',
clientId: '...',
clientSecret: '...',
authority: 'https://login.microsoftonline.com/{tenant}/oauth2/token',
endpoints: {
apiResourceId: 'api://bbbbbb-...',
},
};
function getAccessToken() {
var requestParams = {
grant_type: 'client_credentials',
client_id: adalConfig.clientId,
client_secret: adalConfig.clientSecret,
resource: adalConfig.endpoints.apiResourceId
};
// Make a request to the token issuing endpoint.
fetch(adalConfig.authority,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify( requestParams )
}).then(response => {
if (response.status >= 200 && response.status < 300) {
console.log(response);
console.log(response.json());
} else {
console.log('Somthing happened wrong');
console.log(response);
}
}).catch(err => err);
}
When I call the function above, I get the following response:
Response {type: "cors", url: "https://login.microsoftonline.com/.../oauth2/token", redirected: false, status: 400, ok: false, …}
body: (...)
bodyUsed: false
headers: Headers {}
ok: false
redirected: false
status: 400
statusText: "Bad Request"
type: "cors"
url: "https://login.microsoftonline.com/.../oauth2/token"
proto: Response
Maybe there is another way to start the REACT application so that CORS is not checked? Any ideas?
Thanks again.
So, currently there is not a secure way to do what I want. The basic issue is that you cannot use the client credential grant type from JavaScript in a browser.
However, I think I have a good work around that may help others. I am sure it is NOT for most application. And I believe OAUTH is working on a solution so this may not be needed in the near future. If a better solution is add, I will gladly mark it as the correct answer. Thanks for your help.
My app is basically an automated dashboard/billboard with ZERO user input. It pulls secure data and displays it. The REACT application is ONLY on a LOCAL PC on a wall with NO inputs. A script runs when the PC is turned on.
The script starts the built REACT application using an http server like python.
Ex: "python -m http.server 8000"
The script then opens the browser in kiosk mode so the only thing you see on the screen is the application.
So far, this is exactly as I had it before.
WORK AROUND:
I created a command line utility called GetToken. Before the REACT application is started by the script, it calls this utility like so: "gettoken --client Dashboard --file token.json"
This utility makes the Client Credential Grant Type call to get a token.
It then saved that token to a local json file with the other built REACT files. Ex: \public\data\token.json
In my REACT application, it just loads the token and uses it.
const t = await fetch('./data/token.json').then(r => r.json());
this.setState({ token: t.token });
Then I just add this to my api calls like so:
const fetchOptions = {
method: 'GET',
headers: {
"Authorization": `Bearer ${this.state.token}`,
"Content-Type": "application/json"
}
};
const newSlides = await fetch(this.state.baseUrl + '/api/Dashboard/GetSlides', fetchOptions).then(response => response.json());
IMPORTANT: This only works if you also have the ability to update the API. If you cannot, then you will still get CORS errors. You will have to allow calls from the localhost and port you use to start you application. You should pick something other than 3000, 4200, or 8000.
I added the following to my API startup.cs:
public void ConfigureServices(IServiceCollection services) {
...
var origins = Configuration.GetSection("AppSettings:AllowedOrigins").Value.Split(",");
services.AddCors(o => o.AddPolicy(specificOriginsPolicy, builder => {
builder.WithOrigins(origins)
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
.SetIsOriginAllowed((host) => true);
}));
...
}
public void Configure(IApplicationBuilder app) {
...
app.UseCors(specificOriginsPolicy);
...
}
I am still refining this solution, but it works well so far. I may turn the utility into a background service that is updating the token on an interval. Or I may turn the utility into a Shell, and then use it instead of the script. Either way, you get the idea.
LESSON:
I know I could have done this as a UWP or WPF application and avoided all these issues, but the main goal was to learn REACT. I learned a lot. I would do it again. It is shocking just how little code there is to my REACT application now that it is done. I believe REACT could be used for many similar scenarios.
You could refer to this sample, it uses client credential flow(i.e. client id and secret you want) to get the access token, just change the resource to the one you want to get token for, the sample gets the token for Microsoft Graph.
auth.getAccessToken = function () {
var deferred = Q.defer();
// These are the parameters necessary for the OAuth 2.0 Client Credentials Grant Flow.
// For more information, see Service to Service Calls Using Client Credentials (https://msdn.microsoft.com/library/azure/dn645543.aspx).
var requestParams = {
grant_type: 'client_credentials',
client_id: config.clientId,
client_secret: config.clientSecret,
resource: 'https://graph.microsoft.com'
};
// Make a request to the token issuing endpoint.
request.post({ url: config.tokenEndpoint, form: requestParams }, function (err, response, body) {
var parsedBody = JSON.parse(body);
console.log(parsedBody);
if (err) {
deferred.reject(err);
} else if (parsedBody.error) {
deferred.reject(parsedBody.error_description);
} else {
// If successful, return the access token.
deferred.resolve(parsedBody.access_token);
}
});
return deferred.promise;
};
I'm currently working on a Next.js (React) project, where I use Firebase Auth for authentication. I use this to connect to a REST API back-end, which receives the user token Firebase provides (via getIdToken()).
Because the IdToken changes every now and then, I'm currently reqesting the latest IdToken before sending a fetch request like this:
const fetcher = (url: string) => {
return user.getIdToken().then((token) =>
fetch(url, {
method: "GET",
headers: new Headers({
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
}),
}).then((res) => res.json())
);
};
This setup actually works, but I was wondering if it's considered efficient/best-practice?
I see a lot of examples out there where the IdToken is used to set a cookie (eg. firebase docs, next.js example).
I could see why when using SSR, since getIdToken() can't be called there. But my application only uses client-side data fetching. Would there be any benefits for me moving away from my current approach to using cookies?
The Firebase Authentication SDK already caches the token in local storage, so there's no need for you to cache it elsewhere again.
In fact, the token is refreshed every hour, and the Firebase Authentication SDK refreshes it automatically in the background. If you cache the token yourself, you might end up using an outdated token.
So I'd recommend always calling getIdToken() when you need the ID token. Of course it's fine to store it in a variable, and use that in a single code block (code that runs at pretty much the same time).
Using a cookie to pass the token to your server is fine, as is using the Authorization header as you do now. The latter is more common, but a cookie works too.
Let say i have a post api call like this
fetch('https://mywebsite.com/endpoint/', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
firstParam: 'yourValue',
secondParam: 'yourOtherValue',
}),
});
can some one decode this android react app via dex2jar and something like this and snipe the apis calls..
how can we secure the api calls via server side auth and also from snipping
Yes it is possible, since your browser will show each call done by your app, using chrome you could openthe chrome dev tools and have a look at the network tab.
However there is many way to protect this (you cannot hide it, but you could definetly protect it from unwanted access), probably the most popular are this two :
Cors
Authorization Header`
Plus someone can always open up the app and take a look at you MAP file and get your keys as well.
We're trying to integrate Yammer on our website, getting and putting posts is done, but we have an issue with getting images.
When the user is logged into Yammer, we can show the images with no problem.
When the user is not logged in to Yammer, the image request will give a 401 Unauthorized.
We tried getting the image blobs dynamically by adding an Authorization header, but CORS will block us this way.
Could anyone give some pointers on how to resolve this issue? Thanks in advance!
var req = {
method: 'GET',
url: 'https://www.yammer.com/api/v1/uploaded_files/123456/preview/IMG-20160413-AA0001.jpg',
headers: {
'Authorization': 'Bearer ' + yammertoken
},
responseType: 'blob'
}
return $http(req)
In the end we created a proxy in our PHP backend which was able to get the images serverside. This circumnavigated the CORS issue.
I would highly suggest not trying to subvert authentication for data. Data such as files live behind authentication in order to ensure that only the users who are allowed to see such data can do so.
Have you explored using https://developer.yammer.com/docs/authentication ?