Authentication using Angularjs - angularjs

I am fairly new to AngularJS
I have a resource that I use for user management which is part of a service following this article.
Once sending the login request to the server I am getting a response with a set-cookie as part of the header.
What is the best practice to add this cookie to every request I am sending to the server?
myApp.factory('UserService', ['$resource', function ($resource) {
var userRes = $resource('http://<MyDomain>/api/v1/user/:param',
{param: '#param'},
{
login: {
method: 'POST'
},
logout: {
method: 'DELETE'
}
});
var user;
return {
signIn: function () {
user = userRes.login({param: 'login'}, {"email": "SomeName#MyDomain.com", "password": "test1"});
userRes.get({param: '1'});
},
userRes.login has set-cookie header in on the response
userRes.get does not send the cookie that was just received.
Cheers

Since your API is in a different domain you can't use cookies in this case. We've tried and we failed to put it simple there is no way, not only it doesn't work with CORS but also it doesn't work if you embed an iframe. The iframe trick fails on safaris mostly but it is not reliable.
What we usually do is to return a JWT (Json Web Token) from the API and attach a header then to every API request as Authorization: Bearer JWT.
This JWT can be decoded using a public key from the front end (and it will contain the user profile) and validad with a private key in the backend.
JWT is simple and there are plenty of libraries for every language/technology.
Auth0 is an authentication broker that can validate with any identity provider or custom databases, and it returns JWTs using standars. It provides a clientID that can be used to decode the profile in the front end and a secret to validate the tokens in the backend as well as client side library to do this.
Disclaimer: I work for auth0.

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

GCP Server to Server Authentication with Service Account

I'm trying to authenticate a request from my Google Cloud Function to my API on App Engine (Standard environment).
I have something working, but I'm new to OAuth2 and am looking for a sanity check.
In my Cloud Function, I send an authenticated request to my API doing the following:
import { GoogleAuth } from 'google-auth-library';
// Send Request Code:
const auth = new GoogleAuth();
const tokenClient = await auth.getIdTokenClient(`/protectedEndpoint`);
await tokenClient.request({
url: `https://${process.env.GCLOUD_PROJECT}.appspot.com/protectedEndpoint`,
method: 'POST',
});
In the API (on App Engine), I do the following:
import { GoogleAuth } from 'google-auth-library';
// Handle Request Code:
const token = <Bearer token parsed from request headers>
const googleAuth = new GoogleAuth();
const tokenClient = await googleAuth.getIdTokenClient('');
const loginTicket = await tokenClient.verifyIdToken({
idToken: token,
audience: '/protectedEndpoint',
});
if (loginTicket.getUserId() !== process.env.SERVICE_ACCOUNT_ID)) {
throw new Error('Unauthenticated Service Account');
}
return 'Successful Authentication'
Note: In both cases, I'm using Google's default application credentials to initialize the GoogleAuth client. (my Default App Engine service account)
This all works. My function sends a request to my API, and my API is able to parse the bearer token and tell me that it came from my approved service account... but I'm not 100% confident that this is actually secure. Is it possible for someone to spoof my service account without having its credentials?
Thanks in advance!
Is it possible for someone to spoof my service account without having
its credentials?
A precise answer requires the specification of time. Given enough time and processing power, any authentication/authorization/encryption/hashing/signing method can be broken.
A Google service account contains an RSA 2048-bit private key. Current guesstimates are 300 trillion years to break RSA 2048 bit encryption. With the rapid advances in computers, let's assume your data will probably not be of any use/value by the time RSA is broken.
The private key is used to sign a JWT. The Signed JWT is used to request OAuth Access/Identity Tokens.
Spoofing would require signing with the same private key. Therefore, spoofing is not possible with today's technology.
Stealing/leaking the private key or the generated OAuth tokens is the only realistic method today.

What is the best practice to use Oauth2, React, Node.js and Passport.js to authenticate user with Google sign on button?

I want to have a login button in my website so when a user clicks on it, the user can use their Google credentials. I'd like to ideally perform the authentication server side using Express.js and Passport.js.
I implemented authentication server-side but the problem is that I can't make an AJAX request from the website to the server to start authentication because Google or Oauth don't support CORS. So I need to use a href element in my website which would call the server authentication endpoint. However, I can't catch server response in this way.
If I perform the authentication client-side (I'm using React) I could store login state in Redux and allow the user to access the website's resources. However, when the user logs out I need to make sure that server endpoints stop serving the same user which feels like implementing authentication twice: client-side and server-side.
In addition when authenticating client-side, Google opens a popup for the user to authenticate which I think is worse user experience then just a redirect when authenticating server-side.
I'm wondering what the best practice in terms of authenticating using Oauth2/Google. For example, stackoverflow.com also has Google button but just makes a redirect, without any popup, so I guess they figured out a way to perform server-side authentication and to bypass CORS issue.
I faced the same issue. This article is Gold link
1.In auth route File I had following code
const CLIENT_HOME_PAGE_URL = "http://localhost:3000";
// GET /auth/google
// called to authenticate using Google-oauth2.0
router.get('/google', passport.authenticate('google',{scope : ['email','profile']}));
// GET /auth/google/callback
// Callback route (same as from google console)
router.get(
'/google/callback',
passport.authenticate("google", {
successRedirect: CLIENT_HOME_PAGE_URL,
failureRedirect: "/auth/login/failed"
}));
// GET /auth/google/callback
// Rest Point for React to call for user object From google APi
router.get('/login/success', (req,res)=>{
if (req.user) {
res.json({
message : "User Authenticated",
user : req.user
})
}
else res.status(400).json({
message : "User Not Authenticated",
user : null
})
});
2.On React Side After when user click on button which call the above /auth/google api
loginWithGoogle = (ev) => {
ev.preventDefault();
window.open("http://localhost:5000/auth/google", "_self");
}
3.This will redirect to Google authentication screen and redirect to /auth/google/callback which again redirect to react app home page CLIENT_HOME_PAGE_URL
4.On home page call rest end point for user object
(async () => {
const request = await fetch("http://localhost:5000/auth/login/success", {
method: "GET",
credentials: "include",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"Access-Control-Allow-Credentials": true,
},
});
const res = await request.json();
//In my case I stored user object in redux store
if(request.status == 200){
//Set User in Store
store.dispatch({
type: LOGIN_USER,
payload : {
user : res.user
}
});
}
})();
5.last thing add cors package and following code in server.js/index.js in node module
// Cors
app.use(
cors({
origin: "http://localhost:3000", // allow to server to accept request from different origin
methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
credentials: true // allow session cookie from browser to pass through
})
);
Your authentication should be done server side. Here is how it works.
You make a fetch or axios call to your authentication route.
Your authentication route sends a request to Google's Authentication servers. This is important to have on the backend because you will need to provide your clientSecret. If you were to store this on the frontend, it would make it really easy for someone to find that value and compromise your website.
Google authenticates the user and then sends you a set of tokens to your callback url to use for that user (refresh, auth, etc...). Then you would use the auth token for any additional authorization until it expires.
Once that expires, you would use the refresh token to get a new authorization token for that client. That is a whole other process though.
Here is an example of what that looks like with Passport.js: https://github.com/jaredhanson/passport-google-oauth2
EDIT #1:
Here is an example with comments of the process in use with Facebook, which is the same OAuth codebase:
https://github.com/passport/express-4.x-facebook-example/blob/master/server.js
Redux can really help with achieving this and this follows the same logic as Nick B already explained...
You set up oauth on the server side and provide an endpoint that makes that call
You set up the button on you react frontend and wire that through an action to the endpoint you already setup
The endpoint supplies a token back which you can dispatch via a reducer to the central redux store.
That token can now be used to set a user to authenticated
There you have it.

CSRF token in angular is different of Laravel 5

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!!

token authentication on Django REST framework + Angular project

I'm using DRF and Angular, which client environment is a mobile devices.
I've found out a django-rest-auth package.
I haven't hesitate to choice for that, because that provides a TokenAuthentication feature, which is suitable with a mobile client.
When I sent a login request, client receives a token.
Then, I was add a the bellow in request success callback.
login: function(username, password) {
return $http.post('http://192.168.0.3:8000/rest-auth/login/', {
'username':username,
'password':password,
}).success(function(data) {
$http.defaults.headers.common.Authorization = 'Token ' + data.key;
Account.authenticated = true;
console.log("login success", data)
})
At server's console, output about incoming request is the bellow
'HTTP_AUTHORIZATION': 'Token 3fae470d169adb550e538c99a754fcfbe3485f75'
But, I saw an unexpected result, like this:
request.user AnonymousUser
request.auth None
According to here, If I send a request with token, which extra authentication works will be processed by itself.
Should I add an other code for complete authentication?
(ex. register a token into django's session storage.)
I would like to hear your advice.
I solved for a problem, which cause is just stupid mistakes
I didn't look carefully at the reference documents.
To use the TokenAuthentication scheme you'll need to configure the authentication classes to include TokenAuthentication, and additionally include rest_framework.authtoken in your INSTALLED_APPS setting:
So I had added the configuration in settings.py.
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
# I add this config
'rest_framework.authentication.TokenAuthentication',
)
}
After send a login request terminal to server, then If I request with the "GET", terminal console outputs like the below.
request.user admin
request.auth 626ba4b1357cb472fc4bb0c58afb026cf21dd175

Resources