Authentication and Authorization Best Practices

In the context of access to APIs, authentication is the process of verifying the identity of a user who is making an API request (verifying who a user is), and authorization is the process of determining whether that user has permission to access a particular API (verifying what a user is allowed to do).

In this blog, we will cover different types of authentication and authorization, best practices, and common mistakes.

1. Authentication: Methods and Use Cases

There are many ways to do API authentication, such as basic auth, API keys, JWT, OAuth, etc., and each has its benefits and trade-offs. There is no "one size fits all" answer to the question "What is the best API authentication method", because each method, although has some disadvantages, has its own ideal use cases. So, the best practice in deciding which authentication method to use is "it depends", not simply "choose the best for everything".

1.1 HTTP Basic Authentication (Basic Auth)

When we talk about authentication, we have to start with HTTP basic authentication, because, as the name suggests, it's the most "basic" way to implement API authentication: We put base64-encoded user:password pairs in the Authorization header field and send it over the internet. Since base64 is encoding, not hash or encryption, this method is insecure by default, unless it is used with HTTPS.

However, the insecure nature of basic auth doesn't necessarily mean it's useless:

  • In highly controlled internal networks where no north-south internet traffic is allowed, external access is completely blocked, and network traffic is monitored, basic auth over HTTP might be used (however, even in such environments, one of the best practices is to use HTTPS for better security).
  • Basic auth over HTTP might be used for simplicity for local development, or debugging and testing in a tightly controlled environment.
  • When some entry-level protection over non-sensitive data is needed, like if we are exposing some metrics of our app but we don't want everybody to access it except for Prometheus to scrape it, we can use basic auth to protect the metrics endpoint and configure basic auth in the [scrape_config](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config) of Prometheus.
  • When we don't need to handle HTTPS on a per-service basis and HTTPS is handled in general, like by a service mesh.

1.2 API Keys

An API key is a unique identifier (like a user/password pair) issued by an API provider and linked to users for access control. Similar to basic auth, it's not secure unless it's transmitted over HTTPS.

Like basic auth, the API key over HTTP could only be used in a controlled environment. But unlike basic auth, API key, as the name suggests, offers access to APIs, and APIs oftentimes need to be exposed to external networks. So, use HTTPS with API key authentication wherever possible.

Since the API key is similar to a basic auth credential or user/password, one of the best practices is to treat it like a password: Rotate it regularly. Even if we do so, it's still relatively long-term, so another best practice is to use temporary security credentials wherever possible: before creating some keys and start hacking, review alternatives to long-term access keys that are mentioned in the following sections.

If we choose to use an API key for authentication, there is one more best practice to follow: The API key must be used with every request.
But how?
Although we can set it in the query string, we shouldn't: web servers and browser histories often log URLs, including query parameters. This means our API key could be stored in various log files, making it accessible to anyone with access to those logs. The best practice here is to transmit API keys in the Authorization header, typically using the Bearer scheme: Authorization: Bearer YOUR_API_KEY. Like passwords, API keys should not be stored in plaintext but securely hashed.

1.3 JSON Web Token (JWT)

JWT is a compact, self-contained, stateless mechanism to transmit information as a JSON object. JWTs can be signed and/or encrypted. The server creates a signed and encrypted JWT that includes the user's identity when a user logs in. The client then includes the JWT in every subsequent request.

Based on how it works, we can already tell this is more secure than basic auth and API keys, but it has its limitations: We have to "log in" first (needless to say, must be done over HTTPS) to get the token for the subsequent requests. So, it might only be applicable where we can ask the user to "log in", like on websites. If our service is a pure backend API service with no option to log in, it's not applicable.

That said, JWT has its strong suit compared to basic auth and API key: Scalability. JWT eliminates the need (and the latency) for database lookups to verify the user's user/password/key/session, and the stateless nature makes it easy for horizontal scaling since each server can independently verify the token with no need for sticky sessions.

JWTs are commonly used with OAuth 2.0 and OIDC, which will be covered in the following sections.

1.4 OpenID Connect (OIDC)

OIDC is built on top of OAuth 2.0 (the golden standard for authorization, NOT an authentication, which will be covered a bit more later) to add an authentication layer.

The difference between the two is that OAuth 2.0 provides authorization, while OIDC provides authentication.

OpenID Connect enables an Internet identity ecosystem for easy and secure integration: For example, if a user wants to create an account at a news website, they may use Google to create their account rather than creating a new account on the news website. The OpenID provider (Google, in this case) handles the authentication processes and obtains the user's consent to provide specific information, such as a user profile, to the relying party (the news website, in this case).

For another example, for users who use cloud services extensively, we may have Kubernetes clusters but we can link service accounts to cloud IAM roles so that the cloud handles the authentication and authorization. In this case, we don't have to assign API keys to our workload to gain access to the cloud.

1.5 Multi-Factor Authentication (MFA)

MFA Significantly enhances security by requiring "multiple factors" (hence the name, Multi-Factor) for authentication. In practice, this can be combined with other authentication methods for high-risk operations or sensitive data. E.g. it can be used to secure the authentication at the IdP level in OIDC.


2. Authorization

Authorization verifies what a user is allowed to do. Let's start with one of the most common authorization methods in everyday use: OAuth.

2.1 OAuth 2.0

OAuth (Open Authorization) is a token-based authorization mechanism that enables users to grant third-party apps access to their data without having to share their login credentials. With greater flexibility and scalability than OAuth 1.0, OAuth 2.0 replaced 1.0 in 2012 and is now the de facto standard for online authorization.

