CSRF token in angular is different of Laravel 5 - angularjs

I have a project split up in backend and frontend, the backend (API rest) is built in Laravel 5 and frontend in AngularJS. Both project are independent and they are supposed to be hosted on different servers.
In the first request I obtain the CSRF token from Laravel with this code:
var xhReq = new XMLHttpRequest();
xhReq.open("GET", "http://laravel.local/api/token", false);
xhReq.send(null);
angular.module('mytodoApp').constant('CSRF_TOKEN',xhReq.responseText);
So the CSRF_TOKEN is sent each time that I make a request to API, like this:
$scope.deleteTodo = function(index) {
$scope.loading = true;
var todo = $scope.tours[index];
$http.defaults.headers.common['XSRF-TOKEN'] = CSRF_TOKEN;
console.log($http.defaults.headers.common['XSRF-TOKEN']);
$http.delete('http://laravel.local/api/deleteTodo/' + todo.id, {headers : {'XSRF-TOKEN': CSRF_TOKEN}})
.success(function() {
$scope.todos.splice(index, 1);
$scope.loading = false;
});
The API always return:
TokenMismatchException in compiled.php line 2440:
Is it right that Laravel changes the CSRF Token with every request from Angular? On every request, Laravel creates a new file on storage/framework/sessions. Do you recommend any other solution to validate that requests to API come from a safe origin?

In token-based authentication, cookies and sessions will not be used. A token will be used for authenticating a user for each request to the server.
It will use the following flow of control:
The user provides a username and password in the login form and clicks Log In.
After a request is made, validate the user on the backend by querying in the database. If the request is valid, create a token by using the user information fetched from the database, and then return that information in the response header so that we can store the token browser in local storage.
Provide token information in every request header for accessing restricted endpoints in the applications.
4.request header information is valid, let the user access the specified end point, and respond with JSON or XML.
This Can be Achieved by Jwt (Json web Token).got this information from This link.
So, what is this JWT?
JWT
JWT stands for JSON Web Token and is a token format used in authorization headers. This token helps you to design communication between two systems in a secure way. Let's rephrase JWT as the "bearer token" for the purposes of this tutorial. A bearer token consists of three parts: header, payload, and signature.
The header is the part of the token that keeps the token type and encryption method, which is also encrypted with base-64
The payload includes the information. You can put any kind of data like user info, product info and so on, all of which is stored with base-64 encryption.
The signature consists of combinations of the header, payload, and secret key. The secret key must be kept securely on the server-side.
The tutorial with example can be Found here Token-Based Authentication With AngularJS & NodeJS.
Hope that this will solve your problem,All the Best!!

Related

How to validate AzureAD accessToken in the backend API

I just wanted to know how can we validate the azure ad access token in a backend API in my case i.e. Django rest framework.
Consider that I have a single page app or a native app and a backend API (django rest framework) completely independen of each other. In my case if my single page app/native app wants to access certain data from the backend API, and inorder to access the API, user should be logged in the backend API.
So what my approch is to make use of MSAL library to get the access token from the SPA/native app and then once token is acquired, pass that token to backend API, validate it, get the user info from graph api. If user exists in the DB then login the user and pass the required info. If user info doesn't exist then create the user, login and pass the info from the API.
So my question is when I pass the access token to my backend api, how can I validate that the token that a user/SPA/native app has passed to backend API is valid token or not?
Is it just we need to make an API call to graph API endpoint with accessToken that user/SPA/native passed and if it is able to get the user data with the accessToken then then token is valid or if it fails then the accessToken is invalid.
Is it the general way to validate the token or some better approach is there? Please help
Good day sir, I wanna share some of my ideas here and I know it's not a solution but it's too long for a comment.
I created a SPA before which used msal.js to make users sign in and generate access token to call graph api, you must know here that when you generate the access token you need to set the scope of the target api, for example, you wanna call 'graph.microsoft.com/v1.0/me', you need a token with the scope 'User.Read, User.ReadWrite' and you also need to add delegated api permission to the azure app.
So as the custom api of your own backend program. I created a springboot api which will return 'hello world' if I call 'localhost:8080/hello', if I wanna my api protected by azure ad, I need to add a filter to validate all the request if has a valid access token. So I need to find a jwt library to decode the token in request head and check if it has a token, if the token has expired and whether the token has the correct scope. So here, which scope is the correct scope? It's decided by the api you exposed in azure ad. You can set the scope named like 'AA_Custom_Impression', and then you can add this delegate api permission to the client azure ad app, then you that app to generate an access token with the scope of 'AA_Custom_Impression'. After appending the Bearer token in calling request, it will be filtered by backend code.
I don't know about python, so I can just recommend you this sample, you may try it, it's provided by microsoft.
I've solved the similar issue. I don't found how to directly validate access token, but you can just call graph API on backend with token you've got on client side with MSAL.
Node.js example:
class Microsoft {
get baseUrl() {
return 'https://graph.microsoft.com/v1.0'
}
async getUserProfile(accessToken) {
const response = await got(`${this.baseUrl}/me`, {
headers: {
'x-li-format': 'json',
Authorization: `Bearer ${accessToken}`,
},
json: true,
})
return response.body
}
// `acessToken` - passed from client
async authorize(accessToken) {
try {
const userProfile = await this.getUserProfile(accessToken)
const email = userProfile.userPrincipalName
// Note: not every MS account has email, so additional validation may be required
const user = await db.users.findOne({ email })
if (user) {
// login logic
} else {
// create user logic
}
} catch (error) {
// If request to graph API fails we know that token wrong or not enough permissions. `error` object may be additionally parsed to get relevant error message. See https://learn.microsoft.com/en-us/graph/errors
throw new Error('401 (Unauthorized)')
}
}
}
Yes we can validate the Azure AD Bearer token.
You can fellow up below link,
https://github.com/odwyersoftware/azure-ad-verify-token
https://pypi.org/project/azure-ad-verify-token/
We can use this for both Django and flask.
You can directly install using pip
but I'm not sure in Django. If Django install working failed then try to copy paste the code from GitHub
Validation steps this library makes:
1. Accepts an Azure AD B2C JWT.
Bearer token
2. Extracts `kid` from unverified headers.
kid from **Bearer token**
3. Finds `kid` within Azure JWKS.
KID from list of kid from this link `https://login.microsoftonline.com/{tenantid}/discovery/v2.0/keys`
4. Obtains RSA key from JWK.
5. Calls `jwt.decode` with necessary parameters, which inturn validates:
- Signature
- Expiration
- Audience
- Issuer
- Key
- Algorithm

MVC with Angular - ValidateAntiForgeryToken fails after Azure Login redirect with Adal

I have an MVC site with an embedded angular client and I've recently implemented an anti forgery XSRF token as a security measure.
I have set it up in Startup.cs as follows:
services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
app.Use(next => context =>
{
if (string.Equals(context.Request.Path.Value, "/", StringComparison.OrdinalIgnoreCase) ||
string.Equals(context.Request.Path.Value, "/index.html", StringComparison.OrdinalIgnoreCase))
{
// We can send the request token as a JavaScript-readable cookie, and Angular will use it by default.
var tokens = antiforgery.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken,
new CookieOptions() { HttpOnly = false });
}
return next(context);
});
And I've implemented it within my angular front-end like so:
{ provide: XSRFStrategy, useFactory: xsrfFactory}
export function xsrfFactory(): CookieXSRFStrategy {
return new CookieXSRFStrategy('XSRF-TOKEN', 'X-XSRF-TOKEN');
}
And protecting my controllers like:
[Authorize] //Validation of AzureAD Bearer Token.
[ValidateAntiForgeryToken]
public class UserController : Controller
It is intended that the X-XSRF-TOKEN header be validated with any call to my API, and this works successfully for all calls in the original session. However, my app uses Adal to log the user in, and after the redirect from a successful login, this validation step fails and I receive a 400 from my API for any subsequent calls.
The original X-XSRF-TOKEN header is still sent with all outgoing requests from my angular client after the login so I suspect it must be that my server side no longer has the token to validate against, or my server has generated a new one and my client doesn't retrieve it. But for whatever reason it breaks down and it's very hard to debug without creating some custom filter so I can see what's going on inside it.
Is there a way to reset this token after a client side redirect so that both my server and client share common knowledge of it again? Or should I be generating the token in my Index.html for example?
EDIT
Edited controller decoration above for missing [Authorize] attribute.
So my controller is protected by a step validating the AzureAD Bearer token as well as the Anti-Forgery validation. Removing the AzureAD Validation as a test did not resolve the issue, oddly.
Error on failing API calls displays in output after Adal login as:
The provided anti-forgery token was meant for a different claims-based user than the current user.
Based on my understanding, you were protecting the controller using token. For this issue is expected, you can refer the progress of validate the anti-XSRF tokens from below(refer this link):
To validate the incoming anti-XSRF tokens, the developer includes a ValidateAntiForgeryToken attribute on her MVC action or controller, or she calls #AntiForgery.Validate() from her Razor page. The runtime will perform the following steps:
The incoming session token and field token are read and the anti-XSRF token extracted from each. The anti-XSRF tokens must be identical per step (2) in the generation routine.
If the current user is authenticated, her username is compared with the username stored in the field token. The usernames must match.
If an IAntiForgeryAdditionalDataProvider is configured, the runtime calls its ValidateAdditionalData method. The method must return the Boolean value true.
Since you were developing the SPA application with back-end web API, when the request to the web API, it will always issue the anti-XSRF token with no identity. And when you send the request to the back-end with anti-XSRF and Azure AD token, this time the web API already authenticate the request via the Azure AD token. And it will always return false when checking anti-XSRF token to match the identity information.
In this scenario, if the back-end only using the bear token authentication and store the token with session storage, there is no need to enable XSRF prevention since others is not able to steal the token and forge the request.
If your back-end also support the cookie authentication or basic auth, NTLM etc, you can disable the identity checking by adding the following to your Application_Start method: AntiForgeryConfig.SuppressIdentityHeuristicChecks = true.(refer this link)
More detail about XSRF/CSRF abouth oauth and web API, you can refer the threads below:
How does ValidateAntiForgeryToken fit with Web APIs that can be accessed via web or native app?
AntiForgeryToken does not work well with OAuth via WebAPI
Try replacing [ValidateAntiForgeryToken] with [AutoValidateAntiforgeryToken]
https://github.com/aspnet/Antiforgery/blob/dev/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgeryTokenGenerator.cs

