Authorization / Authentication microservice

December 17, 2018 ยท View on GitHub

Why

  • Get an opportunity to restrict users, so that they can't send requests to microservices without required credentials and permissions.
  • Provide for developers the solution for cases when OpenMatchmaking should work with the dedicated authorization/authentication server, withot communicating with existing authorization/authentication servers.
  • Necessary to store an information about users and let them to get (or refresh) an access token.
  • Required a storage for microservices permissions, so that they can be assigned to each existing user

Benefits of using

  • Can be used as the 3rd party authorization/authentication service for restricting an access in a pair with reverse proxy
  • A good choice for cases when Open Matchmaking project should work independently, without communicating with other services (not related to Open Matchmaking)

General information

General principles of auth/auth microservice can be shown with the following picture:

As you can see on the picture, the microservice is communicating with two different entities:

  1. With reverse proxy, which is sending requests to the certain microservice (in this case they are to Auth/Auth microservice) with a content inside.
  2. With internal parts of Open Matchmaking which are communicating via specially created message queues for auth/auth microservice. It's a hidden part, a don't provide any public APIs for endusers. Only for internal usage.

Entity relationship diagram

IMPORTANT: The tables "Group", "Permission" and "Microservice" will be updated by the other part of microservice, that will be handling requests from inner microservices after their instantiating.

User table

Field nameField typeConstraintsDescription
idUUIDPKA database unique object identifier
usernameVARCHARUNIQUE, NOT NULLA unique username
passwordVARCHARNOT NULLUser password hash
groupRelationMany-To-Many Relationship to Group

Group table

Field nameField typeConstraintsDescription
idUUIDPKA database unique object identifier
nameVARCHARNOT NULLA permission group name
permissionsRelationMany-To-Many Relationship to Permission

NOTE: On the first start of this microservice, the Group table should contain the following groups without permissions if they aren't created yet: "Game client".

Permission table

Field nameField typeConstraintsDescription
idUUIDPKA database unique object identifier
codenameVARCHARNOT NULLA permission name in "{microservice}.{resource}.{action}" format
descriptionVARCHARHuman-readable description about the permission

Microservice table

Field nameField typeConstraintsDescription
idUUIDPKA database unique object identifier
nameVARCHARUNIQUE, NOT NULLA unique Microservice identifier
versionVARCHARNOT NULLMicroservice version in "{major}.{minor}.{patch}" format
permissionsRelationOne-To-Many Relationship to Permission

API Endpoints

MethodEndpointUsageReturns
GET/auth/api/health-checkHealth check endpoint for API Gateways"OK"

RabbitMQ exchanges and queues

Exchanges

Exchange nameExchange typeOptions
open-matchmaking.auth.token.new.directdirectdurable=True, passive=False, auto_delete=False
open-matchmaking.auth.token.verify.directdirectdurable=True, passive=False, auto_delete=False
open-matchmaking.auth.token.refresh.directdirectdurable=True, passive=False, auto_delete=False
open-matchmaking.auth.users.retrieve.directdirectdurable=True, passive=False, auto_delete=False
open-matchmaking.auth.users.register.directdirectdurable=True, passive=False, auto_delete=False

Queues

Queue nameQueue optionsExchange nameUsageReturns
auth.microservices.registerdurable=True, passive=False, exclusive=False, auto_delete=Falseopen-matchmaking.directRegister a new microservice with permissions"OK" or a validation error
auth.token.newdurable=True, passive=False, exclusive=False, auto_delete=Falseopen-matchmaking.auth.token.new.directGet an access token (or an access token and refresh token)A new JSON Web Token or a validation error
auth.token.verifydurable=True, passive=False, exclusive=False, auto_delete=Falseopen-matchmaking.auth.token.verify.directReturns with whether or not a given access token is valid{"is_valid": true} or a validation error
auth.token.refreshdurable=True, passive=False, exclusive=False, auto_delete=Falseopen-matchmaking.auth.token.refresh.directValidates the refresh token, and provides back a new access tokenA new JSON Web Token
auth.users.retrievedurable=True, passive=False, exclusive=False, auto_delete=Falseopen-matchmaking.auth.users.retrieve.directReturns an information about the current userUser
auth.users.registerdurable=True, passive=False, exclusive=False, auto_delete=Falseopen-matchmaking.auth.users.register.directCreate a new user for the game clientUser or a validation error

Request and response examples

Registering microservice

For registering a microservice a developer should send a message to the auth.microservices.register queue with content inside in JSON format and content_type=application/json in headers. The content must contain the following fields:

Field nameParentDescriptionType
nameStores the name of the microservice.String
versionSpecifies the version of the registered microservice. Must specified in the major.minor.minor format.String
permissionsSpecifies a list of available permissions.List of objects
codenamepermissions[index].objectDefines the permissions name. Must specified in the microservice.resource.action format.String
descriptionpermissions[index].objectA short description of the certain permissions.String

