Securing a restful API verifying clients with JWT - rest

I have a RESTful API using JWT for authentication purposes. The first call I receive from a client is the /login call, with the following payload (no headers)
{
"username" : xxxx,
"password": wwww
}
The server verifies if the user is registered and then returns a signed JWT to the client in order to be received in the next calls.
I wonder if this is secure enough. I don't check anywhere if the client sends me a client id / client secret (like in OAuth) so I cannot verify if this call is from my webapp / apps or if it is an external client which I don't know about. I want to know if it makes sense to implement this behavior using JWT and how to implement it.
(I know how to do it with OAuth2 but I don't want to move now from JWT authentication)
Thank you!

If I understood you correctly, you should create a function somewhat similar to this:
function verify(req, res, next) {
const token = req.header('x-auth-token');
if (!token) {
return res.status(401).json({
msg: 'No token, auth denied'
});
}
try {
const decoded = jwt.verify(token, config.get(YOUR_SECRET_GOES_HERE));
req.user = decoded.user;
next();
} catch (err) {
res.status(401).json({
msg: 'Token is not valid'
});
}
}
For all secured API endpoints you should apply it like this:
router.get('/anyuserinfo', verify, (req, res) => ...
And that is it. The function will send 401 response if no token is provided.

I think I found another Stackoverflow question that answers mine:
JWT (Json Web Token) Audience "aud" versus Client_Id - What's the difference?
In a nutshell, client_id and client_secret should be sent on headers to the server to be validated before sending a new JWT token.

Related

Verify facebook token

I have a client application which authenticates with facebook and returns the token successfully. I would like to persist this data to the server without having to pass the entire object. Instead I would like to pass the resulting token from the client side authentication to my C# api in the authorization header and validate this token on the server.
Question, is it possible to verify the token on the server side? How to do it?
I am doing this via google, and need a facebook equivalent:
var googleResult = GoogleJsonWebSignature.ValidateAsync(
accessToken,
new GoogleJsonWebSignature.ValidationSettings
{
Audience = new[] { "secret key here.apps.googleusercontent.com" }
}
).GetAwaiter().GetResult();

How do I call my Cognito secured RestAPI from the browser when using next-auth?

I have an AWS RestApi secured by AWS Cognito. In addition to this I have a NextJS app using next-auth that provides user authentication against the Cognito User Pool.
I now want to call the RestApi directly from the browser, but cannot find a way to include the proper credentials. Since the only cookies present in my web-app begin with next-auth- I assume they are not suitable for the task.
So, how do I access the access token from the browser?
I ended up hooking up to two callbacks on the NextAuth configuration, like this:
NextAuth({
providers: [
CognitoProvider({
idToken: true,
issuer,
clientSecret,
clientId,
authorization,
}),
],
callbacks: {
session: async function ({ session, token }) {
return {
...session,
bearerToken: token.bearerToken ?? session.bearerToken,
};
},
async jwt({ token, account }) {
token.bearerToken = account?.id_token ?? token.bearerToken;
return token;
},
},
})
From the pages/api/auth/[...nextauth].ts file.
This makes the bearerToken available via the getSession call:
import { getSession } from "next-auth/react";
// ...
const { bearerToken } = await getSession();
You can use application like Postman to pass the Authorization header. I am not sure if your query is about getting the access token or about how to use the access token.
In order to get the access token and then to call your REST API, you need to have a server. Suppose you have your server with domain name "example.com". Then, put this server name in the callback URL of your Cognito user pool's app client.
After user authentication, Cognito will send the access token to "example.com". Then, you server will have the responsibility to correctly call the REST API with the access or ID token provided by Cognito.
For testing purpose, you can manually get the access token after authenticating with Cognito. Then, you can use application like Postman to make HTTP calls to your REST API endpoint with the access token. Put the token as value to the authorization header.

Error 401 (Unauthorized) When making REST calls using Axios with JWT headers included

I'm developing a small react node application with JWT passport for authentication. I've tested all the endpoint through postman(by passing token with authorization header) and they are working properly.
This is the call im making from the front-end
export const getUsersDetails=()=>{
console.log( localStorage.getItem('jwtToken'));
return (dispatch) => {
return axios.get('http://localhost:3030/users',
{ headers: { 'Authorization': localStorage.getItem('jwtToken') } }
).then((data)=>{
console.log('data comming',data);
dispatch(getUsersData(data));
}).catch((error)=>{
console.log('error comming',error);
dispatch(errorgetUsersData(error));
});
};
}
I have enable CORS by using the the CORS module. this is the how the network calls looks like from the browser
the authorization header looks like
authorization:[object Object], eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.....
Should this be like authorization: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.....
Is this the reason why im facing this issue? How to overcome this?
I was able to solve a similar issue on a MERN stack, by configuring axios globally in the react application, by adding Bearer and one space, in front of the token that is assigned globally.
axios.defaults.headers.common['Authorization'] =Bearer ${token};
initially, it was without Bearer and i kept getting a 401 status code.
axios.defaults.headers.common['Authorization'] = token;
When you want authorization in your app, it depends on how you have done your back end. If everything is ok trough postman, show how your headers in postman look when you have tasted. I use xsrf token and here is how my request header look:
{headers:
{"Access-Control-Allow-Headers" : "*",
"X-XSRF-TOKEN": this.$cookie.get('XSRF-TOKEN')}
}
Maybe you should just put "Access-Control-Allow-Headers" : "*"

Authenticate on Application Insights REST API with AAD

So far I used successfully Application Insights REST API for getting metrics with X-Api-Key header.
https://api.applicationinsights.io/beta/apps/xxxxxxxxxx/metrics/customMetrics%2FmetricName?timespan=PT2H&interval=PT20M&aggregation=min
However with our new dashboard, crawling several metrics, we hit hard the 1500 request/api key limit.
Some suggest to play around with several api keys, but I would like to prevent this approach.
According to documentation, authenticate with AAD would remove the daily cap (https://dev.applicationinsights.io/documentation/Authorization/Rate-limits)
But I fail to authenticate with AAD (in nodejs, but I suspect it's the same in any language)
I used adal-node with a simple app, I successfully get a token, however I'm not able to forward it to the Request
var context = new AuthenticationContext(authorityUrl);
context.acquireTokenWithClientCredentials(resource, clientId, clientSecret, function(err, tokenResponse) {
if (err) {
console.log('well that didn\'t work: ' + err.stack);
} else {
console.log(tokenResponse);
request({'url' : 'https://api.applicationinsights.io/beta/apps/xxxxxxxxx/metrics/customMetrics%2Fmetrics?timespan=PT2H&interval=PT20M&aggregation=min',
headers: {
'Authorization': 'Bearer ' + tokenResponse.accessToken
}
}, function (error,response,body){
console.log(body);
});
}
});
I'm getting following error message
The provided authentication is not valid for this resource
The given API Key is not valid for the requested resource
I suspect I miss something :)
We don't support AAD in our REST API directly. Your resource is managed by the Azure Resource Manager, and only it can validate a certain user has access to this resource. API Keys are our way of short circuiting the authorization directly to a resource, instead of in the user context.
You gave this AAD app access to this resource as yourself, so the authentication is still in the context of a user. The call has to be made to ARM instead: 'https://management.azure.com/subscriptions/xxxxxx/resourcegroups/xxxxx/providers/microsoft.insights/components/xxxxx/api/metrics/customMetrics%2Fmetrics?api-version=2014-12-01-preview&timespan=PT2H&interval=PT20M&aggregation=min'
Documentation is linked here - though not explained explicitly: https://dev.applicationinsights.io/documentation/Authorization
This will get you a higher rate-limit, and still return the same response as the REST API.

Connection between nativescript and MongoDB (mongoose)

I am new in mobile development world and right now trying to understand few basic things.
I did a simple login nativescript app and from backend side did a login logic with mongoose (MongoDb) and express. But now I don't know how to proceed... How do I connect between backend and app?
Thank you in advance,
Emil
You need to expose an API from your backend, I'll assume you have done this (or can find this out - it's very well documented).
So from the client {N} you will need to access the API, calling whichever end-points you need. If you were using a JWT type approach, you should use the http module in nativescript, which might look something like this:
var http = require("http");
var result;
http.request({
url: "https://myBackend.org/api/post",
method: "POST",
headers: { "Content-Type": "application/json" },
content: JSON.stringify({ username: "ValueOne", password: "ValueTwo" })
}).then(function (response) {
result = response.content.toJSON();
console.log(result); //result.message would have the clients auth token
}, function (e) {
// console.log("Error occurred " + e);
});
You could then store the token (in persistent storage with the application-settings module) and add it to the header of any request to a different API endpoint to interact with your backend as an authenticated user.
Alternatively, you can use one of the cloud backend SDKs, e.g. Azure Mobile Services or Firebase which make your life much easier.