<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Moin Ul Haq</title>
    <description>The latest articles on DEV Community by Moin Ul Haq (@moinulhaq).</description>
    <link>https://dev.to/moinulhaq</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3805420%2Fb2644961-74d5-48e3-a841-0a1f06a92214.png</url>
      <title>DEV Community: Moin Ul Haq</title>
      <link>https://dev.to/moinulhaq</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/moinulhaq"/>
    <language>en</language>
    <item>
      <title>10 Browser-Based Tools That Replaced My Local Dev Utilities</title>
      <dc:creator>Moin Ul Haq</dc:creator>
      <pubDate>Sun, 19 Jul 2026 18:17:58 +0000</pubDate>
      <link>https://dev.to/moinulhaq/10-browser-based-tools-that-replaced-my-local-dev-utilities-19ji</link>
      <guid>https://dev.to/moinulhaq/10-browser-based-tools-that-replaced-my-local-dev-utilities-19ji</guid>
      <description>&lt;p&gt;I replaced my laptop in March and did the thing everyone threatens to do: no backup restore, fresh install, add software only when I genuinely miss it.&lt;/p&gt;

&lt;p&gt;Four months later, an entire category never came back. The one-job utilities — JSON prettifier, diff GUI, hash tool, the little menu-bar timestamp thing — are browser tabs now. Not web apps that ship my data to a server. Client-side pages: they load once, run entirely in the tab, and keep working when the Wi-Fi drops.&lt;/p&gt;

&lt;p&gt;That distinction is the whole point. Half of what I paste into these tools is production-adjacent — webhook payloads with customer emails, staging configs, API responses. So my filter is blunt: open DevTools, watch the Network tab while I paste, and close the tab forever if anything leaves. Everything below passes. Fair warning: the tool links here point at fewly, which is my own project. Every tool on this list has alternatives elsewhere; the client-side pattern is what I'm actually recommending.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. JSON Formatter
&lt;/h3&gt;

&lt;p&gt;Webhook debugging is where this earns its keep. Stripe hands you something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"evt_3PZk"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"invoice.paid"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"amount_paid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;4900&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"customer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"cus_QRt8"&lt;/span&gt;&lt;span class="p"&gt;}}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Readable? Barely, and that's the short version. I paste it into &lt;a href="https://fewly.tech/tools/json-formatter" rel="noopener noreferrer"&gt;fewly's JSON formatter&lt;/a&gt;, get proper indentation, and — the underrated part — validation for free, since the tool has to parse before it can pretty-print. Trailing comma in a hand-edited fixture file? It points at the line instead of letting me squint.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Text Diff
&lt;/h3&gt;

&lt;p&gt;A feature worked on staging and 500'd in production. The entire diagnosis was two &lt;code&gt;.env&lt;/code&gt; files pasted side by side: prod was missing &lt;code&gt;REDIS_TLS=true&lt;/code&gt; and carried a stale &lt;code&gt;API_BASE&lt;/code&gt;. Ninety seconds. No git, no vimdiff over SSH. Real code diffs still happen in the PR, obviously — this is for config-shaped text that never reaches version control: env files, nginx blocks, two versions of an email template. It also settles "did anything change on your side?" disputes with vendors, gently.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Hash Generator
&lt;/h3&gt;

&lt;p&gt;Two habits. Checksums first: when a vendor publishes a SHA-256 next to their SDK download, I actually verify it now, because verifying costs ten seconds. Second, quick digests while sketching — hashing a canonical string to design a cache key or a dedupe ID. Yes, &lt;code&gt;shasum -a 256&lt;/code&gt; exists and I still use it in scripts. But when the string is already on my clipboard and a browser is already open, the tab wins on pure motion economics.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Timestamp Converter
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;1752868800&lt;/code&gt; means nothing to me and never will. Logs speak epoch; incident reports speak "Friday around 9 p.m." A converter translates both directions and — the part I actually get wrong — handles timezones. When a user in Karachi reports something broke "last night," turning that into a UTC range I can grep is the real task, and doing offset math in my head at 1 a.m. has burned me more than once. The ISO 8601 output drops straight into API query params too, which ends the format guessing.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Cron Generator
&lt;/h3&gt;

