When I request this, everything is ok and I get the data:
const get_players = async()=>{
const response = await fetch('http://127.0.0.1:8000/player_stats/api/players/')
const data = await response.json()
console.log(data)
}
But when I put permission_classes in views.py, I recive this in the console:
{detail: 'Authentication credentials were not provided.}
I am a beginner in Javascript so I wll hope you can understand.
I dont know how to put the authentication credentials in my fech.
Views.py
class PlayersView(ModelViewSet):
permission_classes = [IsAuthenticated]
serializer_class = PlayersSerializer
queryset = Players.objects.all()
def list(self, request):
queryset = Players.objects.all()
serializer = PlayersSerializer(queryset, many=True)
return Response(serializer.data)
def retrieve(self, request, pk=None):
queryset = Players.objects.all()
qs = get_object_or_404(queryset, pk=pk)
serializer = PlayersSerializer(qs)
return Response(serializer.data)
Urls.py
router = DefaultRouter()
router.register('players',views.PlayersView,basename='players')
app_name = 'main'
urlpatterns = [
path('',include(router.urls)),
]
Any idea?
The user behind the browser that runs the fetch needs to be authenticated, ie. logged in. There are multiple ways to do it. Refer to:
https://www.django-rest-framework.org/api-guide/authentication/
But basically, SessionAuthentication will use Django's user login system, and if you want access the API without logging in, you can use TokenAuthentication in which case, you need to add an HTTP header to your fetch request.
const get_players = async() =>{
const response = await fetch('http://127.0.0.1:8000/player_stats/api/players/', {
headers: {
'Authorization': `Token ${apiToken}`
}
})
const data = await response.json()
console.log(data)
}
your view class tell us that you cant access this page unless the user is authenticated (logged in), i suggest in case you are using django default auth (session auth) getting the cookie that stored in local storage like this : localStorage.getItem('csrf') and then set the session id:
localStorage.setItem('session_id',res.data.session_id)(this is just a dummy example, i have no idea how you set your session id in the backend) when you receive a response in the frontend, or if you are using token auth (like jwt), you should add to headers : headers: {'Authorization': Token ${apiToken}}
, one of the great jwt modules for drf and that easy to use with different endpoints is drf-simplejwt, more info: https://django-rest-framework-simplejwt.readthedocs.io/en/latest/
on a side note : i would not suggest using django default authentication, since it is hard to deal with, especially on the frontend side
Related
on development, the csrf cookie used to be set normally if it is not in available in application tab in dev tool, however on production, whenever i try to create a new post, it tells me " CSRF Failed: CSRF token from the 'X-Csrftoken' HTTP header has incorrect length."
however, the plot-twist here, is that with other post requests such as when you login, or signup, it works perfectly and fine, so i figured it seems to be a problem with create method in django (BUT with login , even though login works perfectly fine, and that i am logged in using session based authentication, it seem like session_id and csrf are invisible in application tab?
I assume it is because the website is on production and for security reasons, it wont show the session_id there.
However, whenever i try to look at network tab after i try to create a post and fail, it looks like x-csrftoken is undefined
but, there is another key called cookie which includes both csrftoken and session_id
please note that this only occur on production, i never faced such issue on development server, and look at settings.py code after the view code for more clarification (I added https://somedomain.com for the domain that need a csrf token allowed)
views.py:
class CheckAuthenticated(views.APIView):
def get(self, request):
if request.user.is_authenticated:
return Response("Authenticated")
else:
return Response("Not Authenticated",status=401)
class PostView(viewsets.ModelViewSet):
serializer_class = serializer.PostSerializer
def get_queryset(self):
queryset = models.Post.objects.all()
return queryset
#method_decorator(ensure_csrf_cookie)
def create(self,request):
authentication_classes = [SessionAuthentication]
permissions_classes = [IsAuthenticated]
post = serializer.PostSerializer(data=request.data)
if post.is_valid():
title = post.data['title']
description = post.data['description']
models.Post.objects.create(title=title,description=description,user=User.objects.first())
return Response("post created successfully.")
return Response("post creation failed.")
Now in frontend:
let handleSubmit = (e)=>{
e.preventDefault()
console.log(Cookies.get('csrftoken'))
axios.post('https://somedomain.com/posts/',post,{withCredentials:true,headers:{'X-CSRFToken':Cookies.get('csrftoken')}}).then((res)=>{
console.log(res.data)
}).catch((e)=>{
console.log(e.response.data)
console.log(Cookies.get('csrftoken'))
})
}
useEffect(()=>{
axios.get('http://127.0.0.1:8000/posts/').then((res)=>{
setPostList(res.data)
})
axios.get('http://127.0.0.1:8000/csrf/',{headers:{Authorization:null},withCredentials:true})
},[])
settings.py code:
ALLOWED_HOSTS = ['*']
ACCESS_CONTROL_ALLOW_ORIGIN = '*'
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
ACCESS_CONTROL_ALLOW_CREDENTIALS = True
ACCESS_CONTROL_ALLOW_METHODS = '*'
ACCESS_CONTROL_ALLOW_HEADERS = '*'
'''
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_PATH = '/'
'''
CSRF_COOKIE_SAMESITE = 'Strict'
CSRF_TRUSTED_ORIGINS = [ "http://127.0.0.1:3000",'http://127.0.0.1:8000','https://somedomain.com/']
SECURE_SSL_REDIRECT = True
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True
SECURE_HSTS_SECONDS = 60
CUSTOM_HEADERS = (
'Access-Control-Allow-Origin',
'Token',
'User-Type'
)
CORS_ALLOW_HEADERS = default_headers + CUSTOM_HEADERS
CSRF_COOKIE_SAMESITE = 'none'
I forgot to answer this question , Basically the frontend is served on a different subdomain, so the cookie samesite rule need to be set to None, in settings.py: change CSRF_COOKIE_SAMESITE = 'Strict' to CSRF_COOKIE_SAMESITE = 'None'
also if you are using Session Based Authentication (which require a csrf token for post requests by default, read the docs here) dont forget to add:
SESSION_COOKIE_SAMESITE = 'None' in settings.py
In my server, I have the following set up to grab the current logged-in user data:
const server = new Koa();
const router = new Router();
server.keys = [Shopify.Context.API_SECRET_KEY];
server.use(
createShopifyAuth({
async afterAuth(ctx) {
// Access token and shop available in ctx.state.shopify
const { shop, accessToken, scope } = ctx.state.shopify;
const client = new Shopify.Clients.Rest(shop, accessToken);
const data = await client.get({
path: 'users/current',
});
I am correctly getting the data but I would like to pass it to the front end.
I've tried storing the data in a global variable, I've tried storing the data in app.context and I've tried storing the data in ctx.state.
My idea is that I'd be able to grab the data and place it in the following so that I can make a fetch request to this /user endpoint:
router.get('/user', (ctx,next) => {
next();
console.log('check for ctx.state: ', ctx.state);
})
At the end of the day, I need access to the shop and accessToken from the Auth function which is why I'd need to pass the data instead of making the data request in the router.get function.
I haven't worked with Koa before so any help would be greatly appreciated. Thank you!
I figured this out in case this may be helpful to anyone else:
within the server.use function, I grabbed the data and stored it as the following:
server.context.db = data;
This context allows you to pass it around to other middlewares throughout the app. I then assigned ctx.body = ctx.db.body
in my router so that I could use a fetch request to hit that endpoint
I am trying to make a PUT request on my user model to edit username, bio etc. using Django Rest w/ React frontend.
When I make the PUT request at the url via the django rest client it works no issues. From the frontend, when I am not logged into any django user I can send the PUT request via AXIOS with no issues.
Once I am logged into any django user, even with superuser permissions, I get 403 Forbidden Error on my PUT request.
Here is my views.py:
class RetrieveUpdateDestroyUser(RetrieveUpdateDestroyAPIView):
serializer_class = UserCreateUpdateSerializer
queryset = CustomUser.objects.all()
lookup_field = 'id'
permission_classes = (AllowAny,)
def update(self, request, *args, **kwargs):
"""
PUT and UPDATE requests handled by this method.
"""
return super().update(request, *args, **kwargs)
In my frontend, this is how I make the PUT request (put request done with axios):
export class UserProxy extends BackendProxy {
updateUser(updatedUser, userID) {
let parameters = `user/${userID}`
return new Promise((resolve, reject) => {
this.putRequest(updatedUser, parameters)
.then(response => { resolve(response) })
.catch(error => {
console.log(error)
reject(error)
})
});
}
}
Just very confused as to why I don't get the 403 Forbidden when I am not logged into a django user, but I do when I'm logged in. I am using Python-Social-Auth also for logins if that matters.
Thanks!
One thing that can cause this is if you are using SessionAuthentication. Anonymous users get "authenticated" early in the auth process. Authenticated users go through an additional check of CSRF. If that fails, a HTTP 403 is thrown.
In my case, I realized I should be using GET, and CSRF does not apply (https://www.django-rest-framework.org/topics/ajax-csrf-cors/#csrf-protection).
So here's my problem. I have a dasboard page and i have programs page. The problem is on the programs page where i have SSR, because on dashboard page i call my saga on client-side and everything works like it should work.
Client side: The client sends the httpOnly cookie to my backend server and data is fetched from my backend for the use.
Server side: However for some reason when i call the same saga inside getServerSideProps of course {withCredentials: true} it doesn't send the token to my backend for some reason. Inside the req object i get from getServerSideProps inside req.headers.cookie i see the cookie, but it doesn't send it. So what's the solution to manually add it when calling it form getServerSideProps or?
The code:
export const getServerSideProps = wrapper.getServerSideProps(
async ({ store, req }) => {
store.dispatch(fetchprogramsRequest(req.url));
const cookies = cookie.parse(req.headers.cookie);
console.log('COOKIES', cookies); // HERE you can see the cookies
// end the saga
store.dispatch(END);
await store.sagaTask.toPromise();
}
);
The axios inside the saga:
const res = yield axios.get(url, { withCredentials: true });
This is called in both cases (client-side: works, server-side: doesn't)
I believe the cookie is stored on the client side (browser).
May be this can work, as long as you can make the cookie reach the saga.
// The axios inside the saga:
const res = yield axios.get(url, {
headers: {
Cookie: "cookie1=value; cookie2=value; cookie3=value;"
});
Another option, if you are using an access token is sending it like using an authorization header.
const res = await axios.get(url, {
headers: { Authorization: `Bearer ${token}` },
});
I stored my token to authenticate with my GraphQL API by adding a JWT to the header inside an apollo-link-states #client property.
query ClientToken() {
clientToken #client
}
I now want to use that token to authenticate my Apollo remote queries. Without using the local cache, doing the following works:
const authLink = new ApolloLink((operation, forward) => {
operation.setContext({
headers: {
Authorization: `Bearer GETMEATOKEN`
}
})
return forward(operation)
})
I'm struggeling to find a way to query this locally stored token inside this operation to add it where currently GETMEATOKEN appears.
Anyone has a suggestion if/who to query for a locally stored property inside an ApolloLink?
Thanks for all suggestions