I tried great example angularjs todo app:
https://github.com/danielzen/todo-ng-pouchdb
and now I'm trying use it with some authentication plugin, but without success ( https://github.com/nolanlawson/pouchdb-authentication ). Todo app use some old angular-pouchdb lib.
Please do you have any tip to example where is used angular, pouchdb and auth plugin to login, signup to couchdb.
My problems with log into CouchDb were because of wrong auth params, I didn't wrap login values into array with key auth.
So just example of correct call to server:
$scope.sync = $scope.tasks.$db.replicate.sync('http://www.server.info:5984/' + dbName,
{live: true, "auth": {username:"john", password:"secret"}})
.on('error', function (err) {
});
Related
I have a React + Electron app using Google API to authenticate and get a list of calendar events.
The API script is being loaded on the head of my index.html and initialised on my App.js like so:
// Initializes the API client library and sets up sign-in state listeners.
initClient() {
let gapi = window["gapi"];
let that = this;
gapi.load("client", start);
function start() {
gapi.client
.init({
apiKey: GOOGLE_API_KEY,
clientId: CLIENT_ID,
discoveryDocs: [
"https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest"
],
scope: "https://www.googleapis.com/auth/calendar.readonly"
})
.then(() => {
gapi.auth2
.getAuthInstance()
.isSignedIn.listen(that.updateSigninStatus);
that.updateSigninStatus(
gapi.auth2.getAuthInstance().isSignedIn.get()
);
that.setState({
apiLoaded: true
});
});
}
}
It works completely fine on a local environment, where I have a server running, but once I build my Electron app and run the app "natively", I get the following error: gapi.auth2.ExternallyVisibleError: Invalid cookiePolicy
I don't have an advanced understanding of APIs and Servers to figure this out but through research, I found something about the API not working from a "file://" protocol, which is the case on an Electron app.
Thoughts? Ideas?
I want to build an Ionic application with WordPress back-end.
I Installed JSON API user,and I want to use Facebook login, but I can not figure it out how I will call the token and pass it to the JSON page. Please any recommend any good article about these technologies, it will help a lot.
Thank you.
Its very easy, once you have configured Facebook.
You must have FB plugin
installed. Once you call facebook cordova plugin you will get token in response after you try to call fb.login.
And then you can call fb connect function and pass access_token
getWPToken(facebooktoken){
this.http.get('yourdomaindotcom/json-api/user/fb_connect/?
access_token='+token).map(res => res.json()).subscribe(data => {
console.log(data);
this.cookie = data.cookie;
this.storage.get('wp_cookie').then((val)=>{
this.storage.set("wp_cookie", this.cookie);
this.event.publish("cookie",this.cookie);
});
},
err => {
console.log("Oops!");
});
}
Rewriting this question to be clearer.
I've used passport-facebook to handle login with facebook on my site.
My front end is in Angular so I know now need to understand whats the correct way of calling that api route. I already have several calls using Angular's $http service - however as this login with facebook actually re-routes the facebook page can i still use the usual:
self.loginFacebook = function )() {
var deferred = $q.defer();
var theReq = {
method: 'GET',
url: API + '/login/facebook'
};
$http(theReq)
.then(function(data){
deferred.resolve(data);
})
return deferred.promise;
}
or is it perfectly ok/secure/correct procedure to directly hit that URL in a window location:
self.loginFacebook = function (){
$window.location.href = API + '/login/facebook';
}
Furthermore, from this how do I then send a token back from the API? I can't seem to modify the callback function to do that?
router.get('/login/facebook/callback',
passport.authenticate('facebook', {
successRedirect : 'http://localhost:3000/#/',
failureRedirect : 'http://localhost:3000/#/login'
})
);
Thanks.
I was stacked on the same problem.
First part:
I allow in backend using cors and in frontend i use $httpProvider, like this:
angular.module('core', [
'ui.router',
'user'
]).config(config);
function config($httpProvider) {
$httpProvider.defaults.useXDomain = true;
$httpProvider.defaults.headers.common['X-Requested-With'];
$httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';
};
The second part:
<span class="fa fa-facebook"></span> Login with facebook
This call my auth/facebook route that use passport to redirect to facebook page allowing a user to be authenticated.
If the user grant access, the callback /api/auth/facebook/callback is called and the facebook.strategy save the user with the profile data.
After saving the user, i create a special token with facebook token, id and email. This info is used to validate every time the user access to private states in the front.
My routes are something like this:
router.get('/facebook', passport.authenticate('facebook',
{ session: false, scope : 'email' }));
// handle the callback after facebook has authenticated the user
router.get('/facebook/callback',
passport.authenticate('facebook',
{session: false, failureRedirect: '/error' }),
function(req, res, next) {
var token = jwt.encode(req.user.facebook, config.secret);
res.redirect("/fb/"+token);
});
In frontend i catch the /fb/:token using a state and assign the token to my local storage, then every time the user go to a private section, the token is sent to backend and validate, if the validation pass, then the validate function return the token with the decoded data.
The only bad thing is that i don't know how to redirect to the previous state that was when the user click on login with facebook.
Also, i don't know how you are using the callback, but you need to have domain name to allow the redirect from facebook. I have created a server droplet in digitalocean to test this facebook strategy.
In the strategy you have to put the real domain in the callback function, like this:
callbackURL: "http://yourdomain.com/api/auth/facebook/callback"
In the same object where you put the secretId and clientSecret. Then, in your application in facebook developers you have to allow this domain.
Sorry for my english, i hope this info help you.
Depending on your front-end, you will need some logic that actually makes that call to your node/express API. Your HTML element could look like
<a class='btn' href='login/facebook'>Login</a>
Clicking on this element will make a call to your Express router using the endpoint of /login/facebook. Simple at that.
I'm using Laravel and Angular to write a web app.
In the front end Laravel is used to create the basic template, but otherwise controlled by Angular. In the back end laravel is used to create a restful API.
I have a few routes like this:
Route::group(['domain' => 'domain.com'], function() {
Route::get('/', ['as' => 'home', function () {
return view('homepage');
}]);
Route::get('/login', ['as' => 'login', function () {
return view('login');
}]);
//users should be authenticated before accessing this page
Route::get('/dashboard', ['as' => 'dashboard', function () {
return view('dashboard');
}]);
});
Route::group(['domain' => 'api.domain.com', 'middleware' => ['oauth']], function() {
Route::post('/post/create', ['uses' => 'PostController#store']);
Route::get('/post/{id}', ['uses' => 'PostController#show']);
//other API endpoints
// ...
});
I want to make sure my domain.com/dashboard URL is only accessed by authenticated users.
In my backend I have OAuth implemented for my API routes which makes sure the user accessing those routes are authentic. Laravel's Auth::once() is used by the OAuth library to make sure the user credentials are correct then generates an access_token. Since Auth::once() is a "stateless" function no session or cookies are utilized and I cannot use Auth::check() to make sure a user is authenticated before the dashboard page is rendered.
How should I go about checking to see if the user trying to access domain.com/dashboard is authenticated? Should I send the access_token in the header when I forward the user from /login to /dashboard? Or should I implement Laravel's a session/cookie based authentication?
EDIT: As per this: Adding http headers to window.location.href in Angular app I cannot forward the user to the dashboard page with an Authorization header.
In order to reuse my API for my mobile apps I STRONGLY prefer to use some sort of token based authentication.
I would advise to use JWT (JSON Web Tokens) to control for authentication.
I think there are several tutorials for their use with Lavarel and AngularJS. I'm more into Python and I use Flask, but the followings look interesting :
Simple AngularJS Authentication with JWT : the AngularJS configuration
Token-Based Authentication for AngularJS and Laravel Apps : the connection with Laravel
JSON Web Token Tutorial: An Example in Laravel and AngularJS
Pierre was right in suggesting JWT for your token based auth.
When the user successfully logs in, before you finish the request, you can create a JWT and pass that back to the client. You can store it on the client (localStorage, sessionStorage) if you want. Then on subsequent requests, put the JWT inside of your Authorization header. You can then check for this header in your middleware and prevent access to your API routes if the token is valid. You can also use that token on the client and prevent Angular from switching routes if the token doesn't exists or isn't valid.
Now if you are trying to prevent the user from accessing the page entirely on initial load (Opens browser, goes straight to domain.com/dashboard), then I believe that is impossible since there is no way to get information about the client without first loading some code on the page.
Not sure about Angular, as I have never used it, but have you tried targeting a controller with your dashboard route? For example
Route::get('/dashboard', [
'uses' => 'UserController#getDashboard',
'as' => 'dashboard',
'middleware' => 'auth'
]);
UserController.php (I'm assuming you have a blade called dashboard.blade.php)
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Session;
class UserController extends Controller
{
public function getDashboard()
{
if(Auth::user()) {
return view('dashboard');
} else {
redirect()->back();
}
}
}
Also, you could always group whichever routes you want to protect with this (taken from the Laravel 5.2 documentation):
Route::group(['middleware' => 'auth'], function () {
Route::get('/', function () {
// Uses Auth Middleware
});
Route::get('user/profile', function () {
// Uses Auth Middleware
});
});
EDIT: Regarding the session token, your login blade should have this in its code:
<input type="hidden" name="_token" value="{{ Session::token() }}">
When the /dashboard HTML loads, does it already include data specific to the user's account?
I would suggest to load the /dashboard HTML separately from the user's data, and hide the dashboard items with ng-cloak while Angular loads the data to populate it.
Redirect to /dashboard URL
Load (static?) dashboard HTML / Angular app, hiding all parts with ng-cloak.
Have Angular access the API using the access_token to load all dashboard data.
Revealing the parts of the dashboard when the data from the API comes in, or showing an error message if the access_token wan't valid.
That way, your /dashboard HTML could actually be just a static HTML file and directly served by the web server and cached by any proxy on the way.
If that isn't an option, you could put your access_token into a cookie with Javascript that runs on the /login view, then redirect to /dashboard, then have your server-side /dashboard view read the cookie to check if the access_token is valid. But that sounds messy and mixes up things that should be separated.
#Pierre Cordier #Mr_Antivius Thank you guys for your answer, it helped me get insight into the problem and allowed me to tinker with with JWT but ultimately did not product a solution for me.
To allow only authenticated users to access domain.com/dashboard I had to implement a hybrid session and OAuth authentication system. I decided to go with Sentinel (instead of Laravel's out of the box auth system) because it has a user permission system I need in other places in my app. I use this library for the OAuth Server.
Here is what I do in my controller:
POST domain.com/auth/authenticate:
public function processLogin(Request $request)
{
$credentials = [
'email' => $request->input('username'),
'password' => $request->input('password'),
];
try
{
$sentinel = Sentinel::authenticate($credentials);
}
catch (\Cartalyst\Sentinel\Checkpoints\ThrottlingException $e)
{
$response = ['error' => [$e->getMessage()]];
$httpStatus = 429;
return response()->json($response, $httpStatus);
}
catch (\Cartalyst\Sentinel\Checkpoints\NotActivatedException $e)
{
$response = ['error' => [$e->getMessage()]];
$httpStatus = 401;
return response()->json($response, $httpStatus);
}
if ($sentinel) //user credentials correct
{
//get oauth token
$oauthToken = Authorizer::issueAccessToken();
$response = ['success' => true, 'user' => ['id' => $sentinel->id, 'email' => $sentinel->email]] + $oauthToken;
$httpStatus = 200;
}
else
{
$response = ['success' => false, 'error' => ['Incorrect credentials']];
$httpStatus = 401;
}
return response()->json($response, $httpStatus);
}
Here is the method the OAuth library looks at to authenticate the user:
public function verifyAuth($email, $password)
{
$credentials = [
'email' => $email,
'password' => $password,
];
if ($user = Sentinel::stateless($credentials))
{
return $user->id;
}
else
{
return false;
}
}
This would create a response like so:
{
"success": true,
"user": {
"id": 1,
"email": "email#domain.tld"
},
"access_token": "6a204bd89f3c8348afd5c77c717a097a",
"token_type": "Bearer",
"expires_in": 28800,
"refresh_token": "092a8e1a7025f700af39e38a638e199b"
}
Hope this helps someone out there
Side Note: I'm sending a POST request to domain.com/auth/authenticate instead of api.domain.com/auth/authenticate because I could not get domain.com/dashboard to recognize sentinel's cookie if I posted to api.domain.com. I've tried changing domain in config/session.php to .domain.com but still nothing. Maybe I'm doing something wrong?
I am having a very difficult time getting authenticated API requests to GitHub to work. I have created an authorized application in GitHub and connected it to my Auth0 account. I have no problems getting a user signed in using their GitHub account but once they are signed in I cannot make authenticated requests to the GitHub API (I am trying to set a GitHub webhook in one of the user's GitHub repos). All my requests are rejected for having incorrect credentials.
I have the JWT issued by Auth0 being sent along in each request to the GitHub API endpoint but it appears as though this is not sufficient. The Auth0 profile that comes back from my user seems to have an access_token in it, but sending this along does not work either.
Here is what my Auth0 login code looks like (using the Angular API):
angular.module('myApp').controller('LoginCtrl', ['$scope', '$http', 'auth', 'store', '$location',
function ($scope, $http, auth, store, $location) {
$scope.login = function () {
auth.signin({
authParams: {
responseType: 'token' // I think this is the default but just in case
}
}, function (profile, token) {
// Success callback
store.set('profile', profile);
store.set('token', token);
$location.path('/');
}, function () {
// Error callback
console.debug("error logging in");
});
};
}]);
This works fine. They authorize the GitHub application tied to my organization's Auth0 account with its requested permissions without issue and land back in my application and I then have access to an Auth0 profile tied to their GitHub account, but then if I try and make an authenticated request to the GitHub API on their behalf:
var username = auth.nickname;
var repo = "some_user.github.io"; // todo: get repo from setup process
var url = "https://api.github.com/repos/" + username + "/" + repo + "/hooks/";
var conf = {
name: "web",
active: true,
config: {
"url": "https://webtask.it.auth0.com/api/run/wt-my-container_com-0/echo?webtask_no_cache=1",
"content_type": "json"
}
};
$http.post(url, conf).success(function(data, status) {
console.log("post successful:");
console.log(status);
console.log(data);
});
... GitHub rejects the request, either saying the request resource doesn't exist (to prevent private data leakage) or that I supplied bad credentials, depending on different variables (if I try supplying the "access_token" field provided in their Auth0 profile as a query param or supply my Auth0 application's client secret, etc).
I have scoured the documentation of both Auth0 and GitHub trying to figure out what the correct procedure is (for example, do I need to implement the whole OAuth2 token flow myself? it seems like Auth0 should be doing that for me) but nothing I have tried so far works, and nothing on Google has pointed me in the right direction. I have tried a number of other methods of doing this without success but I don't want to make this post too much longer. Any help would be greatly appreciated.
I figured it out. There were two problems: one, a trailing slash had crept in on the end of my API call to the GitHub endpoint, which evidently breaks something and causes GitHub to reject the request, and second, I had set things up to send along the Authorization header with every request as per the Auth0 guide here: https://auth0.com/docs/client-platforms/angularjs, specifically this part:
myApp.config(function (authProvider, $routeProvider, $httpProvider, jwtInterceptorProvider) {
// ...
// We're annotating this function so that the `store` is injected correctly when this file is minified
jwtInterceptorProvider.tokenGetter = ['store', function(store) {
// Return the saved token
return store.get('token');
}];
$httpProvider.interceptors.push('jwtInterceptor');
// ...
});
But GitHub does not like that since it does not contain the token it is expecting and will reject the request if it sees it. Once I removed the trailing slash and removed the above code, everything started working as expected.
Look at this gitHub page. It is something like this with angular:
//'common' will add the headder to every request.
$httpProvider.defaults.headers.common["Authorization"] = token YOUR_TOKEN;