&lt;p&gt;I've written cron expressions for a decade and still don't fully trust myself with field order under pressure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 3 * * 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three a.m. every Monday. Or every March? Or the 1st of the month? (It's Monday. But you double-checked, didn't you.) A generator that renders the schedule back into plain English before it lands in a crontab has prevented at least two "why did this run 31 times" incidents that I know of.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Encoder / Decoder
&lt;/h3&gt;

&lt;p&gt;OAuth debugging is nesting-doll decoding: a &lt;code&gt;redirect_uri&lt;/code&gt; URL-encoded inside a query string, a base64 blob inside an &lt;code&gt;Authorization&lt;/code&gt; header, occasionally both at once. Decode, read, fix, re-encode. If base64 still feels slightly mystical, &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Base64" rel="noopener noreferrer"&gt;MDN's glossary entry&lt;/a&gt; is the best ten-minute explanation I've found. After that, a paste box beats typing &lt;code&gt;atob()&lt;/code&gt; into a console you don't have open.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. YAML to JSON (and back)
&lt;/h3&gt;

&lt;p&gt;GitHub Actions taught me that I cannot see YAML indentation errors after 6 p.m. A matrix build kept skipping one OS; the file looked fine. Converted to JSON, the bug was instant — my entry sat one level too high, a sibling of &lt;code&gt;matrix&lt;/code&gt; instead of a child. YAML-to-JSON gives you the parser's-eye view, which is the view that matters. The reverse direction earns its spot whenever a machine-generated JSON config needs to become something humans can review without wincing. (The &lt;a href="https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions" rel="noopener noreferrer"&gt;workflow syntax reference&lt;/a&gt; and I remain on speaking terms regardless.)&lt;/p&gt;

&lt;h3&gt;
  
  
  8. CSV Viewer
&lt;/h3&gt;

&lt;p&gt;The 18 MB export problem: a spreadsheet app will open it, then immediately start improving it — dates reinterpreted for your locale, encodings guessed, columns reformatted. A read-only viewer does none of that. I skim, confirm the column names, spot-check that row 40,000 looks like row 4, close. Most of the time I never needed to edit the file. I needed to see it, and seeing shouldn't mutate.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Markdown and HTML, both directions
&lt;/h3&gt;

&lt;p&gt;Release notes get written once, in Markdown. Then the email tool wants HTML, a CMS field wants Markdown back, and someone in marketing wants the announcement "as a web page." Round-tripping through a converter beats hand-repairing &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt; soup in either direction. A recent favorite: a client sent brand copy as raw HTML scraped from their old site, and one paste turned it into Markdown I could commit to the project wiki. Small tool, weekly use, zero drama.&lt;/p&gt;

&lt;h3&gt;
  
  
  10. File Converter
&lt;/h3&gt;

&lt;p&gt;The surprise entry. Product managers send specs as &lt;code&gt;.docx&lt;/code&gt;; our docs live in the repo as Markdown. The file converter on the same hub does DOCX-to-Markdown in the tab — a 14-page spec becomes a reviewable pull request in about a minute, headings and lists intact. It goes the other way too, Markdown to PDF, for the people who want "a document" back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the terminal still wins
&lt;/h2&gt;

&lt;p&gt;None of this retires &lt;a href="https://jqlang.org" rel="noopener noreferrer"&gt;jq&lt;/a&gt;. Anything repeated, scheduled, or larger than ~50 MB belongs in a script, and jq's filter language is untouchable for surgical extraction mid-pipeline. The browser tools won a different niche: interactive, one-off, paste-shaped problems where startup cost dominates the actual work. Knowing which niche you're standing in is the skill.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual takeaway
&lt;/h2&gt;

&lt;p&gt;My Homebrew list is a third of its former size and I haven't missed the utility folder once. The full set of tabs I use lives at &lt;a href="https://fewly.tech/tools" rel="noopener noreferrer"&gt;fewly.tech/tools&lt;/a&gt; — 50-odd tools, free, client-side, no signup, and they work offline once loaded. But steal the pattern even if you skip the site: before trusting any "free online tool," open the Network tab and watch what leaves. If your data ships out for a task your laptop could do locally, find a better tab. My running total after four months: zero dollars, zero licenses, zero update prompts.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Suggested author bio:&lt;/strong&gt; Moin is the founder of &lt;a href="https://fewly.tech" rel="noopener noreferrer"&gt;fewly&lt;/a&gt;, a free URL shortener with 50+ free browser-based tools. He builds the kind of small utilities he wishes came pre-installed.&lt;/p&gt;

