0
0
Rest-apiComparisonBeginner · 3 min read

401 vs 403 Difference: Key REST API Status Codes Explained

The 401 Unauthorized status code means the user is not authenticated and must provide valid credentials, while 403 Forbidden means the user is authenticated but does not have permission to access the resource. In short, 401 is about missing or invalid login, and 403 is about insufficient rights.
⚖️

Quick Comparison

Here is a quick side-by-side comparison of HTTP 401 and 403 status codes.

Factor401 Unauthorized403 Forbidden
MeaningUser is not authenticatedUser is authenticated but forbidden
Authentication Required?Yes, user must log inNo, user already logged in
Permission Issue?No, identity unknownYes, access denied
Typical Use CaseMissing or invalid credentialsAccess denied despite valid credentials
Client ActionProvide valid login detailsNo point logging in again
Response HeaderWWW-Authenticate header includedUsually no authentication header
⚖️

Key Differences

The 401 Unauthorized status code indicates that the client request lacks valid authentication credentials. This means the server does not know who the user is because they have not logged in or their login token is missing or invalid. The server responds with a WWW-Authenticate header prompting the client to provide credentials.

On the other hand, 403 Forbidden means the client is authenticated and recognized by the server, but the server refuses to allow access to the requested resource. This is a permissions issue, where the user does not have the rights to perform the action or view the content, even though they are logged in.

In summary, 401 is about authentication failure (who you are), while 403 is about authorization failure (what you are allowed to do).

⚖️

Code Comparison

Example of returning a 401 Unauthorized response in a REST API when the user is not logged in:

python
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/data')
def get_data():
    auth = request.headers.get('Authorization')
    if not auth or auth != 'Bearer validtoken':
        return jsonify({'error': 'Unauthorized'}), 401, {'WWW-Authenticate': 'Bearer'}
    return jsonify({'data': 'Secret data'})

if __name__ == '__main__':
    app.run()
↔️

403 Forbidden Equivalent

Example of returning a 403 Forbidden response when the user is logged in but lacks permission:

python
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/admin')
def admin_panel():
    auth = request.headers.get('Authorization')
    if auth != 'Bearer admintoken':
        return jsonify({'error': 'Forbidden'}), 403
    return jsonify({'data': 'Admin panel data'})

if __name__ == '__main__':
    app.run()
🎯

When to Use Which

Choose 401 Unauthorized when the user has not provided valid authentication credentials or needs to log in. This tells the client to authenticate first.

Choose 403 Forbidden when the user is authenticated but does not have permission to access the resource. This tells the client that authentication succeeded but access is denied.

Using these codes correctly improves API security and helps clients understand what action to take next.

Key Takeaways

401 Unauthorized means authentication is missing or invalid.
403 Forbidden means authentication succeeded but access is denied.
Use 401 to prompt login, 403 to deny permission.
Include WWW-Authenticate header with 401 responses.
Correct use helps clients know whether to log in or stop trying.