Django drf-spectacular with FirebaseBackend auth - django-rest-framework

To give as much context as possible; I have two problems while using drf-spectacular to build my API documentation;
With my default configuration, I cannot even load the documentation's page because I have a custom auth backend (using firebase_admin 5.2.0), the swagger (or ReDoc) are part of my REST API, therefore, would have to pass a valid token to load the page allocated in the documentation's endpoint (which is not possible from a browser).
Second, and most importantly, I am not able to configure my custom firebase auth with drf-spectacular to implement a Swagger authentication method to execute against my API endpoints. I would be just fine having the possibility to add a token in the Swagger doc, do not need to have all Firebase auth credentials, URLs, and flow.
api/urls.py
router = routers.DefaultRouter()
urlpatterns = [
path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
path('api/schema/swagger/', SpectacularSwaggerView.as_view(), name='swagger'),
path('api/schema/redoc/', SpectacularRedocView.as_view(), name='redoc'),
# _____________________FIREBASE AUTH ______________________
path('api-auth/', include('rest_framework.urls')),
path('', include(router.urls)),
settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'auth.backends.FirebaseBackend',
],
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
}
I have unsuccessfully tried adding many different configurations to my SPECTACULAR_SETTINGS.
Thanks in advance!!

By default spectacular uses 'SERVE_PERMISSIONS': ['rest_framework.permissions.AllowAny'], which should allow opening the swagger page even if not authenticated. Maybe FirebaseBackend bails hard which prevents you ever getting to AllowAny. Try this to take Firebase out of the equation for the schema views:
SPECTACULAR_SETTINGS = {
...
'SERVE_PERMISSIONS': ['rest_framework.permissions.AllowAny']
'SERVE_AUTHENTICATION': [],
}
You need to write an OpenApiAuthenticationExtension for Firebase as it is not part of the spectacular at the moment.

Related

Where do I get the value for `shopOrigin` when using Shopify app bridge?

Throughout the documentation for the new App Bridge, Shopify refers to the shopOrigin value and how it's used to configure the Provider from app-bridge-react but they never specify how to get this value?
The react app is loaded inside of an iframe and the src includes the shopOrigin value as a query string param called shop, but when I try the following code I get the error window is not defined:
const params = queryString.parse(window.location.search);
const config = {
apiKey: process.env.SHOPIFY_API_KEY,
shopOrigin: params.shop,
};
1) Why would I be getting window is not defined in javascript code running in a browser?! This makes no sense to me
2) If this value can be read from of the provided libraries such as #shopufy/app-bridge-react please tell me how
Unless you're using a library tailored specifically to Shopify, you have to manually save the shop origin during OAuth authorization.
Hopefully this Shopify tutorial is of some assistance
The shopOrigin is available within your browser cookies.
If you followed the Shopify development for react and Node.js, you should already saved this after the Shopify authentification.
I am not sure what exactly is the need for shopOrigin, if you just wanted to go to admin section of the shop from client side you can use Redirect in app bridge. otherwise you can store the shop detail on server during auth process and create a get api to retrive the details on client side as needed.

Laravel Multi-Tenant Multi-Database Multi-Domain - Problem with default route

I'm studying about multi-tenant with Laravel and I'm having a problem with the routes. The main application works fine, however the main client domain (route / ) returns the 401 error configured in the middleware I created, but the other routes (login, register, etc) work perfectly.
If I put a prefix on the main application routes, then the / client route works normally, but I need the main application not to have a prefix since I want to use it to create the service submission and hiring system.
Anyone who has knowledge on this subject and can take a look at my code and help me find out why only the route is returning this error I will be very grateful.
If i access app.mydefaultapp works
If i access app.myclientapp doesn't works
If i access app.myclientapp/login(or any other route) works
https://pastebin.com/bHHux9sY
I solved the problem by creating a Provider with the same Middleware identification logic, and when accessing the main domain it dynamically loads the routes of the main domain.
$manager = app(ManagerTenant::class);
if ($manager->domainIsMain())
{
$this->registerTenantRoutes();
$this->registerTenantAdminRoutes();
}
https://pastebin.com/20SCsgfL

JWT with Angular and SpringBoot

