I am building an API using Laravel which will be used by both my Mobile and Web Applications. I am confused regarding authentication.
Basically the web application will be used by users both in logged in state and visitor state.
How would authentication work in that case? If the API uses username/password to authenticate a user what about visitors?
Also, how do I make sure its the webapp and mobile app thats making a request to the API? How do I ensure that someone doesn't programatically doesn't access the API and its only my apps that can request access to data?
You have a routes file, and you will be able to apply a filter (Laravel 4) / middleware (Laravel 5) to those routes to protect them. Assuming that you are using L5 -
Route::group('api/v1', function() {
Route::group(['middleware' => 'api.auth'], function() {
Route::get('protected', function() {
return response()->json(['Authenticated Response'], 200);
});
});
Route::get('guest', function() {
return response()->json(['Guest Response'], 200);
});
});
Then you would need to create a middleware for api.auth - See http://laravel.com/docs/5.1/routing#route-group-middleware and http://laravel.com/docs/5.1/middleware
So what happens now is when you try to visit /api/v1/protected, Laravel will run the api.auth middleware before it lets the user go any further.
api/v1/guest will of course be able to be accessed by authenticated users and guest users because there is no middleware applied.
Related
I'm currently working on a personal project which involves a Quarkus REST API as a back-end, Keycloak as OpenId Connect Provider and a Vue app as front-end. I just can't wrap my head around how to make these three components play well together for user authentication while maintaining proper security.
According to draft v8 of OAuth 2.0 for Browser-Based Apps, the SPA shouldn't be the one to keep the access and (possibly) refresh tokens because they are hard to store securely in such a scenario. That means, the back-end must be acting as the Relying Party, initiating the OIDC Authorization Code Flow. I'd then either keep a session cookie with my SPA (which I'd prefer not to do, to keep the API stateless), or store the tokens inside a Secure, SameSite, HttpOnly cookie.
The approach is what I’m trying to accomplish, so far with little success.
Prototype implementation
My Quarkus app uses the quarkus-oicd extension.
The way I understand it, I have to add the following configuration to Quarkus' application.properties:
quarkus.oidc.application-type=web-app
quarkus.oidc.client-id=myClientId
quarkus.oidc.credentials.secret=********
quarkus.oidc.auth-server-url=http://127.0.0.1:8082/auth/realms/myRealm
The application-type=web-app being what tells Quarkus that it is responsible for initiating the authorization code flow. The alternative would be service, in which case Quarkus only validates bearer tokens the client sends to the API.
The API is running on port 8081 and only exposes a single sample resource:
#Path("/hello")
#Authenticated
public class ReactiveGreetingResource {
#GET
#Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "Hello RESTEasy Reactive";
}
}
This simple Vue component is meant as a proof-of-concept:
// FetchComponent.vue
<template>
<div>
<button v-on:click="fetchFromBackend">Fetch</button>
<p><b>Output:</b>{{ message }}</p>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
data() {
return {
message: "Click the button to fetch.",
};
},
methods: {
fetchFromBackend(): void {
this.message = "Waiting...";
fetch("http://localhost:8081/hello", {
credentials: "include",
})
.then((resp) => {
console.log(resp);
if (resp.redirected) {
window.location.assign(resp.url);
} else {
return resp.text().then((text) => (this.message = text));
}
})
.catch((reason) => (this.message = "Caught error: " + reason));
},
},
});
</script>
<style></style>
Desired outcome
I'd have expected that the call to the back-end without a valid token gets redirected to Keycloak's authentication page. The user would then enter their credentials, be logged in and redirected back to the SPA with an auth code. It calls the API again. On the back-channel, Quarkus exchanges the auth code against a token and forwards it to the client in form of a cookie. This cookie would be used to authenticate the user for any further API calls.
Actual outcome
When the back-end is called without a valid token, it redirects to Keycloak's login page, as expected. Apparently, though, there is simply no way to navigate to the redirected URL from JS. The fetch specification states: "Redirects (a response whose status or internal response’s (if any) status is a redirect status) are not exposed to APIs. Exposing redirects might leak information not otherwise available through a cross-site scripting attack." The redirect: 'manual' option in a fetch request is somewhat of a red herring. It doesn't do what one would expect and it certainly doesn't allow me access to the redirect URL.
What happens instead is that the browser transparently follows the redirect and tries to fetch the login URL. That doesn't work at all. It results in a CORS error, because Keycloak doesn't set the relevant headers (and I suppose it shouldn't, because this isn't how it's supposed to work).
I have no clue how to proceed from here but I presume that the answer is extremely obvious to more experienced people.
As a closing remark I'd like to add that this architecture wasn't the result of a very well-informed decision making process. I chose it mostly because:
Quarkus: Java is currently my primary language at my job
Keycloak: I wanted to try my hand at proper externalized IAM and SSO for a while now. This seemed a good opportunity.
Vue: I wanted something to train my JS skills and which would look good on my resume. Any of the current batch of hot SPA frameworks would have fit the bill.
So, any answers along the lines of "that's a terrible setup, just don't do it, try X instead" are definitely also welcome, even though I'd still love to solve this puzzle as a matter of pride.
I am building my site with NextJs. I have a social login component where users can login via e.g. facebook Login. From the social login component (e.g. Facebook login) I get back user data (name, email) into my custom _app . So far so good.
With this user data, I want to create (or identify) an user on my headless wordpress backend. I want to use the Wordpress REST API for that. So I created an wordpress API restpoint which recieves user data, creates the user in wordpress if he is not existing yet, and then returns a JWT access token for calling other wordpress API restpoints where the user then can create some user specific data in my wordpress DB via my website.
What is the best approach to do this with Nextjs and a custom express server? My first idea was to use the new API Route feature and created a pages/api/test.js page like the example in the doc shows.
export default function handle(req, res) {
res.send({some:'json'})
}
So the whole flow starts in _app when getting the user data from the social login component. My first approach:
handleFBSocialLogin = (user) => {
//pesudo code:
//fetch("/api/test") with user data
}
When doing this my api/test.js is called and inside that i could then call my Wordpress API to get the token back, right?
But then i want to store the token server-side in my custom express server session, but how do i do that now?
And how do i read it from there in later requests to other wordpress API restpoints?
And - does that approach makes sense at all ?
Appreciate any input!
Where have I to authenticate in a SPA application using laravel and vuejs? I'm developing a normal web application with laravel and blade. Nothing out of ordinary, but, now, I'm trying to make a spa application using laravel and vuejs - backend separeted from frontend. Where would I have to authenticate in this example? In php routes or vuejs routes or both? My laravel app, only laravel, it works as expected, user permissions, user session, a normal application but in vuejs, how I can do the same verifications as well?
Without knowing you exact Laravel authentication setup I would just say you authenticate through ajax at the same route as you do in Laravel. In a fairly standard setup using axios I do it like this.
ajaxLogin(){
axios.post('/login',{
email: this.loginEmail,
password: this.loginPassword
}).then(function (res) {
this.getCrsfToken(); //refresh crsf token
}.bind(this));
}
Notice the getCrsfToken function here. This may be necessary if your SPA (page) is not being refreshed when logging out and back in. Like in the case of the session expiring while the browser window is open. You would use something like the following to refresh the crsf token if you are including it the standard Laravel way in the header.
In your Routes or Controller
Route::get('/getToken', function(){
return csrf_token();
})->middleware('auth');
In your Vue component
getCrsfToken(){
axios.get('/getToken')
.then(function(res){
// Refresh crsf token from session after login
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = res.data;
});
},
I would like to let my users sign up for my laravelbased application using facebook or similar through socialite.
My users use a mobile app on their smartphones, which accesses the API of my app. Those API-routes are currently secured through the auth.basic middelware
Route::group(['prefix' => 'api/v1', 'middleware' => 'auth.basic'], function()
{
// ...
});
The app interacts with the api restfully through basic protected urls..
https://user:pass#myapp.com/api/v1/item/1
Now, how can i enable my users to access my protected api-routes, when they have registered through socialite? Is there a Package or a predefined middelware? Also, how would the URLs look like? Is it even possible to allow API calls with both, normally registered users and those being registered through socialite at the same time?
I see 2 best options in here.
Easiest is to use simple auth middleware in combination of logging in to the API at first before any other API calls
Secondly you can create custom middleware and include a token in your API call that authenticates the user. Example of such call after logging and getting token is below. Middleware gets the url param and checks if this is correct.
https://myapp.com/api/v1/item/1?token=123456
How do I ensure that a user is logged in before I render a view using loopback?
I can loggin in the front end using my angular app. But I wanted to block anonymous users from viewing the page.
I thought it would be a header, something like headers.authorization_token, but it does not seem to be there.
I am looking for something like connect-ensurelogin for passport, without having to use passport.
This is the $interceptor that solves your problem.
This code detects 401 responses (user not logged in or the access token is expired) from Loopback REST server and redirect the user to the login page:
// Inside app config block
$httpProvider.interceptors.push(function($q, $location) {
return {
responseError: function(rejection) {
if (rejection.status == 401) {
$location.nextAfterLogin = $location.path();
$location.path('/login');
}
return $q.reject(rejection);
}
};
});
And this code will redirect to the requested page once the user is logged in
// In the Login controller
User.login($scope.credentials, function() {
var next = $location.nextAfterLogin || '/';
$location.nextAfterLogin = null;
$location.path(next);
});
Here is one possible approach that has worked for me (details may vary):
Design each of the Pages in your Single Page Angular App to make at one of your REST API calls when the Angular Route is resolved.
Secure all of your REST API Routes using the AccessToken/User/Role/ACL scheme that LoopBack provides.
When no valid Access Token is detected on the REST Server side, pass back a 401 Unauthorized Error.
On the Client Side Data Access, when you detect a 401 on your REST Call, redirect to your Logic Route.
For the smoothest User Experience, whenever you redirect to Login, store the Route the User wanted to access globally
(localStore, $RootScope, etc.) and redirect back there when the User
Logs in and gets a valid Access Token.
Here is the LoopBack Access Control sample: https://github.com/strongloop/loopback-example-access-control