</description>
      <category>privacy</category>
      <category>productivity</category>
      <category>tooling</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Fix “Authentication Credentials Were Not Provided” Error in Django REST Framework JWT</title>
      <dc:creator>Moin Ul Haq</dc:creator>
      <pubDate>Sun, 08 Mar 2026 20:02:56 +0000</pubDate>
      <link>https://dev.to/moinulhaq/how-to-fix-authentication-credentials-were-not-provided-error-in-django-rest-framework-jwt-elo</link>
      <guid>https://dev.to/moinulhaq/how-to-fix-authentication-credentials-were-not-provided-error-in-django-rest-framework-jwt-elo</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;You’ve set up JWT authentication in your Django REST Framework API. Your token generation works perfectly. You’re sending the Authorization header with every request. But somehow, you keep getting this frustrating error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "detail": "Authentication credentials were not provided."
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you’ve been pulling your hair out over this issue, you’re not alone. This is one of the most common authentication problems Django backend developers face, and I’ve encountered it countless times while building production APIs at Elevabel and in my personal projects.&lt;/p&gt;

&lt;p&gt;The good news? This error usually has straightforward solutions once you understand what’s actually happening behind the scenes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Problem
&lt;/h2&gt;

&lt;p&gt;The “Authentication credentials were not provided” error occurs when Django REST Framework’s authentication system cannot find or validate the JWT token in your request. Despite what the error message suggests, this doesn’t always mean you forgot to send credentials—it often means the credentials aren’t being recognized properly.&lt;/p&gt;

&lt;p&gt;Here are the most common causes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Incorrect Authorization header format&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;- Missing authentication classes in settings or views&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;- CORS issues blocking headers&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;- Middleware interference&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;- Token prefix mismatch&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s walk through each solution systematically.&lt;/p&gt;
&lt;h2&gt;
  
  
  Solution 1: Verify Your Authorization Header Format
&lt;/h2&gt;

&lt;p&gt;The most common culprit is an incorrectly formatted Authorization header. Django REST Framework’s SimpleJWT expects a specific format.&lt;/p&gt;
&lt;h4&gt;
  
  
  Correct Format:
&lt;/h4&gt;

&lt;p&gt;Authorization: Bearer &lt;/p&gt;
&lt;h4&gt;
  
  
  Common Mistakes:
&lt;/h4&gt;

&lt;p&gt;Wrong: &lt;code&gt;Authorization: JWT &amp;lt;token&amp;gt;&lt;/code&gt;&lt;br&gt;
Wrong: &lt;code&gt;Authorization: Token &amp;lt;token&amp;gt;&lt;/code&gt;&lt;br&gt;
Wrong: &lt;code&gt;Authorization: &amp;lt;token&amp;gt; (missing prefix)&lt;/code&gt;&lt;br&gt;
Wrong: &lt;code&gt;Authorization: Bearer&amp;lt;token&amp;gt; (missing space)&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Testing with cURL:
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;curl -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGc..." \&lt;br&gt;
     http://localhost:8000/api/protected-endpoint/&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Testing with JavaScript (fetch):
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fetch('http://localhost:8000/api/protected-endpoint/', {
  method: 'GET',
  headers: {
    'Authorization': `Bearer ${accessToken}`,
    'Content-Type': 'application/json',
  },
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Testing with Python requests:
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import requests

headers = {
    'Authorization': f'Bearer {access_token}',
}

response = requests.get(
    'http://localhost:8000/api/protected-endpoint/',
    headers=headers
)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Solution 2: Configure Authentication Classes Properly
&lt;/h2&gt;

&lt;p&gt;Django REST Framework needs to know which authentication backend to use. You can configure this globally or per-view.&lt;/p&gt;
&lt;h4&gt;
  
  
  Global Configuration (settings.py):
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ),
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Per-View Configuration:
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
from rest_framework import generics
from rest_framework.permissions import IsAuthenticated
from rest_framework_simplejwt.authentication import JWTAuthentication

class ProtectedView(generics.ListAPIView):
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]
    queryset = MyModel.objects.all()
    serializer_class = MySerializer

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;em&gt;Important: If you set authentication_classes on a view, it overrides the global setting. Make sure JWT authentication is included.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Solution 3: Handle CORS Properly
&lt;/h2&gt;

