Step up your authentication game

QR code to slides
@AlisaDuncan
Senior Developer Advocate at Okta

Consider the case of a buyer making a large purchase

Get ready to code!

Angular logo
Security icon
💖

Follow along using

Node.js

Node.JS logo v18+

Your
favorite IDE

VS Code logo WebStorm logo

Terminal
window

Browser

Chrome logo
Firefox logo
Edge logo
Internet Explorer logo

Authentication is an expectation

Delegate to an Identity Provider

OAuth 2.0

OpenID Connect

Delegate to an Identity Provider

OAuth 2.0

Authorization

OpenID Connect

Authentication

Identity Provider manages authentication

The OAuth client
Parameters in URL
The OAuth Identity Provider Okta logo

Getting going

Time to code

  1. Get Tour of Heroes project from alisaduncan/angular-stepup-auth
  2. Install dependencies with npm ci
  3. Run app locally using npm start
  4. Log in and sign up using password and email verification

Authentication may not be enough

We treat authentication equally across applications, and use authorization for access control.

But should we?

It's time to treat authentication with more granularity than true or false

RFC 9470 OAuth 2.0 Step Up Authentication Challenge

Elevate authentication factors

Enforce recent authentication

Step Up Authentication Challenge

The OAuth client
Request stepped-up auth
The OAuth Identity Provider

Guard a route


            export const myGuard: CanActivateFn = (route, state) => {
              return true;
            };
          

            export const routes: Routes = [
              {
                path: 'protected',
                component: MyComponent,
                canActivate: [myGuard]
              },
              ...,
            ];
          

Protect the admin route

  1. Add a stepUpGuard in auth.guard.ts file
  2. Prevent route navigation by returning false
  3. Add the step up guard to the "/admin" route

OAuth 2.0 + OpenID Connect

The snorkeler's view of the protocols

Snorkeling in the bay of
OAuth 2.0 + OpenID Connect

OAuth 2.0

OpenID Connect

Snorkeling in the bay of
OAuth 2.0 + OpenID Connect

OAuth 2.0

  • Authorization
  • Access token

OpenID Connect

  • Authentication
  • ID token

The Access and ID tokens are JSON Web Token (JWT) format

The Access and ID tokens are JSON Web Token (JWT) format

The payload contains metadata called "claims"

              {
                "claimKey": "claimValue"
              }
            

The Authentication Context Class Reference (ACR) define business rules identifying levels of assurance profiles

ACR value in token


            {
              "iss": "https://as.example.net",
              "sub": "someone@example.net",
              "aud": "https://rs.example.com",
              "exp": 1646343000,
              "iat": 1646340200,
              "jti" : "e1j3V_bKic8-LAEB_lccD0G",
              "client_id": "s6BhdRkqt3",
              "scope": "purchase",
              "auth_time": 1646340198,
              "acr": "myACR"
            }
          

Step up auth in action

Step up auth in action

Client authentication button

Step up auth in action

Client authentication button
The Identity Provider Sign in with username and password

Step up auth in action

The app dashboard

Step up auth in action

Navigating to Admin route from dashboard

Step up auth in action

Navigating to the Admin route from the dashboard

{
  "iss": "https://as.example.net",
  "sub": "someone@example.net",
  "aud": "https://rs.example.com",
  "exp": 1646343000,
  "iat": 1646340200,
  "jti" : "e1j3V_bKic8-LB_lDG",
  "client_id": "s6BhdRkqt3",
  "scope": "purchase",
  "auth_time": 1646340198,
  "acr": "low-ACR-level"
}
              

Step up auth in action

Navigating to the Admin route from the dashboard
acr_values="elevated"
The Identity Provider Biometric authentication

Step up auth in action

The OAuth client

Authentication Context Class Reference (ACR)

  • Supports standard values and custom registries
  • Examples include phr for phishing-resistant, phrh for phishing-resistant hardware

Authentication Context Class Reference (ACR)

  • Examples include phr for phishing-resistant, phrh for phishing-resistant hardware

  • You may see ACR values such as phr, http://schemas.openid.net/pape/policies/2007/06/multi-factor, and urn:okta:loa:2fa:any

Authentication Context Class Reference (ACR)

acr

The claim identifying the current authentication level.

acr_values

The requested authentication level.

acr_values_supported

ACR values supported by the authorization server. May be listed in the OIDC discovery document.

What about access control measures?

Access controls complement step up authentication challenge to better protect views and resources.

Step up authentication route guard


          const authLevelMet = authService.acrClaim === ACR_VALUES_2FA;

          if (authLevelMet) return true; // continue navigation

          // else authenticate with required acr_values & redirect to URL
          authService.login(ACR_VALUES_2FA, currentURL);
          return false; // prevent navigation for now
        

Finish step up guard implementation

  1. Get the acr claim from the ID token
  2. Check claim matches the acr_values
  3. Call authService.login()

Use route data to define ACR levels per route

What else can we protect?

It is not uncommon for resource servers to require different authentication strengths or recentness according to the characteristics of a request.

—OAuth 2.0 Step Up Authentication Challenge Protocol

Protecting resources, not just views

Add a new hero to the app
Error!
acr_values="elevated"
The OAuth resource server - the backend API The OAuth resource server - the backend API The OAuth resource server - the backend API The OAuth resource server - the backend API

Resource server error


HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer error="insufficient_user_authentication",
  error_description="A different authentication level is required",
  acr_values="myACR"
          

It's time we protect the heroes!

Enable step up middleware in API

  1. Add the StepUpMiddleware to routes
  2. Review the middleware implementation

Handle the error response

The Angular app orchestrates authenticating and re-requesting resources.

Interceptors in Angular

Calling APIs

Use an interceptor to format the HTTP response error into something we can handle within the app

Interceptors in Angular


          export const stepupInterceptor: HttpInterceptorFn = (req, next) => {
            return next(req).pipe(
              catchError(handleError)
            );
          };
        

Interceptors in Angular


          const handleError = (httpError: HttpErrorResponse) => {
              // verify origin url
              // ensure error is 'insufficient_user_authentication'
              // format a new Error with acr_values
          };
        

          export const stepupInterceptor: HttpInterceptorFn = (req, next) => {
            return next(req).pipe(
              catchError(handleError)
            );
          };
        

Responding to errors in services

Responding to step up auth error

  1. Ensure the HttpErrorResponse contains the step up auth error header
  2. Pull key step up auth info from the error
  3. Authenticate with the required ACR values
  4. Re-request the resource

See the completed project

GitHub logo
github.com/
alisaduncan/angular-stepup-auth

Check out the completed branch

Congrats!

Let's talk about next steps!

If you use Okta, the Angular SDK has built-in stepup auth support.

What about recency?

  • Replace acr_values with max_age
  • Calculate recency using auth_time claim

Have good authentication security

Learn more

@AlisaDuncan

Senior Developer Advocate at Okta |
Angular GDE | Pluralsight Author
QR code to slides Get the slides
@AlisaDuncan #stepupAuth