authenticationflaskmicroserviceslogoutcoupling

How to decouple Auth services from other services in Microservice Architecture?


I have set of microservices, one of them is responsible for the authentication. All services use a shared library e.g. flask_jwt_extended, and a shared secret key for validating the incoming requests (e.g. using jwt_required decorator of the flask_jwt_extended ).

The main endpoints of the authentication service are UserLogin and UserLogout, some thing like that:

class UserLogin(Resource):

    def __init__(self, *args, **kwargs):
        self.parser = reqparse.RequestParser()
        self.parser.add_argument('email', type=str, required=True)
        self.parser.add_argument('password', type=str, required=True)


    def post(self):
        args = self.parser.parse_args()
        email = args.get('email')
        password = args.get('password')

        user = User.query.filter_by(email=email).first()
        if not user:
            return jsonify({'message': 'User does not exist'})

        if user.verify_hash(password):
            access_token = create_access_token(identity=user.email) 
            return jsonify({'access_token': access_token})
        else:
            return jsonify({'message': 'Wrong credentials'})


class UserLogout(Resource):

    @jwt_required
    def post(self):
        #Get the token and presist 
        jti = get_raw_jwt()['jti']        
        blocked_token = BlockedTokens(jti=jti) 
        db.session.add(blocked_token)
        db.session.commit()
        return jsonify({'message': 'logged out'})

Then in the other services I protect the endpoints using the jwt_required decorators, which simply validate the token of the incoming request (no thing special):

class PostDetails(Resource):

    @jwt_required
    def get(self, post_id):
        pass

And of-course all services share the same secret key:

app = app = Flask(__name__,)
app.config.from_mapping(JWT_SECRET_KEY=os.environ['JWT_SECRET_KEY']) 

The logout operation Ideally should goes as follows:

  1. store the access token in the database of the authentication service.
  2. For each request, block it if its token is in the blacklist.

My questions is:

  1. How to check for the blocked tokens in the other services (other than the auth service) without introducing further coupling between the services?

  2. Is it possible to further decouple the services i.e. by not sharing any libraries or secret key?

Edit: I have added further details and code snippets to the question, I hope it is better clarified and justified.


Solution

  • Based on the comments above.

    The short answer is yes it may be an overhead for auth service but that's the best way to decouple the services and keep your authentication logic confined into same service.

    Another way is to put the token in distributed cache and validate the token if it's blacklisted. You can only keep the tokens in cache that falls within the expiry time period of tokens. Say you have token expiry of 15mins , you will only check the tokens in cache that were generated in last 15 mins, the rest of the tokens are expired anyway and can be deleted . that would keep the size of cache small and be quicker to check. This cache service can be shared across all your services.

    Generally we have gateway service (public endpoint) validating the tokens and that service can call cache service to check if token is in cache blacklist.