Using django-okta-auth library: Problem Circular Login while running in LocalHost
I have been using the Okta platform and Django to develop a web application, and I am facing a situation in my localhost that I can't seem to circumvent. I sign into the Okta Sign-In Widget, it brings me to the Okta Verify and then redirects back to Okta Sign-In Widget in a circular pattern. I have the setup as follows for my settings.py:
INSTALLED_APPS = [
'appname',
'okta_oauth2.apps.OktaOauth2Config',
'rest_framework',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'okta_oauth2.middleware.OktaMiddleware'
]
AUTHENTICATION_BACKENDS = [
"okta_oauth2.backend.OktaBackend",
]
OKTA_AUTH = {
"ORG_URL": "dev.okta.com",
"ISSUER": "https://dev.okta.com/oauth2/default",
"CLIENT_ID": os.getenv("client_id"),
"CLIENT_SECRET": os.getenv("client_secret"),
"SCOPES": "openid profile email offline_access", # this is the default and can be omitted
"REDIRECT_URI": "http://localhost:8000/accounts/oauth2/callback",
"LOGIN_REDIRECT_URL": "http://localhost:8000/redirect-user/", # default
"CACHE_PREFIX": "okta", # default
"CACHE_ALIAS": "default", # default
"PUBLIC_NAMED_URLS": (), # default
"PUBLIC_URLS": (), # default
"USE_USERNAME": False, # default
}
I have the redirect_URI defined in my Okta dev box, and the login_redirect_url as well. This is my apps urls.py:
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include(("okta_oauth2.urls", "okta_oauth2"), namespace="okta_oauth2")),
path('accounts/login/', okta_views.login, name='login'),
path('accounts/oauth2/callback', views.custom_callback, name='callback'),
path('redirect-user/', view=views.login_redirect_view),
path('appname/Admin/', include("admin.urls")),
]
I have the following views.py:
import logging
logger = logging.getLogger("okta")
def custom_callback(request):
logger.info("==> Entered custom_callback view")
try:
code = request.GET.get("code")
state = request.GET.get("state")
logger.debug(f"Received code: {code}, state: {state}")
if not code or not state:
logger.warning("Missing 'code' or 'state' in GET params")
return HttpResponse("Missing 'code' or 'state' from Okta", status=400)
except KeyError as e:
logger.error(f"KeyError while accessing code/state: {e}", exc_info=True)
return HttpResponse("Missing 'code' or 'state' from Okta", status=400)
try:
from okta_oauth2.backend import OktaBackend
backend = OktaBackend()
logger.debug("Successfully imported OktaBackend")
except ImportError as e:
logger.error("Failed to import OktaBackend", exc_info=True)
return HttpResponse("OktaBackend not able to be imported", status=500)
try:
user = backend.authenticate(request, code=code, state=state)
user.backend = 'okta_oauth2.backend.OktaBackend' # or whatever your full backend path is
logger.debug("Manually set user.backend to OktaBackend")
logger.info(f"Authentication result: {user}")
except Exception as e:
logger.error("Exception during Okta authentication", exc_info=True)
return HttpResponse(f"Authentication failed: {str(e)}", status=401)
if user:
try:
login(request, user)
logger.info(f"User {user} logged in successfully")
logger.debug(f"Session key after login: {request.session.session_key}")
logger.debug(f"User is authenticated: {request.user.is_authenticated}")
em = OKTA_AUTH.get("LOGIN_REDIRECT_URL", '/')
logger.debug(f"Redirecting to: {em}")
return redirect(em)
except Exception as e:
logger.error(f"Exception during login/redirect: {e}", exc_info=True)
return HttpResponse("Login or redirect failed", status=500)
logger.warning("Authentication returned no user")
return HttpResponse("Authentication failed", status=401)
def get_okta_user_profile(user):
logger.info(f"==> Fetching Okta profile for user: {user}")
okta_user_id = user.username
okta_api_token = os.getenv("API_Token")
url = f'https://dev.okta.com/api/v1/users/{okta_user_id}'
headers = {
'Authorization': f'SSWS {okta_api_token}',
'Accept': 'application/json'
}
try:
response = requests.get(url, headers=headers)
logger.debug(f"Okta API response status: {response.status_code}")
if response.status_code == 200:
profile = response.json()['profile']
logger.info(f"Retrieved profile for user {okta_user_id}: {profile}")
return profile
else:
logger.warning(f"Failed to retrieve profile for {okta_user_id}. Status: {response.status_code}")
return {}
except Exception as e:
logger.error("Error fetching Okta profile", exc_info=True)
return {}
def login_redirect_view(request):
logger.info("==> Entered login_redirect_view")
user = request.user
logger.info(f"Authenticated user: {user}")
try:
profile = get_okta_user_profile(user)
role = profile.get("role", "User")
logger.debug(f"User role: {role}")
except Exception as e:
logger.error("Failed to retrieve user role", exc_info=True)
return JsonResponse({'error': 'Could not retrieve user role'}, status=500)
if role == 'Admin':
logger.info(f"Redirecting Admin user {user.username} to admin_home")
return redirect('admin_home')
else:
logger.info(f"User {user.username} redirected to JSON welcome message")
return JsonResponse({'message': f'Welcome {user.username} to the {role} Platform!'})
Before I implemented the Okta platform, my authentication system was working using a SQLite DB, and ModelBackend. I would like to know how I could solve the circular redirection of the login because in the terminal when I am troubleshooting my application I see the following it posts to the callback then it posts back to accounts/login.