Django OAuth Toolkit - Introspection Request: "Authentication credentials were not provided."

683 Views Asked by At

Good morning or afternoon even good evening!

I have been trying to achieve the separating resource server from the auth server using OAuth Toolkit with Django and I got stuck.

Tryed:

First, I have already tried the following:

  1. Follow the tutorial with this tutorial and it works when it comes to serving projects with python manage.py runserver.

  2. The whole structure is that I use Postmen as client and request to resource server and check the authenticated user with auth server so there is introspection process between resource and auth server.

Isuss:

As I mentioned, the whole idea works only when I serve project with python manage.py runserver. When deployed projects in Docker-Compose using Nginx and Gunicorn to serve projects, headache has come.

This was the final error - Max retries exceeded with url: /o/introspect/

When I tracked back to the root - Introspection: Failed POST to localhost:8000/o/introspect/ in token lookup

This is error in the client app - "Authentication credentials were not provided."

I found this issue is happened when the access token is expired or revoked and the system try to get a new access token to resource server from auth server.

Somehow, the introspection process is failed by for me an unknown reason!

Anybody hit this wall before?

Edit: (Thu Mar 4, 2021)

I found another reason that can more related to the exact issue!

As the docker compose create services that each service serves one container consisting of image of the project(Django). Therefore, each project is isolated from each other!

This results in A project can be harder to request to B project as the port for B project cannot be reach in the A project.

A potential solution may be using the Nginx server proxy name (which is gonna be the same as the name of each service in docker compose) to make a request.

I am still trying to handle this! If anyone can help that would be really appreciate!

Edit: (Thu Mar 4, 2021 5:07PM Taiwan) Problem Sovled

Solution is demoed!

1

There are 1 best solutions below

0
On BEST ANSWER

Before you READ: This solution is to handle projects using Django OAuth Toolkit deployed with Docker-Compose which is occurred the Failed Introspection Request issue

So first, let me demo you the docker compose structure:

version: "3.4"

x-service-volumes: &service-volumes
  - ./:/usr/proj/:rw,cached

services:
  ShopDjangoBN_Nginx:
    image: ${DJ_NGINX_IMAGE}
    ports:
      - 8001:8001
    volumes: *service-volumes
    environment:
      - NGINX_SHOP_HOST=${NGINX_SHOP_HOST}
    depends_on:
      - "ShopDjangoBN"

  ShopDjangoBN:
    image: ${SHOP_DJANGO_IMAGE}
    command: gunicorn -w 2 -b 0.0.0.0:8001 main.wsgi:application
    volumes: *service-volumes
    depends_on:
      - "ShopDjangoBN_Migrate"
    expose:
      - 8001

  ShopDjangoBN_CollectStatic:
    image: ${SHOP_DJANGO_IMAGE}
    command: python manage.py collectstatic --noinput
    volumes: *service-volumes

  ShopDjangoBN_Migrate:
    image: ${SHOP_DJANGO_IMAGE}
    command: python manage.py migrate
    volumes: *service-volumes


  OAuthDjangoBN_Nginx:
    image: ${DJ_NGINX_IMAGE}
    ports:
      - 8000:8000
    volumes: *service-volumes
    environment:
      - NGINX_OAUTH_HOST=${NGINX_OAUTH_HOST}
    depends_on:
      - "OAuthDjangoBN"

  OAuthDjangoBN:
    image: ${O_AUTH_DJANGO_IMAGE}
    command: gunicorn -w 2 -b 0.0.0.0:8000 main.wsgi:application
    volumes: *service-volumes
    depends_on:
      - "OAuthDjangoBN_Migrate"
    expose:
      - 8000

  OAuthDjangoBN_CollectStatic:
    image: ${O_AUTH_DJANGO_IMAGE}
    command: python manage.py collectstatic --noinput
    volumes: *service-volumes

  OAuthDjangoBN_Migrate:
    image: ${O_AUTH_DJANGO_IMAGE}
    command: python manage.py migrate
    volumes: *service-volumes

volumes:
  auth-data:
  shop-data:
  static-volume:
  media-volume:

There are two Nginx server services that handle Django's network ShopDjangoBN_Nginx and OAuthDjangoBN_Nginx in the docker-compose yml file! Generally speaking, if we serve projects without docker-compose and nginx, you wouldn't meet this issue. However you would meet this issue when it comes to the deployment using docker tech, I assume.

To set up the idea of Separate Server, You need to follow this tutorial and you will need to complete the following code in Django settings file for the Resource server project:

OAUTH2_PROVIDER = {
    ...
    'RESOURCE_SERVER_INTROSPECTION_URL': 'https://example.org/o/introspect/',
    'RESOURCE_SERVER_AUTH_TOKEN': '3yUqsWtwKYKHnfivFcJu', # OR this but not both:
    #'RESOURCE_SERVER_INTROSPECTION_CREDENTIALS' ('rs_client_id','rs_client_secret'),
    ...
}

The key here is the 'RESOURCE_SERVER_INTROSPECTION_URL' variable! This variable is used to request the Introspection Request from Resource to Auth server and therefore, this url is pretty recommended to be set correctly and it has to be the introspection endpoint in the Auth Server.

Next, if you still remember, the OAuthDjangoBN_Nginx, which handles any request for Auth Server, is a reverse proxy service! And technically speaking, the OAuthDjangoBN_Nginx is gonna be our host for the Auth Server. So... the introspection url in Resource server Django settings file will be like:

'RESOURCE_SERVER_INTROSPECTION_URL': 'https://OAuthDjangoBN_Nginx:<port>/o/introspect/'

And the nginx.conf

upstream OAuthDjangoBN {
    server OAuthDjangoBN:8000;
}

server {
    listen 8000;

    location / {
        proxy_pass http://OAuthDjangoBN;
        # proxy_set_header Host $NGINX_SHOP_HOST;
        proxy_set_header Host "localhost:8000";
        proxy_redirect off;
    }

    location /static/ {
        alias /usr/proj/OAuthDjangoBN/static/;
    }  
}

This proxy_set_header is better to be set with env variable, I found some solutions on the internet so wouldn't be a problem. It is also important to be set up as the reverse host name is gonna be OAuthDjangoBN_Nginx: which will be not recognised as a valid host name and therefore, set it up!

proxy_set_header Host "localhost:8000";

Alright, I think this idea can be a solution if someone has met or will meet the same issue. I also believe this can be still a confusion. Just let me know if you hit the wall!