Coder Social home page Coder Social logo

react-keycloak / keycloak-ts Goto Github PK

View Code? Open in Web Editor NEW
29.0 4.0 15.0 697 KB

Typescript porting of Keycloak javascript client :construction: Under development :construction:

License: MIT License

JavaScript 0.37% TypeScript 99.37% Shell 0.25%
keycloak keycloak-client keycloak-js

keycloak-ts's Introduction

⚠️ DEPRECATED and UNMAINTAINED

This library is deprecated and will no longer be maintained or updated.

Instead, it is recommended to use:



React Keycloak

React Keycloak

React bindings for Keycloak

NPM (scoped) NPM (scoped) NPM (scoped) NPM (scoped)

License lerna GitHub contributors Github Issues npm

Gitter


Table of Contents


Integrations

React

React Keycloak for Web requires:

  • React 16.0 or later
  • keycloak-js 9.0.2 or later
yarn add @react-keycloak/web

or

npm install --save @react-keycloak/web

or as a UMD package through unpkg

See @react-keycloak/web package README for complete documentation.

SSR

React Keycloak for SSR frameworks requires:

  • React 16.0 or later
  • SSR Framework:
    • NextJS 9 or later
    • Razzle 3 or later
  • keycloak-js 9.0.2 or later
yarn add @react-keycloak/ssr

or

npm install --save @react-keycloak/ssr

See @react-keycloak/ssr package README for complete documentation.

React Native

React Keycloak for React Native requires React Native 61.0 or later

To install run

yarn add @react-keycloak/native

or

npm install --save @react-keycloak/native

See @react-keycloak/native package README for complete documentation.

Support

version keycloak-js version
v2.0.0+ 9.0.2+
v1.x >=8.0.2 <9.0.2

Examples

See @react-keycloak/react-keycloak-examples repository for various demo implementing this library main features.

Alternatives

If you need to connect using a more generic OIDC client instead of keycloak.js, consider using one of the following libraries:

Contributing

See the contributing guide to learn how to contribute to the repository and the development workflow.

License

MIT

keycloak-ts's People

Contributors

irontony avatar luneo7 avatar panz3r avatar ronaldvdh-isaac avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

keycloak-ts's Issues

Acces token is not refreshed after expiration time is met and refresh token is still valid

Describe the bug
When the expiration time of the access token is past, the new token is not fetched

To Reproduce
Steps to reproduce the behavior:

  1. Login in react-native app successfully
  2. Reload the app and notice auto login because refresh token is still valid
  3. Wait for token to expire (i set it for testing purposes in the keycloak console to 1 minute but it also happened when it was on 5 minutes)
  4. Observe 'OnTokenExpired' event is fired by the ReactNativeKeycloakProvider
  5. Observe 'UpdateToken' is triggered (i put some console.logs)
  6. Observe it takes the short escape as it already found a defined promise
if (this.refreshTokenPromise) {
      return this.refreshTokenPromise;
    }
  1. No new acces token is fetched so next api call is with the expired access token which results in 401 (which is correct as the token is expired)
  2. Reloading the app will use the valid refreshtoken to fetch a new accesstoken and voila api calls are valid again without re-entering credentials. until the token with logging in is expired and no new tokens are retrieved with the updateToken call.

Expected behavior
I expect after returning to the react-native app that the access token will be tried to be updated after it expires.

Screenshots
If applicable, add screenshots to help explain your problem.
image

Updated client.js in node_modules to set the console.logs:

async updateToken(minValidity = 5) {
    if (!this.refreshToken) {
      throw new Error('missing refreshToken');
    }

    console.log('Update token root: ', {refreshTokenPromise: this.refreshTokenPromise})
    if (this.refreshTokenPromise) {
      return this.refreshTokenPromise;
    }

    this.refreshTokenPromise = new Promise(async (resolve, reject) => {
      let shouldRefreshToken = false;

      if (minValidity === -1) {
        shouldRefreshToken = true;
        this.logInfo('[KEYCLOAK] Refreshing token: forced refresh');
      } else if (!this.tokenParsed || this.isTokenExpired(minValidity)) {
        shouldRefreshToken = true;
        this.logInfo('[KEYCLOAK] Refreshing token: token expired');
      }

      if (!shouldRefreshToken) {
        resolve(false);
        this.refreshTokenPromise = undefined;
        console.log('!shouldRefreshToken', {refreshTokenPromise: this.refreshTokenPromise})
        return;
      }

      const tokenUrl = this.endpoints.token();
      const params = new Map();
      params.set('client_id', this.clientId);
      params.set('grant_type', 'refresh_token');
      params.set('refresh_token', this.refreshToken);
      let timeLocal = new Date().getTime();

      try {
        const tokenResponse = await this.adapter.refreshTokens(tokenUrl, (0, _url.formatQuerystringParameters)(params));
        this.logInfo('[KEYCLOAK] Token refreshed');
        timeLocal = (timeLocal + new Date().getTime()) / 2;
        this.setToken(tokenResponse.access_token, tokenResponse.refresh_token, tokenResponse.id_token, timeLocal); // Notify onAuthRefreshSuccess event handler if set

        this.onAuthRefreshSuccess && this.onAuthRefreshSuccess();
        resolve(true);
      } catch (err) {
        this.logWarn('[KEYCLOAK] Failed to refresh token'); // Clear tokens

        this.clearToken(); // Notify onAuthRefreshError event handler if set

        this.onAuthRefreshError && this.onAuthRefreshError();
        reject();
      }

      this.refreshTokenPromise = undefined;
      console.log('Token Response: ', {refreshTokenPromise: this.refreshTokenPromise})
    });
    return this.refreshTokenPromise;
  }

