My use case:
User is already logged in automatically server side using Facebook with laravel and Socialite.
I check if the user exists in the db and if not create it and log them into laravel.
Then I need to start an Angular app and make sure they are logged in with Laravel / Facebook.
After reading this article, it looks like this token based approach is what I should take.
In the tutorial you serve a login form with Angular, and then pass the email and password to an authenticate controller (Laravel), which returns a token (create by JWT-Auth).
Once the token is in Angular all is well, my problem is that I want to get the token directly into Angular without a login form since the user is already logged in as mention above.
I'm wondering if I could just output the token in markup somewhere and then pick it up from Angular or would that somehow be a security risk? I guess people will only be able to view source and see their own token?
If this is the wrong way to do this, then how should I do it? Do I need to authenticate with Facebook with Javascript, and then create a new laravel user with ajax?
Thanks so much!
One approach you could take is to add something to your .config block that checks for the presence of a JWT in local storage and if there isn't one there, makes a request to the API to see if the user is logged in on the Laravel side. If the user is logged in, a JWT is returned which can be picked up and saved in local storage. Since the .config block is run when the Angular app loads, this will only happen once, which is probably what you're looking for.
Here's what that might look like. First the Laravel side:
// AuthenticateController.php
...
// Simulates a user being logged in on the Laravel side through something
// other than credentials sent from the front-end. Obviously you would use
// Socialite
public function authenticate()
{
$user = User::find(1);
$token = JWTAuth::fromUser(1);
return response()->json(compact('token'));
}
...
Then the Angular:
// app.js
...
.run(function($rootScope, $state, $auth) {
if(!$auth.isAuthenticated()) {
// No credentials provided because the user is already logged in on the server
$auth.login().then(function() {
$state.go('users');
}
}
$rootScope.$on('$stateChangeStart', function(event, toState) {
...
This would just run when the Angular app loads, which will be after your user has logged in with Socialite. It's essentially just checking whether there is a user logged in on the back end and if so, the token is retrieved. It's a bit hacky and the interface isn't obvious, so it might not be the best solution.
You would need to arrange your authenticate controller on the Laravel side such that it returns the token if the user has logged in via socialite or require credentials if he/she hasn't (which is the traditional login).
You could also look at this approach to see if it works for you: https://github.com/barooney/jot-bot/tree/socialite
Let me know if that works out!
Related
I'm pretty new to working with tokens. Just started learning yesterday.
I have an Express backend API. I understand that the token prevents anyone from getting access to data on any given API endpoint/json data...But how can I READ/decrypt the JWT when it's on the angular side?
I.E., Okay, I know that this user is logged in and can therefore view this page, however, this particular user is the CREATOR of this event. Therefore, on this event's show page, users who have been invited are allowed to view it, and so is the event creator, but only the event creator will see a button that when clicked, does a delete request to the event. The other users will not see this button.
The only way I see this being possible is that the JWT containing the user object can be decoded on the front/end, then I have access to variables with the decoded JWT properties. I.E., username and userID. That way, on the view page being rendered in Angular, I can code logic such as:
```
if (decodedJWT.user.username === event.creator.username) {
DO SOMETHING HERE LIKE DISPLAY A CERTAIN BUTTON
}
```
Thanks.
You need to create an API point in your nodeJS backend that will return the user details if he is logged in:
app.use('/userinfo', expressJwt({secret: secret}));
Here you make sure /userinfo is protected by JWT and your secret phrase.
Then the route corresponding to this API returns user info:
router.get('/get', function (request, response) {
response.json({
id: request.user.id,
name: request.user.nom,
email: request.user.email,
role: request.user.role
});
});
The full API is located at /userinfo/get and is secured by the JWT token.
In angularJS you just need to make a request to that API using simple $http.get('/userinfo/get') which will return a user object or an error from the server if not logged in.
Of course you need to pass the token to all your $http requests.
I'm using adaljs. Everything seems great...I can log in, log out, wonderful.
Now, after an hour...I load up my app again and! NOT so wonderful. I debug and I see that adalAuthenticationService.userInfo.isAuthenticated == false and adalAuthenticationService.profile == undefined.
What do I do when I get this? How do I recover?
When do I use these functions and for what?
acquireToken
clearCache
clearCacheForResource
getCachedToken
getResourceForEndpoint
getUser
logOut
logIn
logOutInProgress
Most importantly, WHY are these not explained in detail (or even in brief!) on the adaljs repository?
Let's turn this into a wiki about adaljs functions and properties. We all want to know what they do, what they are for, and how to use them.
Edit
In my app.js, I have this code for handling authentication:
if (adalAuthenticationService.userInfo.isAuthenticated && adalAuthenticationService.userInfo.profile) {
var great = "everything is awesome";
_ld.extend($scope.user,adalAuthenticationService.userInfo);
$scope.successFullyLoggedIn($scope.user);
} else if(!adalAuthenticationService.userInfo.isAuthenticated && !adalAuthenticationService.userInfo.profile) {
adalAuthenticationService.clearCache();
adalAuthenticationService.login();
} else {
adalAuthenticationService.clearCache();
adalAuthenticationService.logOut();
}
The tokens that adal.js gets from AAD expires after every one hour. If you are using angular wrapper then adal will be able to automatically renew the tokens as long as there is a valid user logged in. If you are not using angular wrapper, then application has to take the responsibility of renewing the tokens, that is where the apis will come handy.
I will try to explain what each one of them do:
acquireToken: This is one of the main methods. Takes 2 parameters: resourceId and callback. ResourceId is the app id of application on azure portal. Adal first looks into cache to check if there is token present already. If not, it sends a request to AAD to get a new token. It passes the token or the error to the callback, which has a signature like this: callback(err, token).
clearCache: delete all items in the browser storage that adal stored. Kind of a fresh start.
clearCacheForResource: I am assuming you are using experimental version because this api is not part of released 1.0.12 version. This basically deletes the cache entries for a specific resource id.
getCachedToken: Looks into the caceh and returns the token or null for the given resource.
getResourceForEndpoint: This is useful when using angular wrapper. This looks into the endpoints mapping that user provided at the time of initializing adal. The purpose of this method is to resolve a url into resourceId which can then be fed to acquireToken method.
getUser: current logged in user object or null.
logOut: logs out the user, clears cache and redirect the user to postlogoutredirecturi (if specified), otherwise redirects the user to redirecturi.
login: logs in the user, creates the user object (which can be accessed using getUser), saves the id token in the cache. It also calls the callback that you have on application level on config object when initializing adal.
logOutInProgress: Do you mean loginInProgress? That is just a flag to use internally to see if there is an active login in progress.
Unfortunately, we do not have api guides, that can help people understand our apis better. I will bring this to team's notice. Thanks.
Back to your question: you can use getUser() to get the user object. If it is null, then call logIn() method to log in the user. If user.userName is not null but user.isAuthenticated is false, this means, the token has expired, call acquireToken method and pass clientId of the application to renew the token. Also, you want to check adalAuthenticationService.usernInfo.profile instead of adalAuthenticationService.profile.
How can I maintain the login user details in angular app, the data is lost when to reloading the app, how to resolve this problem, my server side is nodejs
After login I am saving the details in $cookies, like the token, user-name etc. Here is the code:-
$cookies.put('token', response.token);
$cookies.put('user', response.user);
I am putting these things in the success block of service call.
And you can delete them on logout like this:-
$cookies.remove('token');
$cookies.remove('user');
Every website is using $cookies these days even facebook.
You can store the logged user details ,like username email, and any other details in local storage. and remove this storage on logout.
2nd and most important is that you server API interaction may ask some sessionID, or equivalent key for trusted actions. you might want that.
I have a problem I can't figure out, in my application I have two login screens, one for the admin the other for the regular user. These login screens however point to the same controller in the same Auth namespace aside from that I have separated the rest of my controllers and routes into two namespaces; FrontEnd Namespace and BackEnd namespace.
Now my issue right now is when a regular user uses their credentials to login from the backend they are allowed access, I installed this package kodein/acl to handle roles and permissions and it seems to be working because when a user logs in to the backend now they can't do anything. The problem now is that even though they can't do anything they are still able to redirect to admin dashboard.
What I want here is this; when a regular user tries to login to admin backend they are denied access. I am a bit confused, i dunno how to o about it.
Do I have to create separate auth controllers and methods in both namespaces? Is that even possible? How would i go about it?
I use AngularJS for my frontend so in my route file i have this:
Route::group(['domain' => 'admin.website.loc'], function() {
Route::any('{url?}', function($url) {
return view('backend.index');
})->where(['url' => '[-a-zA-Z0-9/]+']);
});
Route::any('{url?}', function($url) {
return view('frontend.index');
})->where(['url' => '[-a-zA-Z0-9/]+']);
Which catch all urls and return to a single Index page,on the front end since i use JWT for authentication it validates the token on the frontend and if invalid or not available takes the user to the login page.
I thought of something else, maybe a temporary measure maybe permanent, i added the following code to my login function():
$url_parts = parse_url($request->url());
$host_parts = explode('.', $url_parts['host']);
if ($host_parts[0] == "admin")
{
$user = User::find(Auth::user()->id);
if (!$user->is('administrator'))
{
Auth::logout();
return response()->json(['error' => 'You Are Not Authorized!']);
}
}
first i get the request url,
then i get the "host" part of the request url and split it using '.' as the delimiter, this way i can check the subdomain.
Since my admin side uses a sub domain i check to see if the login request was from a url with the 'admin' subdomain, if it was then i check the authenticated user's role to see if they're administrator, if they are not, i log them out immediately and return an error message.
This way i don't have to create a separate function and route for the two login screens.
I am sing OAuth2 in WebAPI project. I am authenticating user request in OWIN middleware. On successfull authentication I am sending an JWT access token to client. Now I can validate subsequent request at server and use [Authorize(Roles="myRole")] attribute on Api Controllers.
But how can I show validate client content in AngularJs and show pages based on user role? I have JWT at client and no idea how to get user role out of it?
Is it a good approach to extract information from JWT?
You will need to parse that JWT and get the values out. You can do that with the help of the angular-jtw library.
1) Download the angular-jwt.min.js (https://github.com/auth0/angular-jwt)
2) put a dependecy of "angular-jwt" on the application module:
var app = angular.module("YOUR_APP", ["angular-jwt"]);
3) pass the jwtHelper to your service or controller or wherever it is that you wish to use it.
app.module.factory("YOUR_SERVICE", function(jwtHelper){
...
});
4) use the decodeToken method of the jwtHelper you passed in to decode your token
For example, the code below is parsing out the role object from a jwt that came back from my service endpoint. Upon succssful return from the server the role is extracted from the jwt and returned.
return $http.post(serviceEndPoints.tokenUrl, data, config)
.then(function (response) {
var tokenPayLoad = jwtHelper.decodeToken(response.data.access_token);
//Now do whatever you wish with the value. Below I am passing it to a function: (determineRole)
var userRole = determineRoles(tokenPayLoad.role);
return userRole;
});
};
Hope that helps
//Houdini
Currently we don't offer anything that would help you to take advantage of that information on the client. Also note: as today we do not validate the token on the client, we cannot really trust its content... while the [Authorize] attribute on the server side gets the role info only after the pipeline before it had a chance of validating the signature and deciding that the token is valid.
We might introduce something that will help with this scenario in the future, but for the time being you'd need to write custom code or rely on the server side to echo things back.