Maintaining Secret key and Access Token for JWT in Express and NodeJS with Facebook in Rest API

I have two applications:
server ( REST API Server)
node js
Express
jsonwebtokens
express-jwt
mongoose
client (Portable Front-end)
bootstrap
Angular JS
local-storage
angular-facebook
angular-jwt
Lateron, the client app will be ported for android, iphone and other platforms using phonegap. For OAuth, I am using Facebook as the provider. Now, I just realized JSON Web Tokens are the way to go for this kind of set up. My question is an architectural one rather than syntactical one - how to manage a secret key when signing the facebook access token and user id with JWT in nodejs?
So this is how the flow works in my app:
Angular client has a Login button
User Clicks the button > Facebook Auth starts
Client receives user_id and FB Access Token
Client sends[POST json body] both user_id and Access Token to Node+Express Server at 'http://server.com/auth/login'
Node Server has applied express-jwt to all routes except /auth/login with a
var expressJwt = require('express-jwt');
var jwt = require('jsonwebtoken');
app.use(expressjwt({ secret: ''}).unless({path: ['/auth/login']}));
Node server receives data from req.body, fetches all profile details from facebook using the JavascriptSDK, and signs it using
var token=expressjwt.sign({profile}, );
Node Server stores(updates, if user_id exists) the new token in db and sends it as response to client
client stores the new token it received as json data in local-storage
client uses angular-jwt to fetch profile data from the new token and automatically attach the new token in Authorization header for all requests it sends to the server
Now, my questions are:
Do I really need to store the JWT tokens in database? I am certainly not comparing the tokens in request headers with database
Do I need to generate random secret keys for security, each time a person logs in? If yes then how would that fit in both client and server?
When and where do I need to check for token expiration? and How do I refresh it?
I am kind of lost about the design flow and mechanism.
Ad 1. You do not have to store the JWT in the database. User ID can be part of the payload, therefore there's no need for it.
Ad 2. It's a common practice for the server side app to use one secret key for generating all JWT.
Ad 3. Check if token has expired on each request to your API and disallow access if the token has expired, return 401 status code. Client app should prompt user for credentials and request new JWT. If you want to avoid users re-submitting the credentials you can issue a refresh token that later can be used to generate new JWT.
JWT refresh token flow
http://bitoftech.net/2014/07/16/enable-oauth-refresh-tokens-angularjs-app-using-asp-net-web-api-2-owin/

