Awesome
Okta Angular SDK
Okta Angular SDK builds on top of @okta/okta-auth-js. This SDK adds integration with @angular/router and provides additional logic and components designed to help you quickly add authentication and authorization to your Angular single-page web application.
With @okta/okta-auth-js, you can:
- Login and logout from Okta using the OAuth 2.0 API
- Retrieve user information
- Determine authentication status
- Validate the current user's session
All of these features are supported by this SDK. Additionally, using this SDK, you can:
- Add "protected" routes, which will require authentication before render
- Define custom logic/behavior when authentication is required
- Subscribe to changes in authentication state using an Observable property
- Provide an instance of the [OktaAuthService][] to your components using Dependency Injection
This SDK does not provide any UI components. This SDK does not currently support Server Side Rendering (SSR)
This library currently supports:
This library has been tested for compatibility with the following Angular versions: 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 :warning:
okta-angular
6.0+ supports Angular 12+. For Angular 7 to 11 please useokta-angular
5.x :warning: Angular versions older than 7 may not be fully compatible with all dependencies of this library, due to an older Typescript version which does not contain a definition for theunknown
type. You may be able to workaround this issue by settingskipLibChecks: true
in yourtsconfig.json
file.
Release Status
:heavy_check_mark: The current stable major version series is: 6.x
Version | Status |
---|---|
6.x | :heavy_check_mark: Stable |
5.x | :heavy_check_mark: Stable |
4.x | :heavy_check_mark: Stable |
3.x | :x: Retired |
2.x | :x: Retired |
1.x | :x: Retired |
Getting Started
- If you do not already have a Developer Edition Account, you can create one at https://developer.okta.com/signup/.
- An Okta Application, configured for Single-Page App (SPA) mode. This is done from the Okta Developer Console and you can find instructions here. When following the wizard, use the default properties. They are are designed to work with our sample applications.
Helpful Links
- Angular Quickstart
- If you don't have an Angular app, or are new to Angular, please start with this guide. It will walk you through the creation of an Angular app, creating routes, and other application development essentials.
- Okta Sample Application
- A fully functional sample application.
- Okta Guide: Sign users into your single-page application
- Step-by-step guide to integrating an existing Angular application with Okta login.
- Strategies for Obtaining Tokens
- Okta Angular SDK supports
PathStrategy
andHashStrategy
for more details please check specific section ofokta-auth-js
- Okta Angular SDK supports
Installation
This library is available through npm. To install it, simply add it to your project:
npm install @okta/okta-angular @okta/okta-auth-js
Usage
:warning: This method of configuration is deprecated and will be removed in v7. Starting with okta-angular 6.1.0
, the preferred way to import OktaAuthModule
is by using static method forRoot
.
Add OktaAuthModule
to your module's imports.
Create a configuration object and provide this as OKTA_CONFIG
.
// myApp.module.ts
import {
OKTA_CONFIG,
OktaAuthModule
} from '@okta/okta-angular';
import { OktaAuth } from '@okta/okta-auth-js';
const authConfig = {
issuer: 'https://{yourOktaDomain}/oauth2/default',
clientId: '{clientId}',
redirectUri: window.location.origin + '/login/callback'
}
const oktaAuth = new OktaAuth(authConfig);
@NgModule({
imports: [
...
OktaAuthModule
],
providers: [
{
provide: OKTA_CONFIG,
useValue: { oktaAuth }
}
],
})
export class MyAppModule { }
OktaAuthModule.forRoot()
Add OktaAuthModule.forRoot(config: OktaConfig)
to your module's imports to create a singleton service with provied configuration.
// myApp.module.ts
import {
OktaAuthModule,
OktaConfig
} from '@okta/okta-angular';
import { OktaAuth } from '@okta/okta-auth-js';
const authConfig = {
issuer: 'https://{yourOktaDomain}/oauth2/default',
clientId: '{clientId}',
redirectUri: window.location.origin + '/login/callback'
}
const oktaAuth = new OktaAuth(authConfig);
const moduleConfig: OktaConfig = { oktaAuth };
@NgModule({
imports: [
...
OktaAuthModule.forRoot(moduleConfig)
],
})
export class MyAppModule { }
APP_INITIALIZER
Starting with okta-angular 6.2.0
, you can provide OktaConfig
in APP_INITIALIZER
provider factory with method setConfig()
of OktaAuthConfigService
instance which allows you to load the OktaConfig
at runtime.
// myApp.module.ts
import {
OktaAuthModule,
OktaConfig,
OktaAuthOptions,
OktaAuthConfigService,
} from '@okta/okta-angular';
import { OktaAuth } from '@okta/okta-auth-js';
function configInitializer(configService: OktaAuthConfigService, httpBackend: HttpBackend): () => void {
return () =>
new HttpClient(httpBackend)
.get('/api/config')
.pipe(
map((res: any) => ({
issuer: res.issuer,
clientId: res.clientId,
redirectUri: window.location.origin + '/login/callback'
})),
tap((authConfig: OktaAuthOptions) => {
const oktaAuth = new OktaAuth(authConfig);
const moduleConfig: OktaConfig = { oktaAuth };
configService.setConfig(moduleConfig);
}),
take(1)
);
};
@NgModule({
providers: [{
provide: APP_INITIALIZER,
useFactory: configInitializer,
deps: [OktaAuthConfigService, HttpBackend],
multi: true
}],
imports: [
...
OktaAuthModule.forRoot()
],
})
export class MyAppModule { }
OKTA_CONFIG
An Angular InjectionToken used to configure the OktaAuthModule. This value must be provided by your own application.
oktaAuth
(required): - OktaAuth instance. The instance that can be shared cross different components of the application. One popular use case is to share one single instance cross the application and Okta Sign-In Widget.onAuthRequired
(optional): - callback function. Triggered when a route protected byOktaAuthGuard
is accessed without authentication or without needed level of end-user assurance (ifokta.acrValues
is provided in route data). Use this to present a custom login page. If noonAuthRequired
callback is defined,okta-angular
will redirect directly to Okta for authentication.onAuthResume
(optional): - callback function. Only relevant if using a custom login page. Called when the authentication flow should be resumed by the application, typically as a result of redirect callback from an external identity provider. If not defined,onAuthRequired
will be called.
OKTA_AUTH
An Angular InjectionToken added in okta-angular 5.0
explicitly for OktaAuth instance usage.
import { Component, Inject, OnInit } from '@angular/core';
import { OKTA_AUTH } from '@okta/okta-angular';
import { OktaAuth } from '@okta/okta-auth-js';
@Component({
selector: 'app-component',
template: `
<pre id="userinfo-container">{{ user }}</pre>
`,
})
export class MyProtectedComponent implements OnInit {
user: string = '';
constructor(@Inject(OKTA_AUTH) private oktaAuth: OktaAuth) {}
async ngOnInit() {
const user = await this.oktaAuth.getUser();
this.user = JSON.stringify(user, null, 4);
}
}
OktaAuthModule
The top-level Angular module which provides these components and services:
OktaAuth
- The passed inOktaAuth
instance with default behavior setup.OktaAuthGuard
- A navigation guard implementing CanActivate and CanActivateChild to grant access to a page (and/or its children) only after successful authentication (and only with needed level of end-user assurance ifokta.acrValues
is provided in route data).OktaCallbackComponent
- Handles the implicit flow callback by parsing tokens from the URL and storing them automatically.OktaAuthStateService
- A data service exposing observable authState$.
OktaAuthGuard
Routes are protected by the OktaAuthGuard
, which verifies there is a valid idToken
stored.
To verify the level of end-user assurance (see Step-up authentication), add acrValues
to route data in okta
namespace. Then OktaAuthGuard
will also verify acr
claim of idToken
to match provided okta.acrValues
. See list of supported ACR values. Minimum supported version of @okta/okta-auth-js
for this feature is 7.1.0
.
To ensure the user has been authenticated before accessing your route, add the canActivate
guard to one of your routes:
// myApp.module.ts
import {
OktaAuthGuard,
...
} from '@okta/okta-angular';
const appRoutes: Routes = [
{
path: 'protected',
component: MyProtectedComponent,
canActivate: [ OktaAuthGuard ],
children: [{
// children of a protected route are also protected
path: 'also-protected'
}]
},
...
]
To protect a route with the assurance level, add acrValues
to route data in okta
namespace:
// myApp.module.ts
import { OktaAuthGuard } from '@okta/okta-angular';
const appRoutes: Routes = [
{
path: 'protected',
component: MyProtectedComponent,
canActivate: [ OktaAuthGuard ],
data: {
okta: {
// requires any 2 factors before accessing the route
acrValues: 'urn:okta:loa:2fa:any'
}
},
},
...
]
You can use canActivateChild
to protect children of an unprotected route:
// myApp.module.ts
import {
OktaAuthGuard,
...
} from '@okta/okta-angular';
const appRoutes: Routes = [
{
path: 'public',
component: MyPublicComponent,
canActivateChild: [ OktaAuthGuard ],
children: [{
path: 'protected',
component: MyProtectedComponent
}]
},
...
]
You can use canLoad
to achieve lazy loading for modules that are not immediately necessary to keep the initial bundle size smaller.
// myApp.module.ts
import {
OktaAuthGuard,
...
} from '@okta/okta-angular';
const appRoutes: Routes = [
{
path: 'lazy',
canLoad: [ OktaAuthGuard ],
loadChildren: () => import('./lazy-load/lazy-load.module').then(mod => mod.LazyLoadModule)
},
...
]
If a user does not have a valid session, then a new authorization flow will begin. By default, they will be redirected to the Okta Login Page for authentication. Once authenticated, they will be redirected back to your application's protected page. This logic can be customized by setting an onAuthRequired
function on the config object.
OktaCallbackComponent
Used by the login redirect flow, begun by a call to signInWithRedirect. This component handles the callback after the redirect. By default, it parses the tokens from the uri, stores them, then redirects to /
. If a protected route (using OktaAuthGuard
) caused the redirect, then the callback will redirect back to the protected route. If an error is thrown while processing tokens, the component will display the error and not perform any redirect. This logic can be customized by copying the component to your own source tree and modified as needed. For example, you may want to capture or display errors differently or provide a helpful link for your users in case they encounter an error on the callback route. The most common error is the user does not have permission to access the application. In this case, they may be able to contact an administrator to obtain access.
You should define a route to handle the callback URL (/login/callback
by default).
// myApp.module.ts
import {
OktaCallbackComponent,
...
} from '@okta/okta-angular';
const appRoutes: Routes = [
{
path: 'login/callback',
component: OktaCallbackComponent
},
...
]
OktaAuthStateService
This service exposes an observable (update to date) authState$ to the UI components.
The example below shows connecting two buttons to handle login and logout:
// sample.component.ts
import { Component, Inject } from '@angular/core';
import { OktaAuth } from '@okta/okta-auth-js';
import { OktaAuthStateService, OKTA_AUTH } from '@okta/okta-angular';
@Component({
selector: 'app-component',
template: `
<button *ngIf="!(authStateService.authState$ | async)?.isAuthenticated" (click)="login()">Login</button>
<button *ngIf="(authStateService.authState$ | async)?.isAuthenticated" (click)="logout()">Logout</button>
<router-outlet></router-outlet>
`,
})
export class MyComponent {
constructor(
@Inject(OKTA_AUTH) public oktaAuth: OktaAuth,
private authStateService: OktaAuthStateService
) {}
async login() {
await this.oktaAuth.signInWithRedirect();
}
async logout() {
await this.oktaAuth.signOut();
}
}
OktaHasAnyGroup
directive
This directive implements lite role based access control (RBAC) to only render content for authenticated users in group/s. It supports string
, array
and object
input formats.
string
: single group name. --'admin'
array
: array of group names. --['admin', 'it']
object
: key-value pair of group names, this format of input can be used when custom claim is defined. --{ 'custom-groups': ['admin', 'it'] }
Use any format of input when groups
is available from user claims:
@Component({
template: `
<div *oktaHasAnyGroup="['admin']">
In group
</div>
`
})
class RBACComponent { }
Only use object
format input when custom claim is defined:
@Component({
template: `
<div *oktaHasAnyGroup="{ 'custom-groups': ['admin', 'it'] }">
In group
</div>
`
})
class RBACComponent { }
Note - JWT claim names are case-sensitive. Ensure the claim name is lowercase for the standard
group
claim or that it matches the casing of your custom group's claim.
Using a custom login-page
Using the Okta Signin Widget, you can embed the complete authentication flow within your application. This allows users to signin without requiring any redirects. A full working example is available here
To implement a custom login page, set an onAuthRequired
callback on the OktaConfig
object:
// myApp.module.ts
function onAuthRequired(oktaAuth, injector, options) {
// `options` object can contain `acrValues` if it was provided in route data
// Use injector to access any service available within your application
const router = injector.get(Router);
// Redirect the user to your custom login page
router.navigate(['/custom-login']);
}
const oktaAuth = new OktaAuth({ ... });
@NgModule({
imports: [
...
OktaAuthModule.forRoot({oktaAuth, onAuthRequired})
],
})
export class MyAppModule { }
Alternatively, you can add a data
attribute directly to a Route
:
// myApp.module.ts
const appRoutes: Routes = [
...
{
path: 'protected',
component: MyProtectedComponent,
canActivate: [ OktaAuthGuard ],
data: {
onAuthRequired: onAuthRequired
}
}
]
Resuming the authentication flow
When using a custom login page and an external identity provider your app should be prepared to handle a redirect callback from Okta to resume the authentication flow. The OktaCallbackComponent
has built-in logic for this scenario.
The redirectUri
of your application will be requested with a special parameter (?error=interaction_required
) to indicate that the authentication flow should be resumed by the application. In this case, the OktaCallbackComponent
will call the onAuthResume
function (if set on OktaConfig
). If onAuthResume
is not defined, then onAuthRequired
will be called (if defined). If neither method is set in OktaConfig
, then the interaction_required
error will be displayed as a string.
If the authentication flow began on the custom login page using the [Okta SignIn Widget][], the transaction will automatically resume when the widget is rendered again on the custom login page.
Note that onAuthResume
has the same signature as onAuthRequired
. If you do not need any special logic for resuming an authorization flow, you can define only an onAuthRequired
method and it will be called both to start or resume an auth flow.
// myApp.module.ts
function onAuthResume(oktaAuth, injector) {
// Use injector to access any service available within your application
const router = injector.get(Router);
// Redirect the user to custom login page which renders the Okta SignIn Widget
router.navigate(['/custom-login']);
}
const oktaConfig = {
...
onAuthResume: onAuthResume
};
Testing
To run Jest tests for your app using @okta/okta-angular
please add @okta/okta-angular
(and some of its dependencies listed below) to transformIgnorePatterns
in jest.config.js
:
export default {
preset: 'jest-preset-angular',
transformIgnorePatterns: [
'node_modules/(?!.*\\.mjs$|rxjs|@okta/okta-auth-js|jsonpath-plus|@okta/okta-angular)'
],
...
}
Jest should transform listed dependencies, because @okta/okta-angular
version 6 uses .js
extension for exporing files from the package.
Contributing
We welcome contributions to all of our open-source packages. Please see the contribution guide to understand how to structure a contribution.
Installing dependencies for contributions
We use yarn for dependency management when developing this package:
yarn install
Commands
Command | Description |
---|---|
yarn start | Start the sample app using the SDK |
yarn test | Run unit and integration tests |
yarn lint | Run eslint linting tests |