0

I'm having issues finding the answer anywhere to an issue I'm having related to the (I think) Authorization header in an HTTP request I'm sending from Angular 4 to the Django Rest Framework API I've created. Lets get down to it:

EDIT: Confirmed that the problem relates to authorization since I am also using django-cors-headers now to rid myself of CORS issues for the 4200 port (since it is considered a different origin). The problem that remains is simply that I get the message "Unauthorized" when making requests towards the API. I'm starting to think it is an encoding issue since the following message is shown when I attempt the following request with httpie:

http GET http://localhost:8000/api/groups/ "Authorization: Basic admin:password"

And then the message is shown:

{
    "detail": "Invalid basic header. Credentials not correctly base64 encoded."
}

In settings.py, I've made sure that both a permission class and authentication class have been made available.

REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
    'rest_framework.authentication.BasicAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
    'rest_framework.permissions.IsAdminUser'
],

...

CORS_ORIGIN_WHITELIST = [
    'localhost:4200',
]

In views.py, this is perhaps where my fault is since the console error I get when trying to send the request from Angular -> Rest API is that 'No 'Access-Control-Allow-Origin' header is present on the requested resource.' which is untrue since it does NOT complain about this when I remove the authentication need.

class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all().order_by('-date_joined')
    serializer_class = UserSerializer
    permission_classes = (IsAdminUser, )
    authentication_classes = (BasicAuthentication, )

    def list(self, request):
        queryset = User.objects.all().order_by('-date_joined')
        serializer = UserSerializer(queryset, many=True, context={'request': request})
        return Response(serializer.data,
                        status=200)

The Angular dev server is running on localhost:4200 while django is left on its default of localhost:8000.

I'll include the urls.py for good measure:

from django.conf.urls import url, include
from rest_framework import routers
from backend.api import views
from django.contrib import admin

router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'groups', views.GroupViewSet)
router.register(r'info', views.InfoViewSet)

urlpatterns = [
    url(r'^api/', include(router.urls)),
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    url(r'^admin/', admin.site.urls),
]

NOTE that I can make the request and get a response just fine with httpie using the authorization header like so:

http GET http://localhost:8000/api/users/ -a admin:password

Finally, here is the Angular code for making the request (I included everything so that imports can be checked as well):

import { Component, OnInit } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  title = 'app';
  results: string[];

  constructor(private http: HttpClient) {}

  ngOnInit(): void {

    this.http.get(
      'http://localhost:8000/api/users/',
      { headers: new HttpHeaders().set('Authorization', 'Basic admin:password'), }
      ).subscribe(
        data => {
          this.results = data;
      },
        err => {
          console.log("ERROR RETREIVING USERS");
      });
  }
}

I have also imported HttpClientModule and listed it under 'imports' in my app.module.

1
  • Hi ..try to his.http.get<MYRETURNTYPE>(url) Commented Nov 18, 2017 at 12:46

3 Answers 3

3

Separate ports are considered different origins, so you will of course, get a Cross-Origin error (CORS) on localhost. This is a browser security feature alongwith your server.

Instal django-cross-header package for resolving cross-domain error.

Sign up to request clarification or add additional context in comments.

5 Comments

It does not seem to be a CORS issue, I have looked into django-cors-headers. If anything, there is a problem with Authorization but I cannot yet figure out whether it is the way I add the header, if its the django side choice of authentication or something else... I added django-cors-headers for good measure but nothing has changed.
See this. I had faced similar issues and one of the suggested reasons was that using auth enforces stricter policies by design. I used this and it got resoved. Difference was that we were using Angular 2 and django, but this issue is usually linked with browsers not front end framework.
Thank you for the help, I think using django-cors-headers solved part of the issue, I just didn't know there were two issues here! I FINALLY got it to work by using your solution AND encoding the Authorization header with a 'btoa' function for the username:password part.
You are welcome. If it helped, you can mark the answer as accepted and it can help others with the same issue (and me too :D ). Also describe or post a link if possible to your encoding solution for the angular part.
I added my own solution as well and explained a bit about why it was happening. It was quite hard to find information and the printouts were less than helpful. But thanks to you and httpie it finally works :D
1

I use the same Backend Framework , and the solution I've found was to build my project with the right host using

ng build --production -host=myDomain.com // try localhost -p 8080 in your case

and replace

Access-Control-Allow-Origin: 'http://localhost:4200'

with

Access-Control-Allow-Origin: '*'

Comments

1

The problem was solved in two ways. Firstly, I did not correctly ensure that CORS would be enabled from the origin of where Angular 4 was sending the request. @kmcodes solution of using django-cors-headers was a good one and I no longer had an issue with 'Access-Control-Allow-Origin' being missing after adding it to my project.

The second part of the problem was in the header I was putting on to the request sent by Angular 4. The following was the change I needed to make:

this.http.get(
      'http://localhost:8000/api/users/',
      { headers: new HttpHeaders().set('Authorization', 'Basic admin:password'), }
      ).subscribe(
        data => {
          this.results = data;
      },
        err => {
          console.log("ERROR RETREIVING USERS");
      });

To this:

this.http.get(
      'http://localhost:8000/api/users/',
      { headers: new HttpHeaders().set('Authorization', 'Basic ' + btoa('admin:password')), }
      ).subscribe(
        data => {
          this.results = data;
      },
        err => {
          console.log("ERROR RETREIVING USERS");
      });

I got the hint when using httpie to inspect my request and saw that when I didn't use the -a flag to add authentication parameters but rather the 'Authorization' header. This gave me an error stating that the request failed with error code 401, unauthorized, since the username:password part was not encoded with base64. In Angular 4 (and maybe before) btoa() solves this as above.

1 Comment

I also use requestbin when I am troubleshooting HTTP requests based issues.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.