Specific Inquiry
We want to implement JWT-based authentication and authorization management in a development project.
When implementing JWT (JSON Web Token)-based authentication and authorization management, we request help with specific implementation measures that can strengthen security by using client information.
User authentication and authorization management are increasingly implemented on the basis of JWT (JSON Web Token). Unlike the traditional session method, JWT has the advantage that the server does not need to hold authentication information, so its use is expanding alongside traditional session-based authentication. When developing the part that creates a JWT, there are several ways to strengthen JWT security by using characteristic information about the client, and it is appropriate to use them selectively according to the service environment and purpose.
Ways to identify the client by using characteristic client information when creating a JWT
1. Using the client IP address
This method includes the client’s IP address in the JWT payload. The client’s IP address is one of the most basic ways to identify a client. Each time the server receives a request, it compares the IP address in the JWT with the IP address of the requesting client and verifies that they match. This method is useful when the client’s IP address does not change, but it may not be suitable when the IP address is likely to change or when several IP addresses are used.
2. Using the client’s fingerprint
A device fingerprint is a unique identifier created by combining several attributes of the client device (for example, the user agent, screen resolution, installed fonts, and browser plug-ins). Because this information can identify the client’s device, it can be used effectively through the payload.
3. Using HTTP headers
Header information sent with an HTTP request (for example, User-Agent, Accept-Language, and Accept-Encoding) reflects the client’s browser, operating system, language settings, and similar characteristics. Applying this information to the payload can help identify the client.
4. Using a cookie and a session ID
A web application uses a cookie or a session ID to maintain the user’s session. This information can be used to identify a specific client session.
5. Using an OAuth/OpenID token
A token issued during authentication through a social-network login or an external authentication provider can be used to confirm the user’s identity. This token can be included in a JWT claim and used to identify the client.
6. Using a custom client ID
An identifier (ID) uniquely assigned to a user or a device within the application can be used. This may be an API key or a unique user ID generated by the application. Because each application has many unique identifying values, this method uses those values.
7. Using geographic location information
The client’s geographic location (for example, country, city, and region code) can be obtained from an IP address or GPS information. It can be used for identification based on the user’s location.
8. Using the time zone
The client’s time-zone information can be used as identifying information associated with the user’s geographic location. In some cases this identifier can be used for security verification or to improve the user experience.
<> Sample code – including the client’s IP address in a JWT claim
The Python sample below uses the client’s IP address. It is written with the PyJWT library and the Flask web framework. ‘/create_token’ receives a user ID and creates a JWT, and the /verify_token endpoint verifies the token that is provided. The client’s IP address is included when the token is created, and verification also checks that this IP address matches.
import jwt
import datetime
from flask import Flask, request, jsonify
app = Flask(__name__)
# Set the secret key - manage it more securely in a production environment
SECRET_KEY = 'your_secret_key'
# JWT creation function
def create_token(user_id, client_ip):
try:
# Set the token expiration time based on the current time
expiration_time = datetime.datetime.utcnow() + datetime.timedelta(hours=1)
# Include the user ID, client IP, and expiration time in the JWT payload
payload = {
'user_id': user_id,
'ip': client_ip,
'exp': expiration_time
}
# Create the JWT
token = jwt.encode(payload, SECRET_KEY, algorithm='RS256')
return token
except Exception as e:
# Handle an error
print(f"Token creation failed: {e}")
return None
# JWT verification function
def verify_token(token, client_ip):
try:
# Decode the token
payload = jwt.decode(token, SECRET_KEY, algorithms=['RS256'])
# Verify the client IP address
if payload['ip'] != client_ip:
raise jwt.InvalidTokenError("IP address mismatch")
return payload
except jwt.ExpiredSignatureError:
# Handle a token-expiration error
print("Token has expired")
return None
except jwt.InvalidTokenError as e:
# Handle other JWT errors
print(f"Invalid token: {e}")
return None
@app.route('/create_token', methods=['POST'])
def create_token_route():
user_id = request.json.get('user_id')
client_ip = request.remote_addr # Obtain the client's IP address through Flask
token = create_token(user_id, client_ip)
if token:
return jsonify({'token': token}), 200
else:
return jsonify({'error': 'Token creation failed'}), 500
@app.route('/verify_token', methods=['POST'])
def verify_token_route():
token = request.json.get('token')
client_ip = request.remote_addr # Check the client's IP address again
payload = verify_token(token, client_ip)
if payload:
return jsonify({'payload': payload}), 200
else:
return jsonify({'error': 'Token verification failed'}), 500
if __name__ == '__main__':
app.r0un(debug=True)
<> Sample code – using a client device fingerprint
The Python sample below identifies the client by using the user ID, the device fingerprint, and the expiration time.
from flask import Flask, request, jsonify
import jwt
import datetime
app = Flask(__name__)
# Set the secret key - manage it more securely in a production environment
SECRET_KEY = 'your_secret_key'
# JWT creation function
def create_token(user_id, device_fingerprint):
"""
Function that creates a JWT
user_id: user identifier
device_fingerprint: client device fingerprint
"""
try:
# Set the token expiration time based on the current time
expiration_time = datetime.datetime.utcnow() + datetime.timedelta(hours=1)
# Include the user ID, device fingerprint, and expiration time in the JWT payload
payload = {
'user_id': user_id,
'device_fingerprint': device_fingerprint,
'exp': expiration_time
}
# Create the JWT
token = jwt.encode(payload, SECRET_KEY, algorithm='RS256').decode('utf-8')
return token
except Exception as e:
# Handle an error
print(f"Token creation failed: {e}")
return None
# JWT verification function
def verify_token(token, device_fingerprint):
"""
Function that verifies a JWT
token: JWT to verify
device_fingerprint: client device fingerprint
"""
try:
# Decode the token
payload = jwt.decode(token, SECRET_KEY, algorithms=['RS256'])
# Verify the device fingerprint
if payload['device_fingerprint'] != device_fingerprint:
raise jwt.InvalidTokenError("Device fingerprint mismatch")
return payload
except jwt.ExpiredSignatureError:
# Handle a token-expiration error
print("Token has expired")
return None
except jwt.InvalidTokenError as e:
# Handle other JWT errors
print(f"Invalid token: {e}")
return None
@app.route('/create_token', methods=['POST'])
def create_token_route():
"""
Route that handles a token-creation request
"""
user_id = request.json.get('user_id')
device_fingerprint = request.json.get('device_fingerprint') # Obtain the client's device fingerprint from the request
token = create_token(user_id, device_fingerprint)
if token:
return jsonify({'token': token}), 200
else:
return jsonify({'error': 'Token creation failed'}), 500
@app.route('/verify_token', methods=['POST'])
def verify_token_route():
"""
Route that handles a token-verification request
"""
token = request.json.get('token')
device_fingerprint = request.json.get('device_fingerprint') # Obtain the device fingerprint to use during verification from the request
payload = verify_token(token, device_fingerprint)
if payload:
return jsonify({'payload': payload}), 200
else:
return jsonify({'error': 'Token verification failed'}), 500
if __name__ == '__main__':
app.run(debug=True)

