Add Keycloak JS to the project (#3189)
This commit is contained in:
parent
a51c9c19d3
commit
243cec90df
19 changed files with 4121 additions and 723 deletions
10
.eslintrc.js
10
.eslintrc.js
|
@ -1,7 +1,15 @@
|
|||
/** @type {import("eslint").Linter.Config } */
|
||||
module.exports = {
|
||||
root: true,
|
||||
ignorePatterns: ["node_modules", "dist", "keycloak-theme", "server"],
|
||||
ignorePatterns: [
|
||||
"node_modules",
|
||||
"dist",
|
||||
"keycloak-theme",
|
||||
"server",
|
||||
// Keycloak JS follows a completely different and outdated style, so we'll exclude it for now.
|
||||
// TODO: Eventually align the code-style for Keycloak JS.
|
||||
"libs/keycloak-js",
|
||||
],
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: "./tsconfig.eslint.json",
|
||||
|
|
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
|
@ -29,7 +29,7 @@ jobs:
|
|||
run: npm ci
|
||||
|
||||
- name: Run build task
|
||||
run: npm run build --workspace=admin-ui
|
||||
run: npm run build --workspace=keycloak-js --workspace=admin-ui
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
|
|
3
.github/workflows/main.yml
vendored
3
.github/workflows/main.yml
vendored
|
@ -23,6 +23,9 @@ jobs:
|
|||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Build Keycloak JS
|
||||
run: npm run build --workspace=keycloak-js
|
||||
|
||||
- name: Cache setup
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
|
|
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -7,10 +7,8 @@ yarn-error.log*
|
|||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# NPM
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
|
|
4
apps/admin-ui/.gitignore
vendored
Normal file
4
apps/admin-ui/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Vite
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
|
@ -24,7 +24,7 @@
|
|||
"flat": "^5.0.2",
|
||||
"i18next": "^21.9.1",
|
||||
"i18next-http-backend": "^1.4.1",
|
||||
"keycloak-js": "^19.0.1",
|
||||
"keycloak-js": "999.0.0-dev",
|
||||
"lodash-es": "^4.17.21",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
|
@ -54,7 +54,6 @@
|
|||
"@types/flat": "^5.0.2",
|
||||
"@types/gunzip-maybe": "^1.4.0",
|
||||
"@types/lodash-es": "^4.17.6",
|
||||
"@types/node": "^18.7.15",
|
||||
"@types/react": "^17.0.45",
|
||||
"@types/react-dom": "^17.0.16",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
<nexus.staging.plugin.version>1.6.13</nexus.staging.plugin.version>
|
||||
<frontend.maven.plugin.version>1.12.1</frontend.maven.plugin.version>
|
||||
<frontend.maven.plugin.nodeVersion>v18.7.0</frontend.maven.plugin.nodeVersion>
|
||||
<frontend.maven.plugin.nodeVersion>v18.9.0</frontend.maven.plugin.nodeVersion>
|
||||
|
||||
<keycloak.version>19.0.1</keycloak.version>
|
||||
|
||||
|
@ -237,7 +237,7 @@
|
|||
<goal>npm</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<arguments>run build --workspace=admin-ui</arguments>
|
||||
<arguments>run build --workspace=keycloak-js --workspace=admin-ui</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
|
|
2
libs/keycloak-js/.gitignore
vendored
Normal file
2
libs/keycloak-js/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
dist/*
|
||||
!dist/*.d.ts
|
3
libs/keycloak-js/README.md
Normal file
3
libs/keycloak-js/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Keycloak JS
|
||||
|
||||
The documentation can be found in the [Keycloak documentation](https://www.keycloak.org/docs/latest/securing_apps/index.html#_javascript_adapter).
|
133
libs/keycloak-js/dist/keycloak-authz.d.ts
vendored
Normal file
133
libs/keycloak-js/dist/keycloak-authz.d.ts
vendored
Normal file
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright 2017 Brett Epps <https://github.com/eppsilon>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
* associated documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
||||
* following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||
* portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
* LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
* NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
import Keycloak from './keycloak';
|
||||
|
||||
export interface KeycloakAuthorizationPromise {
|
||||
then(onGrant: (rpt: string) => void, onDeny: () => void, onError: () => void): void;
|
||||
}
|
||||
|
||||
export interface AuthorizationRequest {
|
||||
/**
|
||||
* An array of objects representing the resource and scopes.
|
||||
*/
|
||||
permissions?:ResourcePermission[],
|
||||
|
||||
/**
|
||||
* A permission ticket obtained from a resource server when using UMA authorization protocol.
|
||||
*/
|
||||
ticket?:string,
|
||||
|
||||
/**
|
||||
* A boolean value indicating whether the server should create permission requests to the resources
|
||||
* and scopes referenced by a permission ticket. This parameter will only take effect when used together
|
||||
* with the ticket parameter as part of a UMA authorization process.
|
||||
*/
|
||||
submitRequest?:boolean,
|
||||
|
||||
/**
|
||||
* Defines additional information about this authorization request in order to specify how it should be processed
|
||||
* by the server.
|
||||
*/
|
||||
metadata?:AuthorizationRequestMetadata,
|
||||
|
||||
/**
|
||||
* Defines whether or not this authorization request should include the current RPT. If set to true, the RPT will
|
||||
* be sent and permissions in the current RPT will be included in the new RPT. Otherwise, only the permissions referenced in this
|
||||
* authorization request will be granted in the new RPT.
|
||||
*/
|
||||
incrementalAuthorization?:boolean
|
||||
}
|
||||
|
||||
export interface AuthorizationRequestMetadata {
|
||||
/**
|
||||
* A boolean value indicating to the server if resource names should be included in the RPT’s permissions.
|
||||
* If false, only the resource identifier is included.
|
||||
*/
|
||||
responseIncludeResourceName?:any,
|
||||
|
||||
/**
|
||||
* An integer N that defines a limit for the amount of permissions an RPT can have. When used together with
|
||||
* rpt parameter, only the last N requested permissions will be kept in the RPT.
|
||||
*/
|
||||
response_permissions_limit?:number
|
||||
}
|
||||
|
||||
export interface ResourcePermission {
|
||||
/**
|
||||
* The id or name of a resource.
|
||||
*/
|
||||
id:string,
|
||||
|
||||
/**
|
||||
* An array of strings where each value is the name of a scope associated with the resource.
|
||||
*/
|
||||
scopes?:string[]
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Instead of importing 'KeycloakAuthorizationInstance' you can import 'KeycloakAuthorization' directly as a type.
|
||||
*/
|
||||
export type KeycloakAuthorizationInstance = KeycloakAuthorization;
|
||||
|
||||
/**
|
||||
* @deprecated Construct a KeycloakAuthorization instance using the `new` keyword instead.
|
||||
*/
|
||||
declare function KeycloakAuthorization(keycloak: Keycloak): KeycloakAuthorization;
|
||||
|
||||
declare class KeycloakAuthorization {
|
||||
/**
|
||||
* Creates a new Keycloak client instance.
|
||||
* @param config Path to a JSON config file or a plain config object.
|
||||
*/
|
||||
constructor(keycloak: Keycloak)
|
||||
|
||||
rpt: any;
|
||||
config: { rpt_endpoint: string };
|
||||
|
||||
init(): void;
|
||||
|
||||
/**
|
||||
* This method enables client applications to better integrate with resource servers protected by a Keycloak
|
||||
* policy enforcer using UMA protocol.
|
||||
*
|
||||
* The authorization request must be provided with a ticket.
|
||||
*
|
||||
* @param authorizationRequest An AuthorizationRequest instance with a valid permission ticket set.
|
||||
* @returns A promise to set functions to be invoked on grant, deny or error.
|
||||
*/
|
||||
authorize(authorizationRequest: AuthorizationRequest): KeycloakAuthorizationPromise;
|
||||
|
||||
/**
|
||||
* Obtains all entitlements from a Keycloak server based on a given resourceServerId.
|
||||
*
|
||||
* @param resourceServerId The id (client id) of the resource server to obtain permissions from.
|
||||
* @param authorizationRequest An AuthorizationRequest instance.
|
||||
* @returns A promise to set functions to be invoked on grant, deny or error.
|
||||
*/
|
||||
entitlement(resourceServerId: string, authorizationRequest?: AuthorizationRequest): KeycloakAuthorizationPromise;
|
||||
}
|
||||
|
||||
export default KeycloakAuthorization;
|
||||
|
||||
/**
|
||||
* @deprecated The 'KeycloakAuthorization' namespace is deprecated, use named imports instead.
|
||||
*/
|
||||
export as namespace KeycloakAuthorization;
|
653
libs/keycloak-js/dist/keycloak.d.ts
vendored
Normal file
653
libs/keycloak-js/dist/keycloak.d.ts
vendored
Normal file
|
@ -0,0 +1,653 @@
|
|||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright 2017 Brett Epps <https://github.com/eppsilon>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
* associated documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
||||
* following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||
* portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
* LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
* NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
export type KeycloakOnLoad = 'login-required'|'check-sso';
|
||||
export type KeycloakResponseMode = 'query'|'fragment';
|
||||
export type KeycloakResponseType = 'code'|'id_token token'|'code id_token token';
|
||||
export type KeycloakFlow = 'standard'|'implicit'|'hybrid';
|
||||
export type KeycloakPkceMethod = 'S256';
|
||||
|
||||
export interface KeycloakConfig {
|
||||
/**
|
||||
* URL to the Keycloak server, for example: http://keycloak-server/auth
|
||||
*/
|
||||
url?: string;
|
||||
/**
|
||||
* Name of the realm, for example: 'myrealm'
|
||||
*/
|
||||
realm: string;
|
||||
/**
|
||||
* Client identifier, example: 'myapp'
|
||||
*/
|
||||
clientId: string;
|
||||
}
|
||||
|
||||
export interface Acr {
|
||||
/**
|
||||
* Array of values, which will be used inside ID Token `acr` claim sent inside the `claims` parameter to Keycloak server during login.
|
||||
* Values should correspond to the ACR levels defined in the ACR to Loa mapping for realm or client or to the numbers (levels) inside defined
|
||||
* Keycloak authentication flow. See section 5.5.1 of OIDC 1.0 specification for the details.
|
||||
*/
|
||||
values: string[];
|
||||
/**
|
||||
* This parameter specifies if ACR claims is considered essential or not.
|
||||
*/
|
||||
essential: boolean;
|
||||
}
|
||||
|
||||
export interface KeycloakInitOptions {
|
||||
/**
|
||||
* Adds a [cryptographic nonce](https://en.wikipedia.org/wiki/Cryptographic_nonce)
|
||||
* to verify that the authentication response matches the request.
|
||||
* @default true
|
||||
*/
|
||||
useNonce?: boolean;
|
||||
|
||||
/**
|
||||
*
|
||||
* Allow usage of different types of adapters or a custom adapter to make Keycloak work in different environments.
|
||||
*
|
||||
* The following options are supported:
|
||||
* - `default` - Use default APIs that are available in browsers.
|
||||
* - `cordova` - Use a WebView in Cordova.
|
||||
* - `cordova-native` - Use Cordova native APIs, this is recommended over `cordova`.
|
||||
*
|
||||
* It's also possible to pass in a custom adapter for the environment you are running Keycloak in. In order to do so extend the `KeycloakAdapter` interface and implement the methods that are defined there.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* ```ts
|
||||
* import Keycloak, { KeycloakAdapter } from 'keycloak-js';
|
||||
*
|
||||
* // Implement the 'KeycloakAdapter' interface so that all required methods are guaranteed to be present.
|
||||
* const MyCustomAdapter: KeycloakAdapter = {
|
||||
* login(options) {
|
||||
* // Write your own implementation here.
|
||||
* }
|
||||
*
|
||||
* // The other methods go here...
|
||||
* };
|
||||
*
|
||||
* const keycloak = new Keycloak();
|
||||
*
|
||||
* keycloak.init({
|
||||
* adapter: MyCustomAdapter,
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
adapter?: 'default' | 'cordova' | 'cordova-native' | KeycloakAdapter;
|
||||
|
||||
/**
|
||||
* Specifies an action to do on load.
|
||||
*/
|
||||
onLoad?: KeycloakOnLoad;
|
||||
|
||||
/**
|
||||
* Set an initial value for the token.
|
||||
*/
|
||||
token?: string;
|
||||
|
||||
/**
|
||||
* Set an initial value for the refresh token.
|
||||
*/
|
||||
refreshToken?: string;
|
||||
|
||||
/**
|
||||
* Set an initial value for the id token (only together with `token` or
|
||||
* `refreshToken`).
|
||||
*/
|
||||
idToken?: string;
|
||||
|
||||
/**
|
||||
* Set an initial value for skew between local time and Keycloak server in
|
||||
* seconds (only together with `token` or `refreshToken`).
|
||||
*/
|
||||
timeSkew?: number;
|
||||
|
||||
/**
|
||||
* Set to enable/disable monitoring login state.
|
||||
* @default true
|
||||
*/
|
||||
checkLoginIframe?: boolean;
|
||||
|
||||
/**
|
||||
* Set the interval to check login state (in seconds).
|
||||
* @default 5
|
||||
*/
|
||||
checkLoginIframeInterval?: number;
|
||||
|
||||
/**
|
||||
* Set the OpenID Connect response mode to send to Keycloak upon login.
|
||||
* @default fragment After successful authentication Keycloak will redirect
|
||||
* to JavaScript application with OpenID Connect parameters
|
||||
* added in URL fragment. This is generally safer and
|
||||
* recommended over query.
|
||||
*/
|
||||
responseMode?: KeycloakResponseMode;
|
||||
|
||||
/**
|
||||
* Specifies a default uri to redirect to after login or logout.
|
||||
* This is currently supported for adapter 'cordova-native' and 'default'
|
||||
*/
|
||||
redirectUri?: string;
|
||||
|
||||
/**
|
||||
* Specifies an uri to redirect to after silent check-sso.
|
||||
* Silent check-sso will only happen, when this redirect uri is given and
|
||||
* the specified uri is available within the application.
|
||||
*/
|
||||
silentCheckSsoRedirectUri?: string;
|
||||
|
||||
/**
|
||||
* Specifies whether the silent check-sso should fallback to "non-silent"
|
||||
* check-sso when 3rd party cookies are blocked by the browser. Defaults
|
||||
* to true.
|
||||
*/
|
||||
silentCheckSsoFallback?: boolean;
|
||||
|
||||
/**
|
||||
* Set the OpenID Connect flow.
|
||||
* @default standard
|
||||
*/
|
||||
flow?: KeycloakFlow;
|
||||
|
||||
/**
|
||||
* Configures the Proof Key for Code Exchange (PKCE) method to use.
|
||||
* The currently allowed method is 'S256'.
|
||||
* If not configured, PKCE will not be used.
|
||||
*/
|
||||
pkceMethod?: KeycloakPkceMethod;
|
||||
|
||||
/**
|
||||
* Enables logging messages from Keycloak to the console.
|
||||
* @default false
|
||||
*/
|
||||
enableLogging?: boolean
|
||||
|
||||
/**
|
||||
* Set the default scope parameter to the login endpoint. Use a space-delimited list of scopes.
|
||||
* Note that the scope 'openid' will be always be added to the list of scopes by the adapter.
|
||||
* Note that the default scope specified here is overwritten if the `login()` options specify scope explicitly.
|
||||
*/
|
||||
scope?: string
|
||||
|
||||
/**
|
||||
* Configures how long will Keycloak adapter wait for receiving messages from server in ms. This is used,
|
||||
* for example, when waiting for response of 3rd party cookies check.
|
||||
*
|
||||
* @default 10000
|
||||
*/
|
||||
messageReceiveTimeout?: number
|
||||
}
|
||||
|
||||
export interface KeycloakLoginOptions {
|
||||
/**
|
||||
* Specifies the scope parameter for the login url
|
||||
* The scope 'openid' will be added to the scope if it is missing or undefined.
|
||||
*/
|
||||
scope?: string;
|
||||
|
||||
/**
|
||||
* Specifies the uri to redirect to after login.
|
||||
*/
|
||||
redirectUri?: string;
|
||||
|
||||
/**
|
||||
* By default the login screen is displayed if the user is not logged into
|
||||
* Keycloak. To only authenticate to the application if the user is already
|
||||
* logged in and not display the login page if the user is not logged in, set
|
||||
* this option to `'none'`. To always require re-authentication and ignore
|
||||
* SSO, set this option to `'login'`.
|
||||
*/
|
||||
prompt?: 'none'|'login';
|
||||
|
||||
/**
|
||||
* If value is `'register'` then user is redirected to registration page,
|
||||
* otherwise to login page.
|
||||
*/
|
||||
action?: string;
|
||||
|
||||
/**
|
||||
* Used just if user is already authenticated. Specifies maximum time since
|
||||
* the authentication of user happened. If user is already authenticated for
|
||||
* longer time than `'maxAge'`, the SSO is ignored and he will need to
|
||||
* authenticate again.
|
||||
*/
|
||||
maxAge?: number;
|
||||
|
||||
/**
|
||||
* Used to pre-fill the username/email field on the login form.
|
||||
*/
|
||||
loginHint?: string;
|
||||
|
||||
/**
|
||||
* Sets the `acr` claim of the ID token sent inside the `claims` parameter. See section 5.5.1 of the OIDC 1.0 specification.
|
||||
*/
|
||||
acr?: Acr;
|
||||
|
||||
/**
|
||||
* Used to tell Keycloak which IDP the user wants to authenticate with.
|
||||
*/
|
||||
idpHint?: string;
|
||||
|
||||
/**
|
||||
* Sets the 'ui_locales' query param in compliance with section 3.1.2.1
|
||||
* of the OIDC 1.0 specification.
|
||||
*/
|
||||
locale?: string;
|
||||
|
||||
/**
|
||||
* Specifies arguments that are passed to the Cordova in-app-browser (if applicable).
|
||||
* Options 'hidden' and 'location' are not affected by these arguments.
|
||||
* All available options are defined at https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-inappbrowser/.
|
||||
* Example of use: { zoom: "no", hardwareback: "yes" }
|
||||
*/
|
||||
cordovaOptions?: { [optionName: string]: string };
|
||||
}
|
||||
|
||||
export interface KeycloakLogoutOptions {
|
||||
/**
|
||||
* Specifies the uri to redirect to after logout.
|
||||
*/
|
||||
redirectUri?: string;
|
||||
}
|
||||
|
||||
export interface KeycloakRegisterOptions extends Omit<KeycloakLoginOptions, 'action'> { }
|
||||
|
||||
export interface KeycloakAccountOptions {
|
||||
/**
|
||||
* Specifies the uri to redirect to when redirecting back to the application.
|
||||
*/
|
||||
redirectUri?: string;
|
||||
}
|
||||
|
||||
export type KeycloakPromiseCallback<T> = (result: T) => void;
|
||||
|
||||
export interface KeycloakPromise<TSuccess, TError> extends Promise<TSuccess> {
|
||||
/**
|
||||
* Function to call if the promised action succeeds.
|
||||
*
|
||||
* @deprecated Use `.then()` instead.
|
||||
*/
|
||||
success(callback: KeycloakPromiseCallback<TSuccess>): KeycloakPromise<TSuccess, TError>;
|
||||
|
||||
/**
|
||||
* Function to call if the promised action throws an error.
|
||||
*
|
||||
* @deprecated Use `.catch()` instead.
|
||||
*/
|
||||
error(callback: KeycloakPromiseCallback<TError>): KeycloakPromise<TSuccess, TError>;
|
||||
}
|
||||
|
||||
export interface KeycloakError {
|
||||
error: string;
|
||||
error_description: string;
|
||||
}
|
||||
|
||||
export interface KeycloakAdapter {
|
||||
login(options?: KeycloakLoginOptions): KeycloakPromise<void, void>;
|
||||
logout(options?: KeycloakLogoutOptions): KeycloakPromise<void, void>;
|
||||
register(options?: KeycloakRegisterOptions): KeycloakPromise<void, void>;
|
||||
accountManagement(): KeycloakPromise<void, void>;
|
||||
redirectUri(options: { redirectUri: string; }, encodeHash: boolean): string;
|
||||
}
|
||||
|
||||
export interface KeycloakProfile {
|
||||
id?: string;
|
||||
username?: string;
|
||||
email?: string;
|
||||
firstName?: string;
|
||||
lastName?: string;
|
||||
enabled?: boolean;
|
||||
emailVerified?: boolean;
|
||||
totp?: boolean;
|
||||
createdTimestamp?: number;
|
||||
}
|
||||
|
||||
export interface KeycloakTokenParsed {
|
||||
iss?: string;
|
||||
sub?: string;
|
||||
aud?: string;
|
||||
exp?: number;
|
||||
iat?: number;
|
||||
auth_time?: number;
|
||||
nonce?: string;
|
||||
acr?: string;
|
||||
amr?: string;
|
||||
azp?: string;
|
||||
session_state?: string;
|
||||
realm_access?: KeycloakRoles;
|
||||
resource_access?: KeycloakResourceAccess;
|
||||
[key: string]: any; // Add other attributes here.
|
||||
}
|
||||
|
||||
export interface KeycloakResourceAccess {
|
||||
[key: string]: KeycloakRoles
|
||||
}
|
||||
|
||||
export interface KeycloakRoles {
|
||||
roles: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Instead of importing 'KeycloakInstance' you can import 'Keycloak' directly as a type.
|
||||
*/
|
||||
export type KeycloakInstance = Keycloak;
|
||||
|
||||
/**
|
||||
* @deprecated Construct a Keycloak instance using the `new` keyword instead.
|
||||
*/
|
||||
declare function Keycloak(config?: KeycloakConfig | string): Keycloak;
|
||||
|
||||
/**
|
||||
* A client for the Keycloak authentication server.
|
||||
* @see {@link https://keycloak.gitbooks.io/securing-client-applications-guide/content/topics/oidc/javascript-adapter.html|Keycloak JS adapter documentation}
|
||||
*/
|
||||
declare class Keycloak {
|
||||
/**
|
||||
* Creates a new Keycloak client instance.
|
||||
* @param config A configuration object or path to a JSON config file.
|
||||
*/
|
||||
constructor(config?: KeycloakConfig | string)
|
||||
|
||||
/**
|
||||
* Is true if the user is authenticated, false otherwise.
|
||||
*/
|
||||
authenticated?: boolean;
|
||||
|
||||
/**
|
||||
* The user id.
|
||||
*/
|
||||
subject?: string;
|
||||
|
||||
/**
|
||||
* Response mode passed in init (default value is `'fragment'`).
|
||||
*/
|
||||
responseMode?: KeycloakResponseMode;
|
||||
|
||||
/**
|
||||
* Response type sent to Keycloak with login requests. This is determined
|
||||
* based on the flow value used during initialization, but can be overridden
|
||||
* by setting this value.
|
||||
*/
|
||||
responseType?: KeycloakResponseType;
|
||||
|
||||
/**
|
||||
* Flow passed in init.
|
||||
*/
|
||||
flow?: KeycloakFlow;
|
||||
|
||||
/**
|
||||
* The realm roles associated with the token.
|
||||
*/
|
||||
realmAccess?: KeycloakRoles;
|
||||
|
||||
/**
|
||||
* The resource roles associated with the token.
|
||||
*/
|
||||
resourceAccess?: KeycloakResourceAccess;
|
||||
|
||||
/**
|
||||
* The base64 encoded token that can be sent in the Authorization header in
|
||||
* requests to services.
|
||||
*/
|
||||
token?: string;
|
||||
|
||||
/**
|
||||
* The parsed token as a JavaScript object.
|
||||
*/
|
||||
tokenParsed?: KeycloakTokenParsed;
|
||||
|
||||
/**
|
||||
* The base64 encoded refresh token that can be used to retrieve a new token.
|
||||
*/
|
||||
refreshToken?: string;
|
||||
|
||||
/**
|
||||
* The parsed refresh token as a JavaScript object.
|
||||
*/
|
||||
refreshTokenParsed?: KeycloakTokenParsed;
|
||||
|
||||
/**
|
||||
* The base64 encoded ID token.
|
||||
*/
|
||||
idToken?: string;
|
||||
|
||||
/**
|
||||
* The parsed id token as a JavaScript object.
|
||||
*/
|
||||
idTokenParsed?: KeycloakTokenParsed;
|
||||
|
||||
/**
|
||||
* The estimated time difference between the browser time and the Keycloak
|
||||
* server in seconds. This value is just an estimation, but is accurate
|
||||
* enough when determining if a token is expired or not.
|
||||
*/
|
||||
timeSkew?: number;
|
||||
|
||||
/**
|
||||
* @private Undocumented.
|
||||
*/
|
||||
loginRequired?: boolean;
|
||||
|
||||
/**
|
||||
* @private Undocumented.
|
||||
*/
|
||||
authServerUrl?: string;
|
||||
|
||||
/**
|
||||
* @private Undocumented.
|
||||
*/
|
||||
realm?: string;
|
||||
|
||||
/**
|
||||
* @private Undocumented.
|
||||
*/
|
||||
clientId?: string;
|
||||
|
||||
/**
|
||||
* @private Undocumented.
|
||||
*/
|
||||
clientSecret?: string;
|
||||
|
||||
/**
|
||||
* @private Undocumented.
|
||||
*/
|
||||
redirectUri?: string;
|
||||
|
||||
/**
|
||||
* @private Undocumented.
|
||||
*/
|
||||
sessionId?: string;
|
||||
|
||||
/**
|
||||
* @private Undocumented.
|
||||
*/
|
||||
profile?: KeycloakProfile;
|
||||
|
||||
/**
|
||||
* @private Undocumented.
|
||||
*/
|
||||
userInfo?: {}; // KeycloakUserInfo;
|
||||
|
||||
/**
|
||||
* Called when the adapter is initialized.
|
||||
*/
|
||||
onReady?(authenticated?: boolean): void;
|
||||
|
||||
/**
|
||||
* Called when a user is successfully authenticated.
|
||||
*/
|
||||
onAuthSuccess?(): void;
|
||||
|
||||
/**
|
||||
* Called if there was an error during authentication.
|
||||
*/
|
||||
onAuthError?(errorData: KeycloakError): void;
|
||||
|
||||
/**
|
||||
* Called when the token is refreshed.
|
||||
*/
|
||||
onAuthRefreshSuccess?(): void;
|
||||
|
||||
/**
|
||||
* Called if there was an error while trying to refresh the token.
|
||||
*/
|
||||
onAuthRefreshError?(): void;
|
||||
|
||||
/**
|
||||
* Called if the user is logged out (will only be called if the session
|
||||
* status iframe is enabled, or in Cordova mode).
|
||||
*/
|
||||
onAuthLogout?(): void;
|
||||
|
||||
/**
|
||||
* Called when the access token is expired. If a refresh token is available
|
||||
* the token can be refreshed with Keycloak#updateToken, or in cases where
|
||||
* it's not (ie. with implicit flow) you can redirect to login screen to
|
||||
* obtain a new access token.
|
||||
*/
|
||||
onTokenExpired?(): void;
|
||||
|
||||
/**
|
||||
* Called when a AIA has been requested by the application.
|
||||
*/
|
||||
onActionUpdate?(status: 'success'|'cancelled'|'error'): void;
|
||||
|
||||
/**
|
||||
* Called to initialize the adapter.
|
||||
* @param initOptions Initialization options.
|
||||
* @returns A promise to set functions to be invoked on success or error.
|
||||
*/
|
||||
init(initOptions: KeycloakInitOptions): KeycloakPromise<boolean, KeycloakError>;
|
||||
|
||||
/**
|
||||
* Redirects to login form.
|
||||
* @param options Login options.
|
||||
*/
|
||||
login(options?: KeycloakLoginOptions): KeycloakPromise<void, void>;
|
||||
|
||||
/**
|
||||
* Redirects to logout.
|
||||
* @param options Logout options.
|
||||
*/
|
||||
logout(options?: KeycloakLogoutOptions): KeycloakPromise<void, void>;
|
||||
|
||||
/**
|
||||
* Redirects to registration form.
|
||||
* @param options The options used for the registration.
|
||||
*/
|
||||
register(options?: KeycloakRegisterOptions): KeycloakPromise<void, void>;
|
||||
|
||||
/**
|
||||
* Redirects to the Account Management Console.
|
||||
*/
|
||||
accountManagement(): KeycloakPromise<void, void>;
|
||||
|
||||
/**
|
||||
* Returns the URL to login form.
|
||||
* @param options Supports same options as Keycloak#login.
|
||||
*/
|
||||
createLoginUrl(options?: KeycloakLoginOptions): string;
|
||||
|
||||
/**
|
||||
* Returns the URL to logout the user.
|
||||
* @param options Logout options.
|
||||
*/
|
||||
createLogoutUrl(options?: KeycloakLogoutOptions): string;
|
||||
|
||||
/**
|
||||
* Returns the URL to registration page.
|
||||
* @param options The options used for creating the registration URL.
|
||||
*/
|
||||
createRegisterUrl(options?: KeycloakRegisterOptions): string;
|
||||
|
||||
/**
|
||||
* Returns the URL to the Account Management Console.
|
||||
* @param options The options used for creating the account URL.
|
||||
*/
|
||||
createAccountUrl(options?: KeycloakAccountOptions): string;
|
||||
|
||||
/**
|
||||
* Returns true if the token has less than `minValidity` seconds left before
|
||||
* it expires.
|
||||
* @param minValidity If not specified, `0` is used.
|
||||
*/
|
||||
isTokenExpired(minValidity?: number): boolean;
|
||||
|
||||
/**
|
||||
* If the token expires within `minValidity` seconds, the token is refreshed.
|
||||
* If the session status iframe is enabled, the session status is also
|
||||
* checked.
|
||||
* @returns A promise to set functions that can be invoked if the token is
|
||||
* still valid, or if the token is no longer valid.
|
||||
* @example
|
||||
* ```js
|
||||
* keycloak.updateToken(5).then(function(refreshed) {
|
||||
* if (refreshed) {
|
||||
* alert('Token was successfully refreshed');
|
||||
* } else {
|
||||
* alert('Token is still valid');
|
||||
* }
|
||||
* }).catch(function() {
|
||||
* alert('Failed to refresh the token, or the session has expired');
|
||||
* });
|
||||
*/
|
||||
updateToken(minValidity: number): KeycloakPromise<boolean, boolean>;
|
||||
|
||||
/**
|
||||
* Clears authentication state, including tokens. This can be useful if
|
||||
* the application has detected the session was expired, for example if
|
||||
* updating token fails. Invoking this results in Keycloak#onAuthLogout
|
||||
* callback listener being invoked.
|
||||
*/
|
||||
clearToken(): void;
|
||||
|
||||
/**
|
||||
* Returns true if the token has the given realm role.
|
||||
* @param role A realm role name.
|
||||
*/
|
||||
hasRealmRole(role: string): boolean;
|
||||
|
||||
/**
|
||||
* Returns true if the token has the given role for the resource.
|
||||
* @param role A role name.
|
||||
* @param resource If not specified, `clientId` is used.
|
||||
*/
|
||||
hasResourceRole(role: string, resource?: string): boolean;
|
||||
|
||||
/**
|
||||
* Loads the user's profile.
|
||||
* @returns A promise to set functions to be invoked on success or error.
|
||||
*/
|
||||
loadUserProfile(): KeycloakPromise<KeycloakProfile, void>;
|
||||
|
||||
/**
|
||||
* @private Undocumented.
|
||||
*/
|
||||
loadUserInfo(): KeycloakPromise<{}, void>;
|
||||
}
|
||||
|
||||
export default Keycloak;
|
||||
|
||||
/**
|
||||
* @deprecated The 'Keycloak' namespace is deprecated, use named imports instead.
|
||||
*/
|
||||
export as namespace Keycloak;
|
42
libs/keycloak-js/package.json
Normal file
42
libs/keycloak-js/package.json
Normal file
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"name": "keycloak-js",
|
||||
"version": "999.0.0-dev",
|
||||
"description": "Keycloak Adapter",
|
||||
"main": "./dist/keycloak.js",
|
||||
"module": "./dist/keycloak.mjs",
|
||||
"types": "./dist/keycloak.d.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "rollup --config --configPlugin typescript",
|
||||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/keycloak/keycloak-ui"
|
||||
},
|
||||
"author": "Keycloak",
|
||||
"license": "Apache-2.0",
|
||||
"homepage": "https://www.keycloak.org",
|
||||
"keywords": [
|
||||
"keycloak",
|
||||
"sso",
|
||||
"oauth",
|
||||
"oauth2",
|
||||
"authentication"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-commonjs": "^22.0.1",
|
||||
"@rollup/plugin-inject": "^4.0.4",
|
||||
"@rollup/plugin-node-resolve": "^13.1.3",
|
||||
"@rollup/plugin-typescript": "^8.3.0",
|
||||
"es6-promise": "^4.2.8",
|
||||
"rollup": "^2.67.1",
|
||||
"rollup-plugin-terser": "^7.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"base64-js": "^1.5.1",
|
||||
"js-sha256": "^0.9.0"
|
||||
}
|
||||
}
|
81
libs/keycloak-js/rollup.config.ts
Normal file
81
libs/keycloak-js/rollup.config.ts
Normal file
|
@ -0,0 +1,81 @@
|
|||
import commonjs from "@rollup/plugin-commonjs";
|
||||
import inject from "@rollup/plugin-inject";
|
||||
import { nodeResolve } from "@rollup/plugin-node-resolve";
|
||||
import path from "node:path";
|
||||
import type { OutputOptions, RollupOptions } from "rollup";
|
||||
import { defineConfig } from "rollup";
|
||||
import { terser } from "rollup-plugin-terser";
|
||||
|
||||
interface DefineOptionsArgs {
|
||||
file: string;
|
||||
name: string;
|
||||
amdId: string;
|
||||
}
|
||||
|
||||
function defineOptions({
|
||||
file,
|
||||
name,
|
||||
amdId,
|
||||
}: DefineOptionsArgs): RollupOptions[] {
|
||||
const sourceDir = "src";
|
||||
const targetDir = "dist";
|
||||
const commonOptions: RollupOptions = {
|
||||
input: path.join(sourceDir, `${file}.js`),
|
||||
plugins: [commonjs(), nodeResolve()],
|
||||
};
|
||||
|
||||
const umdOutput: OutputOptions = {
|
||||
format: "umd",
|
||||
name,
|
||||
amd: { id: amdId },
|
||||
};
|
||||
|
||||
return [
|
||||
// Modern ES module variant, with externalized dependencies.
|
||||
{
|
||||
...commonOptions,
|
||||
output: [
|
||||
{
|
||||
file: path.join(targetDir, `${file}.mjs`),
|
||||
},
|
||||
],
|
||||
external: ["base64-js", "js-sha256"],
|
||||
},
|
||||
// Legacy Universal Module Definition, or “UMD”, with inlined dependencies.
|
||||
{
|
||||
...commonOptions,
|
||||
output: [
|
||||
{
|
||||
...umdOutput,
|
||||
file: path.join(targetDir, `${file}.js`),
|
||||
},
|
||||
{
|
||||
...umdOutput,
|
||||
file: path.join(targetDir, `${file}.min.js`),
|
||||
sourcemap: true,
|
||||
sourcemapExcludeSources: true,
|
||||
plugins: [terser()],
|
||||
},
|
||||
],
|
||||
plugins: [
|
||||
...commonOptions.plugins,
|
||||
inject({
|
||||
Promise: ["es6-promise/dist/es6-promise.min.js", "Promise"],
|
||||
}),
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export default defineConfig([
|
||||
...defineOptions({
|
||||
file: "keycloak",
|
||||
name: "Keycloak",
|
||||
amdId: "keycloak",
|
||||
}),
|
||||
...defineOptions({
|
||||
file: "keycloak-authz",
|
||||
name: "KeycloakAuthorization",
|
||||
amdId: "keycloak-authorization",
|
||||
}),
|
||||
]);
|
221
libs/keycloak-js/src/keycloak-authz.js
Normal file
221
libs/keycloak-js/src/keycloak-authz.js
Normal file
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
var KeycloakAuthorization = function (keycloak, options) {
|
||||
var _instance = this;
|
||||
this.rpt = null;
|
||||
|
||||
var resolve = function () {};
|
||||
var reject = function () {};
|
||||
|
||||
// detects if browser supports promises
|
||||
if (typeof Promise !== "undefined" && Promise.toString().indexOf("[native code]") !== -1) {
|
||||
this.ready = new Promise(function (res, rej) {
|
||||
resolve = res;
|
||||
reject = rej;
|
||||
});
|
||||
}
|
||||
|
||||
this.init = function () {
|
||||
var request = new XMLHttpRequest();
|
||||
|
||||
request.open('GET', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/.well-known/uma2-configuration');
|
||||
request.onreadystatechange = function () {
|
||||
if (request.readyState == 4) {
|
||||
if (request.status == 200) {
|
||||
_instance.config = JSON.parse(request.responseText);
|
||||
resolve();
|
||||
} else {
|
||||
console.error('Could not obtain configuration from server.');
|
||||
reject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
request.send(null);
|
||||
};
|
||||
|
||||
/**
|
||||
* This method enables client applications to better integrate with resource servers protected by a Keycloak
|
||||
* policy enforcer using UMA protocol.
|
||||
*
|
||||
* The authorization request must be provided with a ticket.
|
||||
*/
|
||||
this.authorize = function (authorizationRequest) {
|
||||
this.then = function (onGrant, onDeny, onError) {
|
||||
if (authorizationRequest && authorizationRequest.ticket) {
|
||||
var request = new XMLHttpRequest();
|
||||
|
||||
request.open('POST', _instance.config.token_endpoint, true);
|
||||
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token);
|
||||
|
||||
request.onreadystatechange = function () {
|
||||
if (request.readyState == 4) {
|
||||
var status = request.status;
|
||||
|
||||
if (status >= 200 && status < 300) {
|
||||
var rpt = JSON.parse(request.responseText).access_token;
|
||||
_instance.rpt = rpt;
|
||||
onGrant(rpt);
|
||||
} else if (status == 403) {
|
||||
if (onDeny) {
|
||||
onDeny();
|
||||
} else {
|
||||
console.error('Authorization request was denied by the server.');
|
||||
}
|
||||
} else {
|
||||
if (onError) {
|
||||
onError();
|
||||
} else {
|
||||
console.error('Could not obtain authorization data from server.');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var params = "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket&client_id=" + keycloak.clientId + "&ticket=" + authorizationRequest.ticket;
|
||||
|
||||
if (authorizationRequest.submitRequest != undefined) {
|
||||
params += "&submit_request=" + authorizationRequest.submitRequest;
|
||||
}
|
||||
|
||||
var metadata = authorizationRequest.metadata;
|
||||
|
||||
if (metadata) {
|
||||
if (metadata.responseIncludeResourceName) {
|
||||
params += "&response_include_resource_name=" + metadata.responseIncludeResourceName;
|
||||
}
|
||||
if (metadata.responsePermissionsLimit) {
|
||||
params += "&response_permissions_limit=" + metadata.responsePermissionsLimit;
|
||||
}
|
||||
}
|
||||
|
||||
if (_instance.rpt && (authorizationRequest.incrementalAuthorization == undefined || authorizationRequest.incrementalAuthorization)) {
|
||||
params += "&rpt=" + _instance.rpt;
|
||||
}
|
||||
|
||||
request.send(params);
|
||||
}
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Obtains all entitlements from a Keycloak Server based on a given resourceServerId.
|
||||
*/
|
||||
this.entitlement = function (resourceServerId, authorizationRequest) {
|
||||
this.then = function (onGrant, onDeny, onError) {
|
||||
var request = new XMLHttpRequest();
|
||||
|
||||
request.open('POST', _instance.config.token_endpoint, true);
|
||||
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token);
|
||||
|
||||
request.onreadystatechange = function () {
|
||||
if (request.readyState == 4) {
|
||||
var status = request.status;
|
||||
|
||||
if (status >= 200 && status < 300) {
|
||||
var rpt = JSON.parse(request.responseText).access_token;
|
||||
_instance.rpt = rpt;
|
||||
onGrant(rpt);
|
||||
} else if (status == 403) {
|
||||
if (onDeny) {
|
||||
onDeny();
|
||||
} else {
|
||||
console.error('Authorization request was denied by the server.');
|
||||
}
|
||||
} else {
|
||||
if (onError) {
|
||||
onError();
|
||||
} else {
|
||||
console.error('Could not obtain authorization data from server.');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (!authorizationRequest) {
|
||||
authorizationRequest = {};
|
||||
}
|
||||
|
||||
var params = "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket&client_id=" + keycloak.clientId;
|
||||
|
||||
if (authorizationRequest.claimToken) {
|
||||
params += "&claim_token=" + authorizationRequest.claimToken;
|
||||
|
||||
if (authorizationRequest.claimTokenFormat) {
|
||||
params += "&claim_token_format=" + authorizationRequest.claimTokenFormat;
|
||||
}
|
||||
}
|
||||
|
||||
params += "&audience=" + resourceServerId;
|
||||
|
||||
var permissions = authorizationRequest.permissions;
|
||||
|
||||
if (!permissions) {
|
||||
permissions = [];
|
||||
}
|
||||
|
||||
for (var i = 0; i < permissions.length; i++) {
|
||||
var resource = permissions[i];
|
||||
var permission = resource.id;
|
||||
|
||||
if (resource.scopes && resource.scopes.length > 0) {
|
||||
permission += "#";
|
||||
for (j = 0; j < resource.scopes.length; j++) {
|
||||
var scope = resource.scopes[j];
|
||||
if (permission.indexOf('#') != permission.length - 1) {
|
||||
permission += ",";
|
||||
}
|
||||
permission += scope;
|
||||
}
|
||||
}
|
||||
|
||||
params += "&permission=" + permission;
|
||||
}
|
||||
|
||||
var metadata = authorizationRequest.metadata;
|
||||
|
||||
if (metadata) {
|
||||
if (metadata.responseIncludeResourceName) {
|
||||
params += "&response_include_resource_name=" + metadata.responseIncludeResourceName;
|
||||
}
|
||||
if (metadata.responsePermissionsLimit) {
|
||||
params += "&response_permissions_limit=" + metadata.responsePermissionsLimit;
|
||||
}
|
||||
}
|
||||
|
||||
if (_instance.rpt) {
|
||||
params += "&rpt=" + _instance.rpt;
|
||||
}
|
||||
|
||||
request.send(params);
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
this.init(this);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
export default KeycloakAuthorization;
|
1740
libs/keycloak-js/src/keycloak.js
Executable file
1740
libs/keycloak-js/src/keycloak.js
Executable file
File diff suppressed because it is too large
Load diff
5
libs/keycloak-js/tsconfig.json
Normal file
5
libs/keycloak-js/tsconfig.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"allowSyntheticDefaultImports": true
|
||||
}
|
||||
}
|
1932
package-lock.json
generated
1932
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -1,12 +1,14 @@
|
|||
{
|
||||
"name": "keycloak-ui",
|
||||
"workspaces": [
|
||||
"libs/keycloak-js",
|
||||
"apps/admin-ui"
|
||||
],
|
||||
"scripts": {
|
||||
"prepare": "husky install"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.7.16",
|
||||
"@typescript-eslint/eslint-plugin": "^5.36.0",
|
||||
"@typescript-eslint/parser": "^5.36.0",
|
||||
"eslint": "^8.23.0",
|
||||
|
|
Loading…
Reference in a new issue