What is the best way to user authentication with Devise 3 and Backbone?

I'm working with this stack:
Core API RESTful with Rails 4 and Devise 3.2
Another app/stance with Backbone
I have read many articles, manuals, stackoverflow topics, google random results, blogs, etc, but are all very deprecated.
Using a practical approach (tl;dr here) I just need get a real session between Devise 3 and Backbone in different server stances and holding it, like two separate projects. Remote login, you know.
I'm really stuck with that so I would greatly appreciate your suggestions.
Thank you guys.
Personally I have the same situation in my project with Angular instead of Backbone as a front-end and Rails 4 API with Devise. I will try to sum things up for you in the assumption that I got your question right.
To work correctly with the sessions in your scenario you need to be sure that:
Browsers handle communication correctly (i.e. they don't mess with your data because requests do not comply with CORS policies)
and, your requests get through Rails CSRF protection
Please, read this article about CORS. If you are not familiar with CORS the article should provide necessary background for my answer. Some info about CSRF protection is here
Here is your scenario step-by-step:
Backbone.js sends GET request such as http://yourserver/signin
Rails Server sends session cookie that will be stored in the browser and CSRF token, which can be stored somewhere within your Backbone application.
Backbone.js sends POST request with user credentials (name, password) and CSRF token in headers and current unauthorized session in cookies. It is crucial that request contains session information. Otherwise it will be granted different CSRF token on Rails side and you will get WARNING: Can't verify CSRF token authenticity message.
Backbone.js gets authorized session back if the credentials are correct.
Here is what can be done to get it working:
Rails backend should respond correctly to requests from front-end. Which means it should:
Respond to OPTIONS requests (preflight requests)
Send correct CORS headers
Able to communicate CSRF token with the front-end
Front end should:
Able to send requests with credentials
Obtain and use correct CSRF token
The simplest way to teach your Rails back-end to respond to CORS requests is to use
rack-cors gem. This will also provide correct CORS headers.
config.middleware.insert_before Warden::Manager, Rack::Cors do
allow do
origins '*' # it's highly recommended to specify the correct origin
resource '*',
:headers => :any,
:methods => [:get, :post, :options], # 'options' is really important
# for preflight requests
:expose => ['X-CSRF-Token'] #allows usage of token on the front-end
end
end
Last thing on a backend side is to provide CSRF token. Custom Devise controller should handle this task perfectly.
class SessionsController < Devise::SessionsController
after_action :set_csrf_header, only: [:new, :create, :destroy]
#...
protected
def set_csrf_header
response.headers['X-CSRF-Token'] = form_authenticity_token
end
end
Note that you need CSRF token when you send first GET request (new), when you submit credentials through POST request (create) and when you sign out of your application by sending DELETE request (destroy). If you don't send CSRF token on sign out you won't be able to sign in without reloading the page.
And somewhere in config/routes.rb don't forget to specify that you are now using custom controller:
/config/routes.rb
devise_for :users, :controllers => {:sessions => "sessions"}
Now, to the front-end. Please, have a look at this script that overrides standard Backbone.sync and handles communication with Rails server.
It is almost good with couple of corrections needed:
beforeSend: function( xhr ) {
if (!options.noCSRF) {
// we dont have csrf-token in the document anymore
//var token = $('meta[name="csrf-token"]').attr('content');
// New Line #1
// we will get CSRF token from your application.
// See below for how it gets there.
var token = YourAppName.csrfToken;
if (token) xhr.setRequestHeader('X-CSRF-Token', token);
// New Line #2
// this will include session information in the requests
xhr.withCredentials = true;
}
//..some code omitted
//................
// Trigger the sync end event
var complete = options.complete;
params.complete = function(jqXHR, textStatus) {
// New Lines #3,4
// If response includes CSRF token we need to remember it
var token = jqXHR.getResponseHeader('X-CSRF-Token')
if (token) YourAppName.csrfToken = token;
model.trigger('sync:end');
if (complete) complete(jqXHR, textStatus);
};
}
I'm not sure this qualifies as a complete answer to your question, but at least it is something to start from. It might not be the best way, but it is the way. Let me know if you have any questions.

How to pass basic auth header to REST endpoint after Forms Authentication sign in?

I have a Backbone/RequireJS application built on top of .NET MVC4. I am using Forms Authentication to authenticate the user against our back end data store, and this is working great.
Our services layer is a .NET Web Api Project (RESTful API), and is using a tokenized approach to auth (initial request includes basic auth header. If auth is successful, response payload includes authentication token. Subsequent requests pass the token).
What I'm not sure about is how to now authenticate against our services layer. I'm sure I'll have to pass the auth header, but not sure how to generate the token, as I won't have username/password in my JS.
Should I bypass Forms auth altogether here, and simply make an ajax request over SSL? I can POST to the /Account/Login action just as well, and use the Membership Provider to validate credentials. If successful, I can add the Auth header for initial request & use auth token for subsequent requests.
Example of adding auth header / custom token here:
$.ajaxSetup({
'beforeSend': function (xhr) {
if($.cookie("AuthToken")) {
xhr.setRequestHeader("CustomTokenHeader", $.cookie("AuthToken"));
} else {
var token = methodToBase64EncodeUsernamePassword(username, password);
xhr.setRequestHeader("Authentication", "Basic " + token);
}
}
});
Take a look at this solution, which is based off a screencast I cannot seem to find again. If I can find it, I will update the answer. You should be able to follow the solutions easily though. The one you are looking for is PerRouteMHOwnershipSample. I believe the best practice is to 'bypass Forms auth altogether here, and simply make an ajax request over SSL'. Any api route you want to secure, will be filtered and a token will then need to be passed from your app and decoded on the server. I would personally not look at using Forms Authentication to secure your api.

Resources