For example, I use my Garmin fitness app (resource server and authorization server) to track my daily workouts, and now I want to create a new app "Nutriplan" (the client) to monitor my nutrition and calorie intake and consumption. In this case:

  • The Nutriplan app asks for access to resources on the Garmin app, which is granted by the user logging in to the Garmin app with the user/password, but the user/password is not shared with Nutriplan.
  • An authorization code is created and shared with Nutriplan. However, the authorization code can't be used to access user data in the Garmin App.
  • With the authorization code, the Nutriplan app requests an access token from the Garmin app's authorization server endpoint.
  • The Nutriplan client uses the access token to access my resources on the Garmin app to recommend nutrition plans according to my fitness data in the Garmin app.

During the whole process, my Garmin app login password isn't shared with Nutriplan but my data in my Garmin app is shared securely with third-party apps - access delegation without sharing credentials.

2.2 Scope-Based Authorization

OAuth 2.0 uses a scope-based authorization, where specific permissions are defined in scopes as a way to limit the amount of access that is granted to an access token. For example, an access token issued to a client app may be granted READ and WRITE access to protected resources, or just READ access. The client requests a scope during the authorization process and the user can then grant or deny these permissions.

2.3 Role-Based Access Control (RBAC)

Role-based access control (RBAC) is a method of regulating access to resources based on the roles of individual users. By assigning users to roles (e.g., admin, editor, viewer) and defining different permissions for each role, RBAC simplifies permission management and improves security. There are some generally accepted good practices for using RBAC:

  • Least privilege: Minimal and only explicitly required permissions should be assigned to roles, and start with a default deny policy and explicitly grant permissions only where needed.
  • Clearly define roles: Create roles that represent specific job functions or responsibilities within the organization; avoid creating roles that are too broad or too narrow. Keep the number of roles manageable: too many roles can lead to complexity and difficulty in managing permissions; consider using role hierarchies to simplify management.
  • Periodic review, audit, and documentation: Conduct regular security audits to stay up-to-date and identify potential vulnerabilities; maintain clear and comprehensive documentation of our RBAC policies and procedures.

2.4 Attribute-Based Access Control (ABAC)

ABAC provides finer-grained control by basing access decisions on not just the generic role, but detailed attributes of the user, resource, and environment. It is therefore more flexible than RBAC, but the tradeoff is that it's more complex to implement.

For complex scenarios, we can consider integrating ABAC principles with RBAC to provide dynamic and context-aware access control.

2.5 Policy-Based Access Control (PBAC)

PBAC is a strategy for managing user access where the roles of users are combined with policies to determine what access privileges users of each role should have. PBAC can be used with RBAC/ABAC together. Cloud IAM users should already be familiar with roles and policies. PBAC offers several benefits over traditional access control models like RBAC:

  • Finer-grained: like ABAC, PBAC allows for highly granular control over access based on a wide range of attributes and conditions. We can define policies based on both user and resource attributes.
  • Attribute-Based Access Control (ABAC) Integration: PBAC is often used in conjunction with ABAC, allowing for even more flexible and expressive access control.
  • Dynamic Access Control: PBAC enables dynamic access control decisions based on real-time conditions. Access can be granted or revoked automatically based on changes in user attributes, resource attributes, or environmental factors. This allows for more flexible and adaptive security policies.

3. Best Practices for Implementation

No matter which authentication method we choose, and no matter how we decide to manage authorization and access controls, there are some common practices to follow when implementing API authentication and authorization:

  • HTTPS/TLS: Use HTTPS whenever possible to encrypt communication between the client and the API.
  • Secure storage: Never store sensitive credentials (passwords, API keys) in plain text. Use hashing and salting for passwords and secure key management systems for API keys.
  • Secrets management for API keys: It's the user's responsibility to keep the secrets safe, but as API providers, we can also encourage users to follow best practices by writing good sample code in the documentation. For example, in API examples, use environment variables, follow the 12-factor app, or even use secret managers!
  • Principle of least privilege: Grant users only the necessary permissions to perform their tasks.
  • Input validation: Validate all user inputs to prevent injection attacks (SQL injection, cross-site scripting, etc.).
  • Rate limiting: Prevent abuse and denial-of-service attacks (DDoS) by limiting the number of requests from a single client.
  • Logging/monitoring: Log all API requests and responses for auditing and troubleshooting. Monitor API usage for suspicious activity.
  • Regular security audits and documentation: Identify vulnerabilities and improve security posture; document the API authentication and authorization mechanisms for developers.
  • Use good libraries: We've already covered plenty of practices in choosing authentication methods and described the pros, cons, and use cases. In the end, we probably won't implement everything from scratch, we want to offload most of the work to trusted libraries. Learn the libraries, make a decision, and then do as little as possible ourselves (much like choosing the best library for hashing/encryption).

By following these best practices, we can build secure APIs that protect data integrity and more importantly, maintain the trust of our end users. Remember to stay updated on the latest security threats and best practices to ensure our API remains secure.


4. Common Mistakes to Avoid

As a summary, let's quickly cover a few common mistakes when implementing API authentication and authorization. Avoid these:

  • Using HTTP instead of HTTPS.
  • Storing API keys in code.
  • Implementing custom authentication/authorization schemes (unless absolutely necessary).
  • NOT validating user inputs.
  • NOT using strong passwords
  • NOT using password and API key rotation.
  • Ignoring security best practices.

Liked this article? Here's more reading:

API Keys Security & Secrets Management Best Practices - GitGuardian Blog
We have compiled a list of some of the best practices to prevent API key leakage and keep secrets and credentials safe. Secrets management doesn’t have a one-size-fits-all approach, so this list considers multiple perspectives so you can be informed in deciding to or not to implement strategies.
How to Become Great at API Key Rotation: Best Practices and Tips
Secret management can be a complex challenge, especially when you are trying to do it in a way that is right for security. Key rotation is a big piece of that puzzle. In this article, we will take you from zero to hero on key rotation.