&lt;p&gt;When building a separate frontend (React, Vue, etc.), CORS can block your Authorization header from reaching Django.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Install django-cors-headers:

pip install django-cors-headers


Configure CORS (settings.py):

INSTALLED_APPS = [
    # ...
    'corsheaders',
    # ...
]

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',  # Must be at the top
    'django.middleware.common.CommonMiddleware',
    # ... other middleware
]

# Development settings
CORS_ALLOWED_ORIGINS = [
    "http://localhost:3000",
    "http://127.0.0.1:3000",
]

# Allow credentials (important for JWT)
CORS_ALLOW_CREDENTIALS = True

# Explicitly allow Authorization header
CORS_ALLOW_HEADERS = [
    'accept',
    'accept-encoding',
    'authorization',
    'content-type',
    'dnt',
    'origin',
    'user-agent',
    'x-csrftoken',
    'x-requested-with',
]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Production Note: Never use CORS_ALLOW_ALL_ORIGINS = True in production. Always specify exact origins.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution 4: Check for Middleware Conflicts
&lt;/h2&gt;

&lt;p&gt;Custom middleware can sometimes interfere with authentication. If you have custom authentication middleware, ensure it’s not conflicting with DRF’s authentication.&lt;/p&gt;

&lt;h4&gt;
  
  
  Example of problematic middleware:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# DON'T DO THIS
class CustomAuthMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # This might strip the Authorization header
        if 'Authorization' in request.headers:
            # Custom processing that breaks JWT
            pass
        return self.get_response(request)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Either remove conflicting middleware or exclude API endpoints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class CustomAuthMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # Skip middleware for API endpoints
        if request.path.startswith('/api/'):
            return self.get_response(request)

        # Your custom logic for other endpoints
        return self.get_response(request)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Solution 5: Verify Token Prefix Settings
&lt;/h2&gt;

&lt;p&gt;SimpleJWT uses “Bearer” as the default prefix, but this can be customized. Make sure your frontend and backend agree on the prefix.&lt;/p&gt;

&lt;h4&gt;
  
  
  Check your JWT settings (settings.py):
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from datetime import timedelta

SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
    'AUTH_HEADER_TYPES': ('Bearer',),  # This must match your frontend
    'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you changed AUTH_HEADER_TYPES to something like ('JWT',), your Authorization header must use that prefix:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Authorization: JWT &amp;lt;token&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Best Practices for Production JWT Authentication&lt;/p&gt;

&lt;p&gt;Based on my experience building scalable backend systems, here are some best practices:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Use Short-Lived Access Tokens
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=15),  # Short-lived
    'REFRESH_TOKEN_LIFETIME': timedelta(days=7),     # Longer-lived
    'ROTATE_REFRESH_TOKENS': True,
    'BLACKLIST_AFTER_ROTATION': True,
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Implement Token Blacklisting
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSTALLED_APPS = [
    # ...
    'rest_framework_simplejwt.token_blacklist',
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Run migrations:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;python manage.py migrate token_blacklist&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Add Proper Error Handling
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from rest_framework.views import exception_handler
from rest_framework.response import Response

def custom_exception_handler(exc, context):
    response = exception_handler(exc, context)

    if response is not None and response.status_code == 401:
        response.data = {
            'error': 'Authentication failed',
            'detail': 'Please provide valid credentials',
            'code': 'authentication_failed'
        }

    return response

# In settings.py
REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'myapp.utils.custom_exception_handler',
}


4. Log Authentication Failures

import logging

logger = logging.getLogger(__name__)

class ProtectedView(generics.ListAPIView):
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]

    def handle_exception(self, exc):
        if isinstance(exc, AuthenticationFailed):
            logger.warning(
                f"Authentication failed for {self.request.path} "
                f"from IP {self.request.META.get('REMOTE_ADDR')}"
            )
        return super().handle_exception(exc)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Real-World Insight
&lt;/h4&gt;

