Building secure applications using modern authentication (part 1)

TL;DR – You don’t need to disable MFA for users in the name of “automation”. Basic authentication is considered legacy authentication because there are safer options available. Keep reading to learn about OAuth, OIDC, modern authentication and how to use the valet key to create secure applications.

As scary as it sounds, I have worked with too many third party tools (even security tools!) that rely on basic authentication to integrate services. Any IdP that offers only an API key that never expires as an option to authenticate apps used for automation is not offering you the safest option available for authentication.

With the upcoming deprecation of basic auth for Exchange, I figured this is a good time to talk about modern authentication, why it is a safer option, and how Microsoft makes it easier to implement. That’s the topic of the posts in this series:

Let’s start with a quick summary of the basics…

What is OAuth and OIDC?

OAuth is an authorization (authz) framework that was developed to allow application clients to be delegated specific access to services or resources. 

The client gets access via an access token with a specific lifetime that is granted with specific permissions, referred to as scopes, which are included in the claims (contents) within the access token. These access tokens are granted by an authorization server based on the approval of the owner of that resource or service. 

Open ID Connect, or OIDC, is the authentication (authn) profile that is built on top of OAuth to authenticate and obtain information about the end user, which is stored in an id_token once the user authenticates.

Is OIDC the same as SAML? No, it is not the same, but it is similar because it is used for federated authentication. If you are familiar with SAML, the Identity Provider (IdP) would be referred to as the OpenID Provider (OP) for OIDC and the Service Provider (SP) would be referred to as the Relying Party (RP) for OIDC.  And what you normally see within the assertion in SAML, you will see in the id_token in OIDC and the SAML attributes are the user claims in OIDC. SAML is mostly used for websites, whereas OIDC is mostly used for APIs, machine-to-machine, and mobile applications, so far.

In summary:

  • OAuth is for authorization through an access token.
  • OIDC is for authentication through an id token.

Both id_tokens and access tokens are represented as JSON Web Tokens (JWTs). Also, please keep in mind there is another type of token, a refresh token, that allows the clients to get a new access token after expiration. 

Note: When referring to OAuth on this page we are specifically referring to OAuth 2.0 and above. 

Why OAuth?

One word, granularity.

The typical analogy used to describe OAuth is the valet parking process, where the valet key is the OAuth token because it can’t do everything that the regular key can do, only what you need it to do for the valet person to park the car. The valet key cannot open the trunk or the glove box, two places where you may have valuable objects that you don’t want the valet person to have access to.

Those scopes (permissions) that we mentioned above are included in the claims within the token.  Therefore, the actions allowed using that token can only be within the range that is specifically noted in the scope.  For example, the JWT token below, can only perform actions that are permitted for these scopes: “Group.Read.All”, “User.Read.All”, and/or “AccessReview.Read.All”.  Additionally, these access tokens have a predetermined lifetime, as you can see from the expiration time (‘exp’) claim below. Consequently, the permissions on that token are only valid for the amount of time stated.

I used jwt.ms below to decode the token, so you can see the claims included.

Some of the claims in this token are explained in detail below. To simplify the discussion I am just focusing on the most relevant claims in the description below. The areas highlighted in red are (1) the expiration and (2) the specific permissions associated with that access token.

This makes it much easier to deliver effective applications while abiding by the principle of least privilege.

Different flows for different requirements
Requirements

Client Types – OAuth defines two client types based on whether they can keep a secret or not. 

  • Confidential clients can keep a secret because they have a safe process to store secrets. For example, machine-to-machine, web application with a secure backend, etc.
  • Public clients cannot keep a secret. For example, mobile applications, SPAs, etc.

The type of client used for the connection combined with other factors determines the OAuth flow that is recommended for the solution, as explained below.

Flows

Legacy: Authorization Code – This flow is similar to PKCE explained below, but it does not include the code verifier and challenges noted below. This flow should only be used for confidential clients because it is susceptible to authorization code injection. OAuth 2.1 will require PKCE for all OAuth clients using the authorization code flow.

Authorization Code with PKCE (Proof Key for Code Exchange)- PKCE (pronounced ‘pixie’) is an improvement of the legacy Authorization Code grant type described above because vulnerabilities were discovered.  Specifically, a malicious application could intercept the authorization code and obtain the authorization token. This is the recommended flow for public clients. Originally it was intended for for mobile applications, but now this is the recommended flow for browser apps as well. See below a detailed description of this flow:

Authorization Code with PKCE

Client Credentials – This flow allows the client to get a token without the context of an end user.  In other words, you just need a client id and and a client secret. This flow is recommended only for confidential clients, where there is no end-user, i.e. machine-to-machine. Additionally, secrets and certificates used must be stored in a secure vault, such as Azure Key Vault and the credentials should be rotated. Keep in mind there are safer options within this same OAuth flow for machine-to-machine authentication and authorization within various clouds, i.e. MSIs (managed identities) in Azure AD, IAM roles in AWS, etc., and you should use those where possible. They are safer because the system generates the secrets and rotates the secret automatically, a developer doesn’t even need to know the secret.

Legacy: Implicit Flow – When this flow initially became available there were no other options to implement cross domain requests in a secure manner, however, that is no longer the case. Currently, there are secure ways, such as Authorization Code with PKCE, which is the recommended option. This flow is expected to be removed on OAuth 2.1.

Legacy: Password Grant or Resource Owner Password Flow – It’s just a way for the client to exchange a username and the user’s password for an access token from the authorization server. Given the obvious security risks associated with exposing a user’s credential to a client, the IETF states that “the resource owner password credentials grant MUST NOT be used“.  This flow is expected to be removed on OAuth 2.1.

Note: Some flows above have been marked Legacy because the upcoming OAuth 2.1 release will not support those. 

In part 2 of the series I’ll discuss the various types of scopes or permissions and the wonderful MSAL.

6 thoughts on “Building secure applications using modern authentication (part 1)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: