Angular authentication library based on the OpenId Connect standard (OAuth & Signed JWTs).
The major version designates the supported Angular version. For example, 15.x.x
means it supports Angular 15.
The angular-oauth2-oidc library is used for authentication. For integration with Azure AD see Azure AD Integration Doc
- OIDC compatible
- Supports OIDC discovery and auto configuration
- Remote login supporting OAuth2 login (code flow)
- Saving JWT in local storage
- In-memory Principal created by JWT parsing
- Parsing user tokens from URL like
/?access_token=myNiceJwt.token
- Mock support for easy development handling
- Supports
HttpClient
request interceptors for automated JWT bearer token injection - Refreshtoken support
- Supports Angular 15
Install via npm
npm i @elderbyte/ngx-auth --save
Import via JS/TS import statement
import {} from "@elderbyte/ngx-auth";
@NgModule({
declarations: [
imports:
[
HttpClientModule,
ElderAuthModule.forRoot(
{
issuerUrl: 'http://localhost:8099/auth/realms/demo',
clientId: 'demo-client',
scope: 'openid profile email',
accessDeniedRoute: 'app/accessdenied'
}
)
]
})
export class AppModule {
}
Azure AD B2C: don't forget to add an api scope to your client and add it in your authConfig like
so: scope: 'openid profile email api://yourClientId/api'
Beware, this module depends on these three libraries:
In case you need to hide certain elements when users do not belong to a specific role, use hasRole
:
<div *hasRole="['ADMIN']">
<!-- my incredible content -->
</div>
Besides obtaining a token from the server, of course you may want to protect routes by restricting access to authenticated users only. This is pretty straight forward:
const appRoutes: Routes = [
{
path: 'login', // Unprotected url
component: LoginComponent,
},
{
path: 'orders',
canActivate: [SimpleAuthGuard], // Only accessible for logged in users
component: OrderBrowserComponent,
}
];
- For more fine gradient role based rules, see belows
HasRoleGuard
.
To prevent users from accessing parts of your application if they lack certain roles, you can use a role based router guard:
Assume you have the following route definition:
{
path: 'app/customers',
component
:
CustomerBrowserComponent,
}
Just add the HasRoleGuard
incanActivate
and specify the allowed roles under the data.roles key:
{
path: 'app/customers',
component
:
CustomerBrowserComponent,
canActivate
:
[HasRoleGuard],
data
:
{
roles: ['USER']
}
}
export class AuthConfig {
/**
* OIDC issuer url
*
* If this property is specified OpenId Connect is enabled.
* Using this url, the basic configuration is auto discovered.
*/
issuerUrl?: string;
/**
* Specify the OAuth client id. (Required for OAuth / OIDC login)
*/
clientId?: string;
/**
* The requested scopes
*/
scope?: string;
/**
* Specify resource parameter
* AAD: To get an access token for itself, pass the client_id
*/
resource?: string;
/**
* Role hierarchy to consider when
* making decisions about granting access.
*/
roleHierarchy?: string;
bearer?: {
/**
* If true, disable bearer token injection.
*/
disabled?: boolean
/**
* Specify authorization header value prefix.
* Defaults to 'Bearer'
*/
prefix?: string;
};
/**
* An Angular route which is invoked on access denied.
* Defaults to '/accessdenied'
*/
accessDeniedRoute?: string;
/**
* The Angular route where the successful OAuth login redirect should be sent.
*
* Note: Since the user is automatically redirected where he wanted to go before the login intercepted him
* (remembered url), this route is usually only important in very specific edge cases.
* Defaults to '/'
*/
loginCallbackRoute?: string;
validation?: {
/**
* The level of https enforcement.
* By default, all non localhost connections must use HTTPS.
*/
httpsRequired?: HttpsValidationType;
/**
* Check that the obtained issuer-url at discovery time
* equals the initial provided issuer url.
*
* Disabled by default for higher compatibility.
*/
originalIssuerCheck?: boolean;
/**
* Checks that all urls in the obtained
* discovery document are located under the same issuer-url.
*
* Disabled by default for higher compatibility.
*/
discoveryDocumentUrlCheck?: boolean;
};
}
You might want to test your application with an Identity provider instead of mocking. You can do so by using a local IAM like Keycloak.
There are a couple steps to configure a client in keycloak with code flow + PKCE.
If you haven't installed keycloak yet, here's the official guide to install and set it up on docker: https://www.keycloak.org/getting-started/getting-started-docker
Using the linked guide is recommended as it's being kept updated. Here are the basic steps:
- Run keycloak in docker
docker run -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:21.0.1 start-dev
- create a master realm (only for management)
- create a realm (for applications)
- create a client in realm
- create a user in realm
- create role in realm and assign it to the user
- navigate to your client (client details)
- in Settings tab, configure the following:
setting | |
---|---|
Client authentication |
OFF |
Authentication flow |
Standard flow |
Valid redirect URIs |
set you application URI http://localhost:4300/* |
Valid post logout redirect URIs |
+ |
Web origins |
set you application origin http://localhost:4300 |
- save
- in Advanced tab, configure the following:
setting | |
---|---|
Proof Key for Code Exchange Code Challenge Method |
S256 |
- save
Your client should now be configured to use code flow + PKCE
After you have added and tested a new feature, publish a new version on npm:
- Increment the version in
package.json
anddist/package.json
- they must have the same version - Build the library into the
/dist
directory by runningnpm run build
from the project root directory. - Commit the compiled
/dist
changes - Run
npm publish dist --access=public
from the project root directory ornpm publish --access=public
from within the dist directory.
Note --access=public
is only neccessary if you publish the package the first time. If you omit this parameter
the first time, you'll get a error message that you need a paid account.
MIT © ElderByte AG