&lt;p&gt;In my work at Elevabel, I’ve debugged this exact error dozens of times across different client projects. The most common issue? Frontend developers using Authorization: Token  because they’re used to Django’s built-in token authentication.&lt;/p&gt;

&lt;p&gt;One project had a particularly tricky case: the Authorization header was being stripped by an AWS Application Load Balancer security rule. Always test your authentication in the actual deployment environment, not just locally.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Another lesson learned: when building APIs consumed by mobile apps, implement detailed error responses. A generic “credentials not provided” message doesn’t help mobile developers debug whether the token is malformed, expired, or missing entirely.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Debugging Checklist&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you encounter this error, work through this checklist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Verify Authorization header format: Bearer &lt;/li&gt;
&lt;li&gt;Check that rest_framework_simplejwt is installed&lt;/li&gt;
&lt;li&gt;Confirm JWTAuthentication is in &lt;code&gt;DEFAULT_AUTHENTICATION_CLASSES&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Test the token is valid (not expired)&lt;/li&gt;
&lt;li&gt;Verify CORS is configured correctly&lt;/li&gt;
&lt;li&gt;Check for middleware conflicts&lt;/li&gt;
&lt;li&gt;Test with a simple cURL request to isolate frontend issues&lt;/li&gt;
&lt;li&gt;Review Django logs for authentication errors&lt;/li&gt;
&lt;li&gt;Confirm the endpoint requires authentication &lt;code&gt;(has IsAuthenticated permission)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;“Authentication credentials were not provided”&lt;/strong&gt; error in Django REST Framework JWT authentication is frustrating but solvable. In most cases, it comes down to header formatting, configuration issues, or CORS problems.&lt;/p&gt;

&lt;p&gt;Start with the basics: verify your Authorization header format and ensure JWT authentication is properly configured. If those don’t work, systematically check CORS settings and middleware conflicts.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Remember, authentication is the foundation of API security. Taking time to implement it correctly—with proper error handling, logging, and token management—will save you countless debugging hours down the road.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About the Author
&lt;/h2&gt;

&lt;p&gt;Moin Ul Haq is a backend web developer from Pakistan specializing in Django, REST APIs, and scalable backend architecture. As the Founder of Elevabel, a software and web development company, he builds production-ready web platforms and backend systems for clients globally. Moin shares his development insights and projects on GitHub at github.com/moin-ul-haq.&lt;/p&gt;

</description>
      <category>django</category>
      <category>djangorestframework</category>
      <category>restapi</category>
      <category>jwt</category>
    </item>
    <item>
      <title>LinkedIn OAuth in Django Using Allauth and OpenID Connect: A Practical Guide</title>
      <dc:creator>Moin Ul Haq</dc:creator>
      <pubDate>Thu, 05 Mar 2026 22:34:34 +0000</pubDate>
      <link>https://dev.to/moinulhaq/linkedin-oauth-in-django-using-allauth-and-openid-connect-a-practical-guide-38od</link>
      <guid>https://dev.to/moinulhaq/linkedin-oauth-in-django-using-allauth-and-openid-connect-a-practical-guide-38od</guid>
      <description>&lt;p&gt;&lt;em&gt;By Moin ul Haq – Software Engineer | Web Developer | Django Enthusiast&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Integrating LinkedIn OAuth in Django can be tricky, especially when you want smooth authentication and proper user data handling. In this guide, I’ll walk you through using Django Allauth with OpenID Connect for LinkedIn login, tackling real-world issues I faced while building client-facing web apps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4wohmg6y3oz6acmefi01.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4wohmg6y3oz6acmefi01.png" alt="Django allauth linkedin openid connect"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Why LinkedIn OAuth?&lt;/strong&gt;&lt;br&gt;
LinkedIn login is perfect when you want:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users to sign up quickly using their LinkedIn profiles.&lt;/li&gt;
&lt;li&gt;Secure authentication without managing passwords.&lt;/li&gt;
&lt;li&gt;Access to professional user data like email, name, and profile URL.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most tutorials cover Google or Facebook, but LinkedIn’s OpenID Connect implementation often confuses developers. Let’s solve it step by step.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1: Install Dependencies
&lt;/h3&gt;

