Consider the case of a buyer making a large purchase
Node.js
Your
favorite IDE
Terminal
window
Browser
Authentication is an expectation
OAuth 2.0
OpenID Connect
OAuth 2.0
AuthorizationOpenID Connect
Authenticationnpm ci
npm start
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
Elevate authentication factors
Enforce recent authentication
export const myGuard: CanActivateFn = (route, state) => {
return true;
};
export const routes: Routes = [
{
path: 'protected',
component: MyComponent,
canActivate: [myGuard]
},
...,
];
stepUpGuard
in auth.guard.ts
filefalse
"/admin"
routeThe snorkeler's view of the protocols
OAuth 2.0
OpenID Connect
OAuth 2.0
OpenID Connect
The Access and ID tokens are JSON Web Token (JWT) format
The Access and ID tokens are JSON Web Token (JWT) format
{
"claimKey": "claimValue"
}
The Authentication Context Class Reference (ACR) define business rules identifying levels of assurance profiles
{
"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"
}
{
"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"
}
phr
for phishing-resistant, phrh
for phishing-resistant hardwarephr
for phishing-resistant, phrh
for phishing-resistant hardwarephr
, http://schemas.openid.net/pape/policies/2007/06/multi-factor
, and urn:okta:loa:2fa:any
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.
Access controls complement step up authentication challenge to better protect views and resources.
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
acr
claim from the ID tokenacr_values
authService.login()
Use route data to define ACR levels per route
It is not uncommon for resource servers to require different authentication strengths or recentness according to the characteristics of a request.
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!
StepUpMiddleware
to routesThe Angular app orchestrates authenticating and re-requesting resources.
Use an interceptor to format the HTTP response error into something we can handle within the app
export const stepupInterceptor: HttpInterceptorFn = (req, next) => {
return next(req).pipe(
catchError(handleError)
);
};
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)
);
};
HttpErrorResponse
contains the step up auth error headerCheck out the completed
branch
Congrats!
Let's talk about next steps!
If you use Okta, the Angular SDK has built-in stepup auth support.
acr_values
with max_age
auth_time
claimHave good authentication security