At Symantec, we recently launched a technical re-design of our Lifelock backend systems for better performance, scale and enhanced security. As part of the initiative, Harmeek Singh Bedi, Magesh Varadharajan and myself were involved in building an Authentication / Authorization platform to cater to several security / product use-cases. The platform was envisioned to act as a framework that supports existing internal clients as well as on-board new / external clients.
In this article, I will describe a few technology choices we made and system design / paradigms we incorporated to achieve the same. Before getting into the technical details, a few product / security use-cases are as follows:
- Support authentication / authorization privileges for clients.
- Restrict individual clients to specific services (ex: member personal vs payment info) / operations within services (ex: read, write, delete).
- Prevent clients from cross-sharing data between them.
- Provide granular access for clients to access member's personal data.
- Log all events for trace-ability / audit purposes.
The platform supports REST-ful web service APIs built using SpringBoot framework with every API mandating a token generated as part of client authentication. We used the below mentioned technologies to achieve the same.
Technologies
OAuth 2.0
We enhanced an existing implementation that uses OAuth 2.0 protocol to define credentials / privileges / scopes for individual clients and authenticate them / authorize access to individual services. The implementation was made simpler with Spring Security OAuth framework that allowed us to simply focus on implementing our custom authentication scheme and storing generated tokens in our datastore. The system supports several grant types such as authorization code, password, client credentials and refresh token with each token configured to exist for a period of time.
The authentication platform is the initial point of entry for every client to authenticate itself and obtain a token before proceeding to access other services. While the clients using the platform on production are all internal, there is ongoing integration to onboard external clients as well using the same methodology.
JSON Web Token
We migrated from the existing implementation that returned UUID tokens to one that returns JSON Web Tokens. JWT is a compact, URL-safe representation of data that allowed us to store client information (privileges / access) as part of the token itself for quicker access.
The client information is stored in the form of headers / claims JWT library provides and supports several algorithms for us to sign / verify. We use HMAC with SHA-512 using a unique cryptographic key generated and stored on our data store. This ensures even a single compromised key cannot be used to verify any other tokens.
Encryption
The data stored as part of JWT claims is encrypted using a symmetric encryption key to protect client claims. In certain cases, the data is simply a hash of client information that is validated against our datastore instead of decrypting and validating cleartext info.
System Design / Constructs
In this section, I will discuss a few system design / constructs we designed to handle specific security and product use-cases.
Authentication Design
We introduced two constructs in our authentication system design to handle specific security use-cases.
Support for multiple schemes - We support multiple authentication schemes in our platform and provide a federated layer that would determine / authenticate user accordingly. An example would be authenticating Lifelock member vs customer service representative vs internal employees etc. The layer allows flexibility to incorporate new authentication schemes with minimal code / config changes.
- Support for multiple types - To authenticate a Lifelock member, we support multiple types to handle traditional authentication (username / password on web / mobile app) vs non-traditional one (service representative verifying a member via personal info).
Client Data Model
We had several varied requirements from multiple clients during the authentication process that required us to configure additional attributes for each client. To handle these, we developed a data model for clients that would, in addition to privileges / scopes, store these information as well. This model is maintained on our data store and created / updated by our operations team with appropriate privileges thereby providing the flexibility to support additional use-cases in future.
Client Configuration APIs
We built APIs for our operations team to be able to dynamically add / update / delete clients along with required privileges / token TTLs. This enabled new clients onboarding with requiring any code changes. We also provided functionality to be able to block clients if our security team identifies any credentials have been leaked.
Member Info across multiple clients
As mentioned before, a token generated is specific to a client and provides access only to services allowed for the client. This is enforced by mandating client credentials as part of every API call to ensure the client passing the token is the one that created it.
However, there were use-cases that required clients to pass on member data to other clients. An example would be a customer service representative viewing member's personal info via one client and requiring to navigate to another client to process member's payment. This would require the service representative to authenticate the member for each client and obtain / manage several tokens.
To handle this use-case, we developed a one-time token mechanism that a client could request for a destination client. Once the destination client receives this token, it could exchange it for a token of its own preserving the member information. This mechanism enabled our clients to generate tokens for other clients / share member info seamlessly without exposing their credentials.
Logging / Audit
Every token created is logged on our datastore for trace-ability and audit purposes with additional information such as client name, member info (if associated with a member), token type etc. This information is persisted for a sufficiently longer duration to support any audit queries from our operations team.
API Performance
The APIs authenticate several internal clients with an average throughput of ~ 1000 requests per minute, 95th percentile latency under 100 ms and an error rate under 0.001%.
What's next
While we work towards stabilization / resolving any news issues discovered / on-board new clients, there are a few ideas in the pipeline such as request throttling per client, enhanced client usage dashboard etc. besides new business use-cases.