&lt;p&gt;Start with Django and Allauth:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install django
pip install django-allauth[openidconnect]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure your Django project is set up with INSTALLED_APPS updated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSTALLED_APPS = [
    ...
    'django.contrib.sites',
    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    'allauth.socialaccount.providers.openid_connect',
]
SITE_ID = 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Configure LinkedIn as OpenID Connect Provider
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to LinkedIn Developer Portaland create a new app.&lt;/li&gt;
&lt;li&gt;Add OAuth 2.0 redirect URLs, e.g.,
&lt;code&gt;http://localhost:8000/accounts/openid/login/callback/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Note your Client ID and Client Secret.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 3: Add Provider in Django Admin
&lt;/h3&gt;

&lt;p&gt;Django Allauth allows dynamic configuration:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Login to Django Admin → Social Applications → Add LinkedIn.&lt;/li&gt;
&lt;li&gt;Select Site → &lt;code&gt;example.com&lt;/code&gt; (or localhost for testing).&lt;/li&gt;
&lt;li&gt;Enter Client ID and Secret Key.&lt;/li&gt;
&lt;li&gt;Use OpenID Connect as Provider type.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 4: Update URLs
&lt;/h3&gt;

&lt;p&gt;Add Allauth URLs to your &lt;code&gt;urls.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.urls import path, include

