@descope/angular-sdk
Advanced tools
Comparing version 0.0.0-next-7be68a9b-20231226 to 0.0.0-next-855688d5-20231231
103
package.json
{ | ||
"name": "@descope/angular-sdk", | ||
"version": "0.0.0-next-7be68a9b-20231226", | ||
"license": "MIT", | ||
"engines": { | ||
"node": "^16.14.0 || >=18.10.0", | ||
"npm": ">= 8.1.0" | ||
}, | ||
"scripts": { | ||
"ng": "ng", | ||
"start": "ng serve", | ||
"prepare": "husky install", | ||
"format-lint": "pretty-quick --staged --ignore-path .gitignore && lint-staged", | ||
"prebuild:ci": "node scripts/setversion/setversion.js", | ||
"build:ci": "npm run build:lib", | ||
"build:lib": "ng build angular-sdk", | ||
"build:app": "ng build demo-app", | ||
"watch": "ng build --watch --configuration development", | ||
"test": "jest --config jest.config.js", | ||
"lint": "ng lint", | ||
"format": "prettier . -w --ignore-path .gitignore", | ||
"format-check": "prettier . --check --ignore-path .gitignore", | ||
"leaks": "bash ./scripts/gitleaks/gitleaks.sh" | ||
}, | ||
"lint-staged": { | ||
"+(src|test|examples)/**/*.{js,ts,html}": [ | ||
"npm run lint" | ||
] | ||
}, | ||
"devDependencies": { | ||
"@angular-devkit/build-angular": "^16.2.6", | ||
"@angular-eslint/builder": "16.3.1", | ||
"@angular-eslint/eslint-plugin": "16.3.1", | ||
"@angular-eslint/eslint-plugin-template": "16.3.1", | ||
"@angular-eslint/schematics": "16.3.1", | ||
"@angular-eslint/template-parser": "16.3.1", | ||
"@angular/animations": "^16.2.9", | ||
"@angular/cli": "^16.2.6", | ||
"@angular/common": "^16.2.9", | ||
"@angular/compiler": "^16.2.9", | ||
"@angular/compiler-cli": "^16.2.9", | ||
"@angular/core": "^16.2.9", | ||
"@angular/forms": "^16.2.9", | ||
"@angular/platform-browser": "^16.2.9", | ||
"@angular/platform-browser-dynamic": "^16.2.9", | ||
"@angular/router": "^16.2.9", | ||
"@descope/web-component": "3.0.0", | ||
"@types/jest": "^29.5.5", | ||
"@typescript-eslint/eslint-plugin": "6.11.0", | ||
"@typescript-eslint/parser": "6.11.0", | ||
"eslint": "^8.51.0", | ||
"eslint-plugin-prettier": "^4.2.1", | ||
"husky": "^8.0.3", | ||
"jest": "^29.7.0", | ||
"jest-preset-angular": "^13.1.2", | ||
"lint-staged": "^15.2.0", | ||
"ng-mocks": "^14.11.0", | ||
"ng-packagr": "^16.2.3", | ||
"prettier": "2.8.8", | ||
"pretty-quick": "^3.1.3", | ||
"rxjs": "~7.8.1", | ||
"tslib": "^2.6.2", | ||
"typescript": "~5.1.6", | ||
"zone.js": "~0.13.0" | ||
} | ||
} | ||
"name": "@descope/angular-sdk", | ||
"version": "0.0.0-next-855688d5-20231231", | ||
"peerDependencies": { | ||
"@angular/common": ">=16.0.0", | ||
"@angular/core": ">=16.0.0" | ||
}, | ||
"license": "MIT", | ||
"engines": { | ||
"node": "^16.14.0 || >=18.10.0", | ||
"npm": ">= 8.1.0" | ||
}, | ||
"lint-staged": { | ||
"+(src|test|examples)/**/*.{js,ts,html}": [ | ||
"npm run lint" | ||
] | ||
}, | ||
"dependencies": { | ||
"@descope/web-component": "3.0.0", | ||
"tslib": "^2.3.0" | ||
}, | ||
"optionalDependencies": { | ||
"@descope/web-js-sdk": ">=1" | ||
}, | ||
"module": "fesm2022/descope-angular-sdk.mjs", | ||
"typings": "index.d.ts", | ||
"exports": { | ||
"./package.json": { | ||
"default": "./package.json" | ||
}, | ||
".": { | ||
"types": "./index.d.ts", | ||
"esm2022": "./esm2022/descope-angular-sdk.mjs", | ||
"esm": "./esm2022/descope-angular-sdk.mjs", | ||
"default": "./fesm2022/descope-angular-sdk.mjs" | ||
} | ||
}, | ||
"sideEffects": false | ||
} |
461
README.md
@@ -1,460 +0,21 @@ | ||
# Descope SDK for Angular | ||
# AngularSdk | ||
The Descope SDK for Angular provides convenient access to the Descope for an application written on top of Angular. You can read more on the [Descope Website](https://descope.com). | ||
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 16.2.0. | ||
## Requirements | ||
## Code scaffolding | ||
- The SDK supports Angular version 16 and above. | ||
- A Descope `Project ID` is required for using the SDK. Find it on the [project page in the Descope Console](https://app.descope.com/settings/project). | ||
Run `ng generate component component-name --project angular-sdk` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project angular-sdk`. | ||
## Installing the SDK | ||
> Note: Don't forget to add `--project angular-sdk` or else it will be added to the default project in your `angular.json` file. | ||
Install the package with: | ||
## Build | ||
```bash | ||
npm i --save @descope/angular-sdk | ||
``` | ||
Run `ng build angular-sdk` to build the project. The build artifacts will be stored in the `dist/` directory. | ||
Add Descope type definitions to your `tsconfig.ts` | ||
## Running unit tests | ||
``` | ||
"compilerOptions": { | ||
"typeRoots": ["./node_modules/@descope"], | ||
<other options> | ||
} | ||
``` | ||
Run `ng test angular-sdk` to execute the unit tests via [Karma](https://karma-runner.github.io). | ||
## Usage | ||
## Further help | ||
### NgModule - Import `DescopeAuthModule` to your application | ||
`app.module.ts` | ||
```ts | ||
import { NgModule } from '@angular/core'; | ||
import { BrowserModule } from '@angular/platform-browser'; | ||
import { AppComponent } from './app.component'; | ||
import { DescopeAuthModule } from '@descope/angular-sdk'; | ||
@NgModule({ | ||
declarations: [AppComponent], | ||
imports: [ | ||
BrowserModule, | ||
DescopeAuthModule.forRoot({ | ||
projectId: '<your_project_id>' | ||
}) | ||
], | ||
bootstrap: [AppComponent] | ||
}) | ||
export class AppModule {} | ||
``` | ||
### Standalone Mode - Configure Descope SDK for your application | ||
`main.ts` | ||
```ts | ||
import { bootstrapApplication } from '@angular/platform-browser'; | ||
import { AppComponent } from './app/app.component'; | ||
import { DescopeAuthConfig } from '@descope/angular-sdk'; | ||
bootstrapApplication(AppComponent, { | ||
providers: [ | ||
{ provide: DescopeAuthConfig, useValue: { projectId: '<your_project_id>' } } | ||
] | ||
}).catch((err) => console.error(err)); | ||
``` | ||
### Use Descope to render specific flow | ||
You can use **default flows** or **provide flow id** directly to the descope component | ||
#### 1. Default flows | ||
`app.component.html` | ||
```angular2html | ||
<descope-sign-in-flow | ||
(success)="onSuccess()" | ||
(error)="onError()" | ||
></descope-sign-in-flow> | ||
``` | ||
`app.component.ts` | ||
```ts | ||
import { Component } from '@angular/core'; | ||
@Component({ | ||
selector: 'app-root', | ||
templateUrl: './app.component.html' | ||
}) | ||
export class AppComponent { | ||
onSuccess() { | ||
console.log('SUCCESSFULLY LOGGED IN FROM WEB COMPONENT'); | ||
} | ||
onError() { | ||
console.log('ERROR FROM LOG IN FLOW FROM WEB COMPONENT'); | ||
} | ||
} | ||
``` | ||
#### 2. Provide flow id | ||
```angular2html | ||
<descope | ||
flowId="<your_flow_id>" | ||
(success)="<your_success_function>" | ||
(error)="<your_error_function>" | ||
<!-- theme can be "light", "dark" or "os", which auto select a theme based on the OS theme. Default is "light" | ||
theme="dark" | ||
locale can be any supported locale which the flow's screen translated to, if not provided, the locale is taken from the browser's locale. | ||
locale="en" | ||
debug can be set to true to enable debug mode | ||
debug="true" | ||
tenant ID for SSO (SAML) login. If not provided, Descope will use the domain of available email to choose the tenant | ||
tenant=<tenantId> | ||
Redirect URL for OAuth and SSO (will be used when redirecting back from the OAuth provider / IdP), or for "Magic Link" and "Enchanted Link" (will be used as a link in the message sent to the the user) | ||
redirectUrl=<redirectUrl> | ||
telemetryKey=<telemtry_key> | ||
autoFocus can be true, false or "skipFirstScreen". Default is true. | ||
- true: automatically focus on the first input of each screen | ||
- false: do not automatically focus on screen's inputs | ||
- "skipFirstScreen": automatically focus on the first input of each screen, except first screen | ||
autoFocus="skipFirstScreen" | ||
errorTransformer is a function that receives an error object and returns a string. The returned string will be displayed to the user. | ||
NOTE: errorTransformer is not required. If not provided, the error object will be displayed as is. | ||
Example: | ||
errorTransformer = (error: { text: string; type: string }): string => { | ||
const translationMap: { [key: string]: string } = { | ||
SAMLStartFailed: 'Failed to start SAML flow' | ||
}; | ||
return translationMap[error.type] || error.text; | ||
}; | ||
... | ||
errorTransformer={errorTransformer} | ||
logger is an object describing how to log info, warn and errors. | ||
NOTE: logger is not required. If not provided, the logs will be printed to the console. | ||
Example: | ||
const logger = { | ||
info: (title: string, description: string, state: any) => { | ||
console.log(title, description, JSON.stringify(state)); | ||
}, | ||
warn: (title: string, description: string) => { | ||
console.warn(title); | ||
}, | ||
error: (title: string, description: string) => { | ||
console.error('OH NOO'); | ||
}, | ||
} | ||
... | ||
logger={logger}--> | ||
></descope> | ||
``` | ||
#### Standalone Mode Note: | ||
All components in the sdk are standalone, so you can use them by directly importing them to your components. | ||
### Use the `DescopeAuthService` and its exposed fields (`descopeSdk`, `session$`, `user$`) to access authentication state, user details and utilities | ||
This can be helpful to implement application-specific logic. Examples: | ||
- Render different components if current session is authenticated | ||
- Render user's content | ||
- Logout button | ||
`app.component.html` | ||
```angular2html | ||
<p *ngIf="!isAuthenticated"> You are not logged in</p> | ||
<button *ngIf="isAuthenticated" (click)="logout()">LOGOUT</button> | ||
<p>User: {{userName}}</p> | ||
``` | ||
`app.component.ts` | ||
```ts | ||
import { Component, OnInit } from '@angular/core'; | ||
import { DescopeAuthService } from '@descope/angular-sdk'; | ||
@Component({ | ||
selector: 'app-home', | ||
templateUrl: './app.component.html', | ||
styleUrls: ['./app.component.scss'] | ||
}) | ||
export class AppComponent implements OnInit { | ||
isAuthenticated: boolean = false; | ||
userName: string = ''; | ||
constructor(private authService: DescopeAuthService) {} | ||
ngOnInit() { | ||
this.authService.session$.subscribe((session) => { | ||
this.isAuthenticated = session.isAuthenticated; | ||
}); | ||
this.authService.user$.subscribe((descopeUser) => { | ||
if (descopeUser.user) { | ||
this.userName = descopeUser.user.name ?? ''; | ||
} | ||
}); | ||
} | ||
logout() { | ||
this.authService.descopeSdk.logout(); | ||
} | ||
} | ||
``` | ||
### Session Refresh | ||
`DescopeAuthService` provides `refreshSession` and `refreshUser` methods that triggers a single request to the Descope backend to attempt to refresh the session or user. You can use them whenever you want to refresh the session/user. For example you can use `APP_INITIALIZER` provider to attempt to refresh session and user on each page refresh: | ||
`app.module.ts` | ||
```ts | ||
import { APP_INITIALIZER, NgModule } from '@angular/core'; | ||
import { BrowserModule } from '@angular/platform-browser'; | ||
import { AppComponent } from './app.component'; | ||
import { DescopeAuthModule, DescopeAuthService } from '@descope/angular-sdk'; | ||
import { zip } from 'rxjs'; | ||
export function initializeApp(authService: DescopeAuthService) { | ||
return () => zip([authService.refreshSession(), authService.refreshUser()]); | ||
} | ||
@NgModule({ | ||
declarations: [AppComponent], | ||
imports: [ | ||
BrowserModule, | ||
DescopeAuthModule.forRoot({ | ||
projectId: '<your_project_id>' | ||
}) | ||
], | ||
providers: [ | ||
{ | ||
provide: APP_INITIALIZER, | ||
useFactory: initializeApp, | ||
deps: [DescopeAuthService], | ||
multi: true | ||
} | ||
], | ||
bootstrap: [AppComponent] | ||
}) | ||
export class AppModule {} | ||
``` | ||
#### Standalone Mode Note: | ||
You can use the same approach with `APP_INITIALIZER` in standalone mode, by adding it to `providers` array of the application. | ||
### Descope Interceptor | ||
You can also use `DescopeInterceptor` to attempt to refresh session on each HTTP request that gets `401` or `403` response: | ||
`app.module.ts` | ||
```ts | ||
import { NgModule } from '@angular/core'; | ||
import { BrowserModule } from '@angular/platform-browser'; | ||
import { AppComponent } from './app.component'; | ||
import { | ||
HttpClientModule, | ||
provideHttpClient, | ||
withInterceptors | ||
} from '@angular/common/http'; | ||
import { DescopeAuthModule, descopeInterceptor } from '@descope/angular-sdk'; | ||
@NgModule({ | ||
declarations: [AppComponent], | ||
imports: [ | ||
BrowserModule, | ||
HttpClientModule, | ||
DescopeAuthModule.forRoot({ | ||
projectId: '<your_project_id>', | ||
pathsToIntercept: ['/protectedPath'] | ||
}) | ||
], | ||
providers: [provideHttpClient(withInterceptors([descopeInterceptor]))], | ||
bootstrap: [AppComponent] | ||
}) | ||
export class AppModule {} | ||
``` | ||
`DescopeInterceptor`: | ||
- is configured for requests that urls contain one of `pathsToIntercept`. If not provided it will be used for all requests. | ||
- attaches session token as `Authorization` header in `Bearer <token>` format | ||
- if requests get response with `401` or `403` it automatically attempts to refresh session | ||
- if refresh attempt is successful, it automatically retries original request, otherwise it fails with original error | ||
**For more SDK usage examples refer to [docs](https://docs.descope.com/build/guides/client_sdks/)** | ||
### Session token server validation (pass session token to server API) | ||
When developing a full-stack application, it is common to have private server API which requires a valid session token: | ||
![session-token-validation-diagram](https://docs.descope.com/static/SessionValidation-cf7b2d5d26594f96421d894273a713d8.png) | ||
Note: Descope also provides server-side SDKs in various languages (NodeJS, Go, Python, etc). Descope's server SDKs have out-of-the-box session validation API that supports the options described bellow. To read more about session validation, Read [this section](https://docs.descope.com/build/guides/gettingstarted/#session-validation) in Descope documentation. | ||
You can securely communicate with your backend either by using `DescopeInterceptor` or manually adding token to your requests (ie. by using `DescopeAuthService.getSessionToken()` helper function) | ||
### Helper Functions | ||
You can also use the following helper methods on `DescopeAuthService` to assist with various actions managing your JWT. | ||
- `getSessionToken()` - Get current session token. | ||
- `getRefreshToken()` - Get current refresh token. | ||
- `isAuthenticated()` - Returns boolean whether user is authenticated | ||
- `refreshSession` - Force a refresh on current session token using an existing valid refresh token. | ||
- `refreshUser` - Force a refresh on current user using an existing valid refresh token. | ||
- `getJwtRoles(token = getSessionToken(), tenant = '')` - Get current roles from an existing session token. Provide tenant id for specific tenant roles. | ||
- `getJwtPermissions(token = getSessionToken(), tenant = '')` - Fet current permissions from an existing session token. Provide tenant id for specific tenant permissions. | ||
### Refresh token lifecycle | ||
Descope SDK is automatically refreshes the session token when it is about to expire. This is done in the background using the refresh token, without any additional configuration. | ||
If the Descope project settings are configured to manage tokens in cookies. | ||
you must also configure a custom domain, and set it as the `baseUrl` in `DescopeAuthModule`. | ||
### Descope Guard | ||
`angular-sdk` provides a convenient route guard that prevents from accessing given route for users that are not authenticated: | ||
```ts | ||
import { NgModule } from '@angular/core'; | ||
import { RouterModule, Routes } from '@angular/router'; | ||
import { HomeComponent } from './home/home.component'; | ||
import { ProtectedComponent } from './protected/protected.component'; | ||
import { descopeAuthGuard } from '@descope/angular-sdk'; | ||
import { LoginComponent } from './login/login.component'; | ||
const routes: Routes = [ | ||
{ | ||
path: 'step-up', | ||
component: ProtectedComponent, | ||
canActivate: [descopeAuthGuard], | ||
data: { descopeFallbackUrl: '/' } | ||
}, | ||
{ path: 'login', component: LoginComponent }, | ||
{ path: '**', component: HomeComponent } | ||
]; | ||
@NgModule({ | ||
imports: [RouterModule.forRoot(routes, { enableTracing: false })], | ||
exports: [RouterModule] | ||
}) | ||
export class AppRoutingModule {} | ||
``` | ||
If not authenticated user tries to access protected route they will be redirected to `descopeFallbackUrl` | ||
## Code Example | ||
You can find an example angular app in the [examples folder](./projects/demo-app). | ||
### Setup | ||
To run the examples, create `environment.development.ts` file in `environments` folder. | ||
```ts | ||
import { Env } from './conifg'; | ||
export const environment: Env = { | ||
descopeProjectId: '<your_project_id>' | ||
}; | ||
``` | ||
Find your Project ID in the [Descope console](https://app.descope.com/settings/project). | ||
### Run Example | ||
Run the following command in the root of the project to build and run the example: | ||
```bash | ||
npm i && npm start | ||
``` | ||
### Example Optional Env Variables | ||
See the following table for customization environment variables for the example app: | ||
| Env Variable | Description | Default value | | ||
| ------------------- | ------------------------------------------------------------------------------------------------------------- | ----------------- | | ||
| descopeFlowId | Which flow ID to use in the login page | **sign-up-or-in** | | ||
| descopeBaseUrl | Custom Descope base URL | None | | ||
| descopeTheme | Flow theme | None | | ||
| descopeLocale | Flow locale | Browser's locale | | ||
| descopeRedirectUrl | Flow redirect URL for OAuth/SSO/Magic Link/Enchanted Link | None | | ||
| descopeTenantId | Flow tenant ID for SSO/SAML | None | | ||
| descopeDebugMode | **"true"** - Enable debugger</br>**"false"** - Disable flow debugger | None | | ||
| descopeStepUpFlowId | Step up flow ID to show to logged in user (via button). e.g. "step-up". Button will be hidden if not provided | None | | ||
| descopeTelemetryKey | **String** - Telemetry public key provided by Descope Inc | None | | ||
| descopeBackendUrl | Url to your test backend app in case you want to test e2e | None | | ||
Example `environment.development.ts` file: | ||
```ts | ||
import { Env } from './conifg'; | ||
export const environment: Env = { | ||
descopeProjectId: '<your_project_id>', | ||
descopeBaseUrl: '<your_base_url>', | ||
descopeFlowId: 'sign-in', | ||
descopeDebugMode: false, | ||
descopeTheme: 'os', | ||
descopeLocale: 'en_US', | ||
descopeRedirectUrl: '<your_redirect_url>', | ||
descopeTelemetryKey: '<your_telemetry_key>', | ||
descopeStepUpFlowId: 'step-up', | ||
descopeBackendUrl: 'http://localhost:8080/protected' | ||
}; | ||
``` | ||
## Troubleshooting | ||
If you encounter warning during build of your application: | ||
``` | ||
▲ [WARNING] Module 'lodash.get' used by 'node_modules/@descope/web-component/node_modules/@descope/core-js-sdk/dist/index.esm.js' is not ESM | ||
``` | ||
add `lodash.get` to allowed CommonJS dependencies in `angular.json` | ||
```json | ||
"architect": { | ||
"build": { | ||
"builder": "@angular-devkit/build-angular:browser", | ||
"options": { | ||
"allowedCommonJsDependencies": ["lodash.get"], | ||
<other_options> | ||
} | ||
<other_config> | ||
} | ||
<other_config> | ||
} | ||
``` | ||
## Learn More | ||
To learn more please see the [Descope Documentation and API reference page](https://docs.descope.com/). | ||
## Contact Us | ||
If you need help you can email [Descope Support](mailto:support@descope.com) | ||
## License | ||
The Descope SDK for Angular is licensed for use under the terms and conditions of the [MIT license Agreement](./LICENSE). | ||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Misc. License Issues
License(Experimental) A package's licensing information has fine-grained problems.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
0
0
1
148027
5
32
1248
22
1
1
+ Added@descope/web-component@3.0.0
+ Addedtslib@^2.3.0
+ Added@angular/common@19.1.5(transitive)
+ Added@angular/core@19.1.5(transitive)
+ Added@descope/core-js-sdk@2.0.02.33.6(transitive)
+ Added@descope/web-component@3.0.0(transitive)
+ Added@descope/web-js-sdk@1.23.91.6.7(transitive)
+ Added@fingerprintjs/fingerprintjs-pro@3.11.63.8.5(transitive)
+ Addedjs-cookie@3.0.5(transitive)
+ Addedjwt-decode@3.1.24.0.0(transitive)
+ Addedlodash.get@4.4.2(transitive)
+ Addedrxjs@7.8.1(transitive)
+ Addedtslib@2.6.22.8.1(transitive)
+ Addedzone.js@0.15.0(transitive)