An example of a request for registering:

{
    'name': 'my-microservice',
    'version': '0.1.0',
    'permissions': [
        {
            'codename': 'my-microservice.stats.retrieve',
            'description': 'Can retrieve the player statistics'
        },
        {
            'codename': 'my-microservice.stats.update',
            'description': 'Can update the player statistics'
        }
    ]
}

Creating a new JSON Web Token (JWT)

For creating a new JSON Web Token the user needs to send a message to the auth.token.new queue with a content that contains the following fields:

Field nameParentDescriptionType
usernameA user's login.String
passwordA password from the account.String

An example of the request from the reverse proxy:

{
    'username': 'some_user',
    'password': 'super_secret_password'
}

An example of the response:

{
  'content': {
     'access_token': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJhdXRoIiwiaWF0IjoxNTM4NTcwMTk0LCJleHAiOjE1NzAxMDYxOTUsImF1ZCI6IiIsInN1YiI6IiJ9.Z3zURZaWvX1p2B5dRqO1ma1-NC6Ip7blYIEyzylSi4s',
    'refresh_token': 'd49ac89a2da505b689281f70460d80e0'
  },
  'event-name': 'generate-new-token'
}

Each access_token contains a user_id in payload so that the any server could understand which user is doing the certain action under the resource.

Verifying the JSON Web Token (JWT)

For verifying the generated JSON Web Token the user needs to send a message to the auth.token.verify queue with a content that contains the following fields:

Field nameParentDescriptionType
access_tokenA generated JSON Web Token.String

An example of the request from the reverse proxy:

{
    'access_token': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJhdXRoIiwiaWF0IjoxNTM4NTcwMTk0LCJleHAiOjE1NzAxMDYxOTUsImF1ZCI6IiIsInN1YiI6IiJ9.Z3zURZaWvX1p2B5dRqO1ma1-NC6Ip7blYIEyzylSi4s'
}

An example of the response:

{
  'content': {
    'is_valid': true
  },
  'event-name': 'verify-jwt'
}

Refreshing the JSON Web Token (JWT)

For refreshing the JSON Web Token the user needs to send a message to the auth.token.refresh queue with a content that contains the following fields:

Field nameParentDescriptionType
access_tokenA generated JSON Web Token.String
refresh_tokenA generated JSON Web Token which using for generating a new access JSON Web Token.String

An example of the request from the reverse proxy:

{
    'access_token': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJhdXRoIiwiaWF0IjoxNTM4NTcwMTk0LCJleHAiOjE1NzAxMDYxOTUsImF1ZCI6IiIsInN1YiI6IiJ9.Z3zURZaWvX1p2B5dRqO1ma1-NC6Ip7blYIEyzylSi4s',
    'refresh_token': 'd49ac89a2da505b689281f70460d80e0'
}

An example of the response:

{
  'content': {
    'access_token': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJhdXRoIiwiaWF0IjoxNTM4NTcyMDI2LCJleHAiOjE1NzAxMDgwMjYsImF1ZCI6IiIsInN1YiI6IiJ9.UmRDMP6ocNacTD7clmCWwtO74PvFRwgjnvvf6k-bYY0'
  },
  'event-name': 'refresh-jwt'
}

Retrieving a user profile

For verifying the generated JSON Web Token the user needs to send a message to the auth.users.retrieve queue with a content that contains the following fields:

Field nameParentDescriptionType
access_tokenA generated JSON Web Token.String

P.S. In actual moment of time users can retrieve only his own user profile that associated with the generated token by Auth/Auth microservice.

An example of the request from the reverse proxy:

{
    'access_token': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiIiLCJpYXQiOjE1Mzk2NzY2NDYsImV4cCI6MTU3MTIxMjY0NywiYXVkIjoiIiwic3ViIjoiIiwidXNlcl9pZCI6IjViYjRjOTg0MWY4ZWMwMDA0NTI0YTU0ZiJ9.3jUYf-ffQVJjdERnSYXApTAfvA3QLsiIQIWDQKHniZE'
}

An example of the response:

{
  'content': {
    'id': '5bb4c9841f8ec0004524a54f',
    'username': 'some_user',
    'permissions': ['matchmaking.games.retrieve', 'matchmaking.games.update']
  },
  'event-name': 'get-profile'
}

Registering a new user

For verifying the generated JSON Web Token the user needs to send a message to the auth.users.register queue with a content that contains the following fields:

Field nameParentDescriptionType
userA unique username.String
passwordA password for the account.String
confirm_passwordA password confirmation.String

An example of the request from the reverse proxy:

{
    'username': 'some_user',
    'password': '123456',
    'confirm_password': '123456'
}

An example of the response:

{
  'content': {
    'id': '5bb4c9841f8ec0004524a54f',
    'username': 'some_user'
  },
  'event-name': 'new-game-client'
}