I want to integrate a JWT authentication in my current Angular application which is connected to a spring boot backend.
I looked through quiet a lot of tutorials, but most of them did not fit, since they were connected to Auth0. I want to handle the usermanagement by myself.
I found this example:
Angular: https://medium.com/#juliapassynkova/angular-springboot-jwt-integration-p-1-800a337a4e0
Spring Boot: https://medium.com/#nydiarra/secure-a-spring-boot-rest-api-with-json-web-token-reference-to-angular-integration-e57a25806c50
Unfortunately, this Angular Frontend is Angular 4 and I'm using Angular 6 already. They use the 'angular2-jwt' which is not compatible with Angular 6. I have to use 'auth0/angular-jwt'.
My problem is, that after I use my login form, the browser opens again a login popup to login the backend. But even with the right credentials, it doesn't work. I'm guessing, that some credentials are missing in the request. In the app.module.ts are 2 old angular2-jwt code, which i don't know how to upgrade it to auth0/angular-jwt
export function authHttpServiceFactory(http: Http) {
return new AuthHttp(new AuthConfig({
headerPrefix: 'Bearer',
tokenName: TOKEN_NAME,
globalHeaders: [{'Content-Type': 'application/json'}],
noJwtError: false,
noTokenScheme: true,
tokenGetter: (() => localStorage.getItem(TOKEN_NAME))
}), http);
}
and
providers: [
{provide: AuthHttp, useFactory: authHttpServiceFactory, deps: [Http]},
]
Can someone help me with this issue. May be I'm wrong with my guessing and it could be something else?
A side note; I just changed my frontend but trying to connect to the backend from the example. If I'm using both front- and backend from the example, its working fine.
I have passed successful migration from angular2-jwt to auth0/angular-jwt several months ago. What you have to keep in mind while doing so is:
auth0/angular-jwt uses new angular HttpClient library, so if you want to use so, you have to migrate all your application to it (I suggest doing so anyway, new library is quite amazing)
new angular-jwt uses HttpInterceptors - this allows you to attach JWT directly to HttpClient filters chain. So you don't have to migrate your code above. You have to remove it completely and replace with interceptor initialization: (copy-paste from auth0/angular-jwt documentation):
import { JwtModule } from '#auth0/angular-jwt';
import { HttpClientModule } from '#angular/common/http';
export function tokenGetter() {
return localStorage.getItem('access_token');
}
#NgModule({
bootstrap: [AppComponent],
imports: [
// ...
HttpClientModule,
JwtModule.forRoot({
config: {
tokenGetter: tokenGetter,
whitelistedDomains: ['localhost:3001'],
blacklistedRoutes: ['localhost:3001/auth/']
}
})
]
})
export class AppModule {}
Remember to apply this code in your root module - then use your HttpClient without any changes and interceptors will apply JWT automatically. In case of problems - blame whitelistedDomains/blacklistedRoutes. These fields are very poorly implemented at the moment and are causing problems with regular expressions etc.
As migration is not straightforward, and took me a lot of time, feel free to ask about it. There's high probability, that I'll know the answers.

Sails.js 0.10 and passport

I was fiddling with sails.js and passport. Seems they are mend to be used together.
I have made the user models available in de db. And I am able to use the authentication by bcryptjs. This works, but dearly want to like to automatically authenticate every call, and mostly socket.io blueprint calls.
Still, I am searching for an elegant method to enable the sails.js way of integrating passport.
There are many examples, but seem a bit out-dated, not sure.
Important is the sockets. They need to be authenticated.
For e.g. every io.socket CRUD method, would be nice.
Kind regards
I found a link (http://www.bearfruit.org/2014/07/21/tutorial-easy-authentication-for-sails-js-apps/) that's pointing me in the right direction, but still not clear how this is reflected in for instance controllers
What I am trying to manage, is to have the custom api calls authenticated before they are called (configured in routes.js or by means of blueprints).
e.g:
OrderController:
module.exports = {
placeOrder: function (req, res) {
if (true === req.isSocket) {
// Pseudo code:
if (passport.authenticated(['user','admin'])) {
Order.save();
}
// end pseudo code
}
}
}
How should/is the above method secured, and I am I able to use for instance user-roles here?
I know two good solution for you question:
sails-auth
sails-generate-auth
Both implements passport, I recommend the first one, because it creates a layer to handle all authentication difficulties in model and services

Template-less Django + AJAX: Does Django's CSRF token get updated during the course of a browsing session?

My current setup is AngularJS + Django 1.5 and I have completely thrown away the use of Django's template engine (ie. the backend is pretty much an API server).
Since I am not using the csrf_token template tag, Django, in turn, does not set and send the csrftoken cookie in response. As instructed by the official docs, the ensure_csrf_cookie() decorator should be used to force the decorated view to send the csrftoken cookie.
I have applied the ensure_csrf_cookie() decorator to the view, which serves the first GET request that my web client calls at bootstrapping. With that, my web client gets a hold of the CSRF token and henceforth is allowed to call unsafe methods (ex. POST) to the server.
The above setup works fine only if the CSRF token remains the same until the browsing session ends.
Question: Does Django's CSRF token get updated during the course of a browsing session? If 'yes', does that mean I would need to apply the ensure_csrf_cookie() decorator to all the views I have?
1) Does Django's CSRF token get updated during the course of a browsing session?
Looks like the CSRF token is unique per session, but it is based in my observations, I have no "official" source. With Angular.js I use the following code without problems:
angular.module('app', ...)
.config(function($httpProvider) {
var cookies = document.cookie.split(';');
var csrftoken = _.find(cookies, function(v) {
return v.trim().indexOf('csrftoken=') == 0;
});
if(csrftoken) {
$httpProvider.defaults.headers.common['X-CSRFToken'] = csrftoken.split('=')[1];
}
})
Since I serve the HTML from Django, by the time Angular bootstraps the cookie is already there.
2) If 'yes', does that mean I would need to apply the ensure_csrf_cookie() decorator to all the views I have?
You can try CORS instead if CSRF. Otto Yiu maintains the django-cors-headers package, which is known to work correctly with REST framework APIs.
Some (untested) ideas to apply ensure_csrf_cookie():
monkey-patch APIView
create a CSRFCookie mixin and add it to your views
apply ensure_csrf_cookie() to your base classes
Giving support to the #Paulo Scardine ideas of applying the ensure_csrf_cookie() (which I consider valid, and useful), I would like to add a new one possible solution to it, if you definitely have to ensure_csrf_cookie() in all your views. You could write a custom middleware, and implement the logic that is there inside the ensure_csrf_cookie. Something like this:
On your app.middleware.py:
from django.middleware.csrf import get_token
class EnsureCsrfCookie(object):
def process_request(self, request):
# Forces process_response to send the cookie
get_token(request)
and of courses on your settings file add the middleware to the MIDDLEWARE_CLASSES:
MIDDLEWARE_CLASSES = (
.,
.,
.,
'app.middleware.EnsureCsrfCookie',
.,
.,
.,
)
It is just one idea more to face this problem. I hope it can be useful for somebody in the future.

Resources