Smartphone (please complete the following information):

  • Device: iPhone 11
  • OS: iOS 14.5
  • Browser: stock browser (safari)

Additional context
As far as i could see there is only one spot where this.refreshTokenPromise is set and this is in the updateToken function. And it seems that the code that sets this promise as undefined is hit, but when coming back to the app it is already set without any token call being executed.

P.S. Currently im running patch-package in my app and i just comment out the check for an existing refreshTokenPromise which solves the 401 error after your first access token is expired.

P.S2. I had accidently reported the issue under the wrong package (react-keycloak/react-keycloak#147). Although keycloak-ts is under development, it is required by the react-keycloak/native package and therefore hitting the code mentioned above. Now im also unsure if i should report the issue here or under react-keycloak/native package. But since the code my app is hitting is in keycloak-ts, i created the issue here.

Concurrency issue with updateToken method

Describe the bug
When doing multiple/concurrent calls to updateToken we end up in a bad state where refreshTokenPromise exists but the promise is already fulfilled, so all other calls to updateToken doesn't work since it won't do the token refresh and will return the existing promise fulfilled promise.

Also when doing the refresh token we should only clear the tokens if the API returns 400, that will have a body payload containing a JSON with an error entry there.

If the user has a problem with internet in a mobile device and the updateTokens fails the user will be logged out, since the tokens will be cleared.

To Reproduce
Steps to reproduce the behavior:

  1. Use a project with react native
  2. Do a successful login
  3. The app does multiple calls to API wrapping the calls in updateToken(30)
  4. Check app logs for events and token refresh that should happen every 1 minute, and see that it won't refresh anything.

Expected behavior
updateToken should always work, and the token should only be cleared when we have an 400 from the API.

Keycloak Authz Donation

Hello, recently I have been working on several apps where I needed to use the keycloak authz code, and ended up finding the official code unusable. I have since then re-implemented the same api, but in typescript, and using modern js features (such as the fetch api). I was hoping that I could find a good home for this code, and was hoping that I might be able to donate it to react-keycloak and keycloak-ts. Please let me know if you are open to this donation, and have a wonderful day! :)

generatePkceChallenge does not generate PKCE challenge

Describe the bug
generatePkceChallenge does not generate PKCE challenge even though valid pkceMethod and codeVerifier were given

To Reproduce

import { generatePkceChallenge } from '../utils/uuid';

describe('utils', () => {
  describe('uuid', () => {
    describe('generatePkceChallenge', () => {
      it('should generate PKCE challenge', () => {
        const pkceMethod = 'S256';
        const codeVerifier =
          'HkT1H162h8q51qmekRQB2x7DDzTiIEo25rr3awXHS3FCMD4t2Hxa0vpWKCFarHE4om5fQujSmdUqjplJMVv0Cf9duh6Mv5hN';

        const pkceChallenge = generatePkceChallenge(pkceMethod, codeVerifier);

        expect(pkceChallenge).toBeTruthy();
      });
    });
  });
});

Expected behavior
PKCE challenge is generated

Screenshots

FAIL  src/__tests__/uuid.spec.ts
  ● utils › uuid › generatePkceChallenge › should generate PKCE challenge

    expect(received).toBeTruthy()

    Received: ""

      11 |         const pkceChallenge = generatePkceChallenge(pkceMethod, codeVerifier);
      12 |
    > 13 |         expect(pkceChallenge).toBeTruthy();
         |                               ^
      14 |       });
      15 |     });
      16 |   });

      at Object.<anonymous> (src/__tests__/uuid.spec.ts:13:31)

generatePkceChallenge returns an empty string

Describe the bug
generatePkceChallenge returns an empty string

To Reproduce
Steps to reproduce the behavior:

  1. Call generatePkceChallenge with 'S256' as the first parameter and generateCodeVerifier(96) as the second
  2. Observer returned string is empty.

Expected behavior
I expect to have a usable pkceChallenge that can be used for the pkce flow in keycloak

Smartphone (please complete the following information):

  • Device: Pixel 3A
  • OS: Android 11
  • Browser Firefox
  • Version 90.1.2

Additional context
pkce flow is not working with the current package.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.