urlpatterns = [
    path('accounts/', include('allauth.urls')),
    ...
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5: Frontend Integration
&lt;/h3&gt;

&lt;p&gt;Add a simple login button in your template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;a href="{% provider_login_url 'openid_connect' %}?process=login"&amp;gt;
    Login with LinkedIn
&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚠️ Tip: Always use &lt;code&gt;{% provider_login_url %}&lt;/code&gt; instead of hardcoding URLs to avoid callback issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Handling Common Problems
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. “Invalid redirect_uri”&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make sure the redirect URI in LinkedIn app matches exactly with the one Django Allauth uses.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. User Email Not Returned&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LinkedIn requires r_emailaddress permission. Ensure your Allauth provider scope includes:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SOCIALACCOUNT_PROVIDERS = {
    'openid_connect': {
        'SCOPE': ['openid', 'email', 'profile']
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Tokens Not Saved&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allauth stores tokens in SocialToken. Always check the SocialApp and SocialAccount entries in Django Admin.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 7: Verify Everything Works
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Run server:&lt;br&gt;
&lt;code&gt;python manage.py runserver&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click Login with LinkedIn → authorize → redirected to dashboard.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check &lt;code&gt;request.user&lt;/code&gt; → should have LinkedIn email, name, and token.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Personal Branding Angle
&lt;/h3&gt;

&lt;p&gt;While implementing this, I realized professional networking login flows not only save development time but also improve user trust. As a developer, mastering OAuth integrations with Django is a strong portfolio highlight, showing clients that you can handle enterprise-grade authentication.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;💡 Pro Tip: Post your projects integrating OAuth on GitHub with proper README and a live demo. Recruiters and clients love this.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Using &lt;strong&gt;Django Allauth&lt;/strong&gt; + &lt;strong&gt;OpenID&lt;/strong&gt; Connect makes LinkedIn OAuth integration straightforward if you handle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provider scopes correctly.&lt;/li&gt;
&lt;li&gt;Redirect URIs precisely.&lt;/li&gt;
&lt;li&gt;Tokens and user data securely.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This setup not only improves user experience but also demonstrates your capability to solve complex authentication challenges professionally.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔗 About Me
&lt;/h3&gt;

&lt;p&gt;I’m Moin ul Haq, a software engineer building scalable Django applications. I write about real-world solutions, web development challenges, and software best practices. Check out my projects on &lt;a href="https://github.com/moin-ul-haq" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>django</category>
      <category>allauth</category>
      <category>oauth</category>
      <category>linkedin</category>
    </item>
    <item>
      <title>Fixing “Got AttributeError: 'NoneType' object has no attribute …” in Django REST Framework</title>
      <dc:creator>Moin Ul Haq</dc:creator>
      <pubDate>Wed, 04 Mar 2026 10:43:43 +0000</pubDate>
      <link>https://dev.to/moinulhaq/fixing-got-attributeerror-nonetype-object-has-no-attribute-in-django-rest-framework-4ln2</link>
      <guid>https://dev.to/moinulhaq/fixing-got-attributeerror-nonetype-object-has-no-attribute-in-django-rest-framework-4ln2</guid>
      <description>&lt;p&gt;Hi! I’m Moin Ul Haq, a Software Engineer from Bahawalpur specializing in Django backend development.&lt;/p&gt;

&lt;p&gt;If you’ve ever worked with Django REST Framework (DRF), you may have seen this frustrating error:&lt;br&gt;
&lt;code&gt;AttributeError: 'NoneType' object has no attribute 'id'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This usually happens when Serializer.save() or a nested serializer tries to access a field that doesn’t exist or is not properly passed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In this tutorial, I’ll show you:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why this error occurs&lt;/li&gt;
&lt;li&gt;How to reproduce it&lt;/li&gt;
&lt;li&gt;How to fix it cleanly in DRF&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the end, your serializers will handle missing data safely, and this error will become a thing of the past.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1: Understanding the Error
&lt;/h3&gt;

&lt;p&gt;This error typically occurs in DRF when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A nested serializer expects a related object but receives None&lt;/li&gt;
&lt;li&gt;A required field is missing in validated_data&lt;/li&gt;
&lt;li&gt;You call .id or access attributes on a NoneType object&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example scenario:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from rest_framework import serializers
from .models import Task, Project

class TaskSerializer(serializers.ModelSerializer):
    class Meta:
        model = Task
        fields = ['id', 'title', 'project']

    def create(self, validated_data):
        project = validated_data.get('project')
        print(project.id)  # ❌ Error occurs here if project is None
        return Task.objects.create(**validated_data)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a client POSTs without project, DRF will raise:&lt;br&gt;
&lt;code&gt;AttributeError: 'NoneType' object has no attribute 'id'&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 2: Proper Validation in Serializer
&lt;/h3&gt;

&lt;p&gt;The clean way to fix this is to validate the field before using it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class TaskSerializer(serializers.ModelSerializer):
    class Meta:
        model = Task
        fields = ['id', 'title', 'project']

    def create(self, validated_data):
        project = validated_data.get('project')
        if project is None:
            raise serializers.ValidationError({
                'project': 'Project must be provided.'
            })
        return Task.objects.create(**validated_data)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Now, if the client forgets project, they get a clear DRF validation error instead of AttributeError.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Optional Nested Objects
&lt;/h3&gt;

&lt;p&gt;Sometimes, the field may be optional. In that case, handle it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class TaskSerializer(serializers.ModelSerializer):
    class Meta:
        model = Task
        fields = ['id', 'title', 'project']

    def create(self, validated_data):
        project = validated_data.get('project')
        task = Task.objects.create(
            title=validated_data.get('title'),
            project=project if project else None
        )
        return task
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;If project is missing, the serializer still works&lt;/li&gt;
&lt;li&gt;No more “NoneType object has no attribute …” error&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 4: Always Test Your API
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Example POST request:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;{&lt;br&gt;
  "title": "Finish DRF Tutorial"&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;With validation: returns 400 Bad Request with message: "Project must be provided."&lt;/li&gt;
&lt;li&gt;Without validation: crashes with AttributeError&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ This ensures clean error handling and a better developer experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;The “Got AttributeError: 'NoneType' object has no attribute …” error is one of the most common issues in Django REST Framework, especially for beginners dealing with nested serializers or required fields.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key takeaways:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Always validate required fields before accessing attributes&lt;/li&gt;
&lt;li&gt;Use serializers.ValidationError for meaningful messages&lt;/li&gt;
&lt;li&gt;Optional fields should be handled with None checks&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  About the Author
&lt;/h3&gt;

&lt;p&gt;I’m Moin Ul Haq, a Software Engineer from Bahawalpur specializing in Django &amp;amp; Python backend development. I share tutorials, tips, and real-world solutions to help developers build scalable web applications.&lt;/p&gt;

&lt;p&gt;Follow me on Dev.to or check my GitHub: &lt;a href="https://github.com/moin-ul-haq" rel="noopener noreferrer"&gt;moin-ul-haq&lt;/a&gt;&lt;br&gt;
 for more backend projects.&lt;/p&gt;

</description>
      <category>django</category>
      <category>djangorest</category>
      <category>restapi</category>
      <category>python</category>
    </item>
  </channel>
</rss>
