I am new to Django and have built a basic application (Django 3.1) which uses session authentication and a simple login page (username + password) to login a django user. It works fine. I would like to use javascript (vue.js) on pages accessible to the logged in user to call Django REST APIs, hosted on the same Django application.
Despite lots of googling, no one seems to give a clear authentication example of a hybrid Django app, augmented with APIs. I have used lots of APIs before so am familiar with the authentication options. My issue is how to get credentials to the javascript loaded by django templates in a secure manner.
IDEALLY I would like:
User logs in with username/password
django redirects to PAGE B, AUTOMAGICALLY SOMEHOW inserting user's token into a cookie/sessionStorage
A javascript function on PAGE B gets credentials from cookie/sessionStorage and calls API (using all the various options supported by django-rest-framework)
My Questions:
Question 1 ==> in my do_login view function (below), after successful authentication with Djangos inbuilt login method, do I need to create a cookie in HttpResponse (e.g. token=XXXXXXX), so javascript can access it? Is this secure?
def do_login(request):
....
login(request, user)
...
#create token here and return to user somehow in cookie/sessionStorage
return render(request, 'hello/logged_in_ok.html')
So my javascript can do something like this (demo code only):
function onButtonClick(){
let token = sesssionStorage.getItem("django_gave_me_this_token");
let response = callGetAPISomehow(token, "https://demo/rest/api/account/1")
.....
}
Question 2 ==> Most view methods finish up with:
return render(request, 'blah/blah.html', {'data': blah})
How do I set the cookie in the response this way? There is no response object to access.
All help appreciated
Related
I have a .cshtml page, where a click on a button calls an API
Currently, my JS code looks like :
var headers = {};
headers["Authorization-Token"] = '#Model.ApiToken';
$.ajax({
url: "my-url",
type: "GET",
headers: headers
});
However, if the end-user opens the browser console, goes to the Network tab, searches for the generated cshtml, he can see :
var headers = {}
headers[Authorization-Token] = 'my_token'
The token can be seen in clear text
I can't call my API without this header, as the call is immediately rejected if the header is not present.
Is there a way to hide it to the end-user, and if so, how ?
Thank you
It is better to keep the tokens outside the browser, one option is to store the token inside the cookie (encrypted of course). ASP.NET Core can handle that for you automatically. Or in the backend as part of the user session.
An perhaps better option is to look at using the Backend For Frontend (a.k.a BFF) pattern to secure SPA applications.
See
Backend For Frontend Authentication Pattern with Auth0 and ASP.NET Core
The BFF Pattern (Backend for Frontend): An Introduction
Securing SPAs using the BFF Pattern (once and for all)
Is there a way to handle POST requests using the react-router-dom (npm) library?
Why? The payment gateway will redirect the user, who successfully payed, back to the platform. I can use a GET or POST request to transfer data with the redirection page. But I don't like having the data visible in the URL. Other options are always welcome, I'm using a REST API (Node.JS, Express) and a website/dashboard (ReactJS)
I get what you're after but you can't POST to the browser. If you're uncomfortable passing data as GET params in a URL, you could:
store data in LocalStorage when user submits
deliver server-rendered, static HTML upon redirect that contains purchase information
asynchronously get user's purchase data upon page load with AJAX or fetch() (or your favorite data-grabbing util).
Since you're in a React world, I'd recommend the third option here. How to fetch data, build an API endpoint, store data, then display it goes well beyond the scope of this question so I'd suggest some Googling. Here's a starting point: https://code.tutsplus.com/tutorials/introduction-to-api-calls-with-react-and-axios--cms-21027
You can handle the POST request on your express server then redirect to a static page of your app :
app.post('/payment_webhook', (req, res) => {
const paymentOk = req.body.payment // handle POST data
if (paymentOk) {
res.redirect('http://app.com/payment_success');
} else {
res.redirect('http://app.com/payment_failed');
}
});
I was discussing the same with a friend and so far we saw 2 ways of doing this:
let the payment gateway return_url be an endpoint of the backend API (rails api), which will do the commit to the payment gateway (and probably updating the order in the BD), and then it will do a redirect back to your frontend app
store the gateway trasaction token on the order object in the DB, and let the payment gateway return_url to return to a dynamic order url, therefore, react will now which order should render, then asynchronously ask the backend (rails service) to extract the token from the order object and do the commit (confirmation) and update it's status and return the order object back to react, then react can now show if the order was successful or not.
we opted for option #2, since I feel that the frontend (react) shall be the main communication gateway to our system, and the only one communicating to the backend shall be the frontend.
UPDATE: option #2 did not work since you cant do POST to a react-app therefore, we make the return_url to be dynamic, and we immediately redirect to the frontend with a url with the order_id as query param, then, the frontend when tries to load the order, in the backend we do the payment gatway confirmation, update the order object and return the updated order object to the frontend
I am trying to use Vue.js as a frontend, and Django as the backend for an SPA.
In the frontend, I am leveraging Auth0 for user authentication and I want to send the id_token obtained from user registration/creation from Auth0 to the backend to create specific user profiles in real-time.
How do I create user profiles on my django backend for every user when they register using Auth0 on vue.js on the frontend?
Previously, I was using the following code to enable profile creation once a user is created:
# Whenever a User account is created, it creates a profile for it too.
def create_profile(sender, **kwargs):
user = kwargs["instance"]
if kwargs["created"]:
user_profile = UserProfile(user=user)
user_profile.save()
post_save.connect(create_profile, sender=User)
def __str__(self):
return self.user.username
In simpler terms, this is what I am trying to achieve:
- User registers on the website
- Account is created by leveraging Auth0
- user_id from Auth0 is fetched and sent to the backend (Django) from the frontend (Vue.js)
- Django creates a user profile for the registered user in its backend postgresql database.
- User is now able to access his profile page http://website/profile once logged in. (Data for the profile is fetched from Django)
I am fairly new to Vue.js and Javascript. Although Vue.js is a breeze to use, but I can't seem to figure out how to replicate similar functionality in Vue.js with Auth0.
Any help/guidance/pointers in the right direction are appreciated.
Thanks.
You want to make Ajax calls - I recommend Axios - to communicate between your client and server sides. It's pretty straightforward, I've been using it with Vue.js & love it.
Something like:
in auth.vue:
axios.post('/yourUserRoute', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
If you make sure that you call this axios call every time you want to register a new user, your back-end will receive the correct informations for you to proceed on your server. I never touched Django so I'm not going to try and help you on the details, but this should give you a good start to work with!
I'm trying to get graph api data for public Facebook events rendered in an html document. The site I need to put it on is made with a website builder so I don't have control over the server that generates the html. I can only insert JavaScript code into the page.
The only solution I've found now is by using an app access_token in the client side request:
FB.api(
"/<event_id>?fields=start_time,description",
function (response) {
if (response && !response.error) {
console.log(response.start_time, response.description);
}
},
{access_token: "<app access token>"}
);
I've read through the docs on access tokens
and the JavaScript sdk docs, but the app token solution I've found is not secure (from the docs):
... app access token should never be hard-coded into client-side code.
I don't think the user access token is the flow I want because I don't want people to have to log in; it's only for public events. I don't think the page access token is right either.
Is there:
a way to use the Graph API for public events without requiring a user to log in or without introducing an insecurity?
or a way to make sharing my app access token with the world have no bad consequences?
I was wondering how can I track the current logged in user in a backbone.js app, Most of the views on the page need to know if the user is logged in or now and which user is logged in. What is the best method to achieve this?
I have session management on the server but how do I know which user am I dealing with in my backbone app and how do I know if he logged out thats the question
Also how do I know that a user has logged out using another tab etc? There should be a generic way to handle this stuff, like we have before filters in rails to manage such things. What method is used to achieve the same on the front end.
What I am currently doing is that when the homepage loads I have set from my server side rendered html a hidden field #current_user_id, which the my backbone app reads and sets a variable like the follwoing
window.MyApp =
Models: {}
Collections: {}
Views: {}
Routers: {}
currentUser: null
init: ->
#currentBusiness = $('#current_business').val()
new MyApp.Routers.Businesses
Backbone.history.start()
$(document).ready ->
MyApp.init()
Then my router sets up a ShowView which then sets ups other sub views on the page
class MyApp.Routers.AppRouter extends Backbone.Router
routes:
'': 'show'
show: ->
user = new Vocallocal.Models.user id: Vocallocal.currentBusiness
Vocallocal.currentBusiness = business
new Vocallocal.Views.BusinessesIndex model: business
business.fetch()
Here is the main ShowView
class MyApp.Views.ShowView extends Backbone.View
el: '#main'
template: JST['users/home']
initialize: ->
#model.bind 'change', #render, #
#details = new Vocallocal.Views.UserDetails model: #model
#logo = new Vocallocal.Views.UserLogo model: #model
#managePhotos = new Vocallocal.Views.ManagePhotos model: #model
render: ->
console.log('change has occured')
#
does the above code and setup makes sense. I am looking on general advice if I should make any changes to the above.
Thank you for you valuable input
--Abid
Our app is a fully separated client/server API architecture, including login.
When a user authenticates and authorizes with our server we send a JSON request with the relevant data over an HTTPS connection (this means due to CORS & IE, that our backend and our front end have to be served from the same site).
The backend returns an auth token.
Every authentication-required REST API requires this token to be sent along as an Authorization header over an HTTPS AJAX request. The server is set to reject any tokens not provided by our mechanism, and reject any connections from pages which aren't served by our severs.
We store this auth token in a cookie on the client side. If the auth token is invalid, missing, etc, our server returns an HTTP 401 which we trap and redirect the client to the login page if it occurs.
I also battled wrapping my head around authentication when developing client side apps. If you have ever worked with a 3rd party API (Facebook, Twitter) you will know that all authentication is done on the server side. Thats why #Pointy is correct. No authentication is done client side.
So If you are looking to access a secure part of your API, your username and password must be sent with every request, and checked on the server. This is definitely not the most secure way, and there are very few ways to get around this without an HTTPS connection. I am not sure what language you are developing your API in, but still this link is a very good read. Steve basically uses a simple protocol whereby the client sends an authorization token as a header in the HTTP request, and the server decodes that token to decide whether or not it is valid.
In answering your question, I would check if the user is valid. If he/she is, bootstrap your user model with an authentication token. This authentication token will be sent and decoded with every api request that requires authentication. I am no expert, so if there is any other way, please let me know. I am also still learning this.