Giter VIP home page Giter VIP logo

plusauth / oidc-client-js Goto Github PK

View Code? Open in Web Editor NEW
12.0 12.0 6.0 3.18 MB

OpenID Connect (OIDC) and OAuth2 library for browser-based JavaScript applications.

Home Page: https://plusauth.github.io/oidc-client-js/

License: MIT License

JavaScript 3.77% TypeScript 96.13% Shell 0.10%
authentication javascript jwt oauth2 oauth2-library oidc oidc-client openid-connect openid-connect-client plusauth typescript

oidc-client-js's People

Contributors

ayzagen avatar mjudeikis avatar

Stargazers

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

Watchers

 avatar  avatar  avatar

oidc-client-js's Issues

Throw error when login popup is closed by the user

Hi—thanks for putting this library together. I've been experimenting with it for a few days and it works really well 🙌

One thing that might be a nice addition is throwing a custom OIDCClientError when the user manually closes the login popup. I believe I've seen this in other OAuth libraries. Is this something you would consider adding?

It seems like this scenario could be tracked or detected in the runPopup method, similar to the timeoutId:

export function runPopup( url: string, options: PopupOptions ) {

Deleted getter expires_at in minor release

By fixing #17, the minor 1.3.0 introduced a breaking change.

We make use of getExpiresAt to avoid using the timer and comparing the value to now before api calls, could it be restored?

CORS error when using with Google identity

When using issuer https://accounts.google.com, the library fails as Google does not seem to support the content-type header in the openid configuration request.

Error message:
Access to fetch at 'https://accounts.google.com/.well-known/openid-configuration' from origin 'http://localhost:3000' has been blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.

response_mode parameter not passed to authorization endpoint

When I use this library with config:

      response_mode: 'fragment',
      response_type: 'id_token token'

The tokens are returned in a fragment

When I use this library with config:

      response_mode: 'fragment',
      response_type: 'code'

The tokens are returned in a query

I guess this depends on provider setting, but when I added manually response_mode in query string to authorization endpoint for second configuration, it worked and returned as a fragment.

client_secret in options vs extraParams

Current behavior is that during a token request, the client_secret is not being sent unless it's configured in a way that even the code doesn't seem to anticipate.

It is called here:

  /**
   * Exchange authorization code retrieved from auth request result.
   * @param options
   * @private
   */
  private async exchangeAuthorizationCode( options: TokenRequestOption ){
    if ( !this.options.endpoints?.token_endpoint ){
      await this.fetchFromIssuer();
    }
    const { extraTokenHeaders, extraTokenParams, ...rest } = options

    const mergedOptions = {
      grant_type:    'authorization_code',
      client_id:     this.options.client_id,
      client_secret: this.options.client_secret,
      redirect_uri:  this.options.redirect_uri,
      ...rest,
      ...extraTokenParams || {}
    }

    for ( const req of ['code', 'redirect_uri', 'code_verifier', 'client_id'] as const ){
      if ( !mergedOptions[req] ){
        return Promise.reject( new Error( `"${ req }" is required` ) );
      }
    }

    return this.http( {
      url:         `${ this.options.endpoints!.token_endpoint }`,
      method:      'POST',
      requestType: 'form',
      body:        mergedOptions as any,
      headers:     extraTokenHeaders
    } )
  }

but due to earlier code, namely in createAuthRequest, which saves authParams to state without client_secret property, and then loginCallback which retrieves the authParams from state, the client_secrets will always get wiped out from the mergedOptions unless they are added to extraParams in the client configuration like so:

const auth= new OIDCClient({
  issue: 'foo'
  ...
  silent_redirect_uri: '...',
  extraParams: {
    client_secret: 'foo_secret'
  }
})

This IPlusAuthClientOptions has a property for client_secrets, but due to later (mis)handling of it in the code, it is effectively lost:

export interface IPlusAuthClientOptions extends Omit<AuthRequestOptions, 'request_type'>,
  Omit<LogoutRequestOptions, 'localOnly'> {
  authStore?: StateStore;
  /**
   * Enable/disable automatic access token renewal. If enabled, access tokens will be refreshed by using silent
   * login in an iframe before they expire.
   *
   * Also see {@link secondsToRefreshAccessTokenBeforeExp}
   */
  autoSilentRenew?: boolean;
  /**
   * Enable/Disable session monitoring.
   */
  checkSession?: boolean;

  /**
   * Session checking interval in milliseconds. Defaults to 2000
   */
  checkSessionInterval?: number;

  client_id: string;

  client_secret?: string;
}

Add getter for expires_in

In 9c8718e, you added getter for expires_at.

My initial request was to be able to calculate expires_at after new tokens retrieval to manually trigger token renewal.

Most IDP provider will provide expires_in, but only a few do provide expires_at, this is why I was calculating it from expires_in.

Would it be therefore possible to have a getter for expires_in as well?

Auto renewal of access token using refresh token

Hello,

I was looking for suitable client OIDC OAuth2 javascript library to my Single page application(SPA). I researched and came accross this plusauth oidc-client library and looks very impressive and promising as it handles more use cases and feature rich for SSO login support. But i have this access token renewal with refresh token api call and faced some issues as i mention in below. I followed steps as per your documentation and saw some shortcomming in handling refresh token. SO i think it's worth bringing as issue and getting it addressed.

Environment: AWS Cognito as OIDC Provider.

Issue 1 - Retention of Refresh Token in OIDCClient:
The OIDCClient is not retaining the existing refresh token after its initial use to refresh the access token. This poses a problem, especially in scenarios where OIDC providers might have refresh token rotation policies that allow reusing the existing refresh token until it expires. In the case of AWS Cognito, which I'm using as the OIDC Provider, there is no provision to return the refresh token along with the renewed access token and ID Token during the refresh process. This results in a disrupted flow after the first refresh because the OIDCClient is not preserving the original refresh token. I researched on stackoverflow and other recomandations that during access token renewal, we will not get back refresh token. so in this api the refresh token is getting overwritten as blank. I was able to resolve it as an example below, there could be other ways too, but the refresh token has to be retained till user logout or it expires.

ex:,
private async handleTokenResult( tokenResult: TokenResponse, authParams: AuthRequestOptions,
finalOptions: IPlusAuthClientOptions ){
...
....
...
if(tokenResult.refresh_token){
return {
authParams,
user,
...tokenResult,
id_token: parsedIDToken,
id_token_raw: tokenResult.id_token,
scope: tokenResult.scope || authParams.scope,
}
}
else{
return {
authParams,
user,
...tokenResult,
refresh_token: this.refreshToken,
id_token: parsedIDToken,
id_token_raw: tokenResult.id_token,
scope: tokenResult.scope || authParams.scope,
}
}
}

Issue 2 - Validation of IDToken in Handle Token Result Method:
The "handleTokenResult" method of client.ts calls the "validateIdToken" of jose.ts to validate the ID Token both during the initial authentication and when refreshing the access token. However, it appears that the validation process is checking for a valid nonce in the ID Token. This nonce is provided by the server during authentication using login credentials such as a username or email and password. Notably, when refreshing the access token using the refresh token (and not the credentials), the server does not include the nonce in the ID Token. Therefore, during the token validation process for refresh, If it can be optional and if not present, it should not validate for a valid nonce since it is not required in this context.

ex:
export function validateIdToken( id_token: string, nonce: string, options: IPlusAuthClientOptions, refreshToken:string | undefined ) {
....
...
if (refreshToken !== undefined && nonce !== jwt.payload.nonce ) {
throw new Error( Invalid nonce in id_token: ${ jwt.payload.nonce } );
}
.....
}

It's important to mention that I've also passed the nonce in the OIDCClient constructor during initialization. However, the OIDCClient is currently considering the nonce from the server, which may lead to this inconsistency in the validation process. So it could be made optional in this validation process.

I've arrived at these conclusions based on my analysis, research, and debugging. If there are any recommended adjustments or configurations that could be made within the OIDCClient library to address these issues, I would greatly appreciate your guidance on how to overcome them. Furthermore, if these observations are indeed indicative of bugs or shortcoming within the library, I kindly request your assistance in resolving them so that it may help more user community like me.

Thank you

Possible regression concerning `response_mode`

Since upgrading to v1.1.2 (which contains the change from #6) I'm seeing the following error from some providers, including Google:

Access blocked: Authorization Error
Invalid parameter value for response_mode: 'web_message' 
Error 400: invalid_request

I've tried overriding repsonse_mode (to be query) in both the OIDCClient constructor and the loginWithPopup parameters but it appears that the hard-coded value (web_message) always takes precedence here:

response_mode: 'web_message',

Am I missing something or is this a regression? Any guidance would be appreciated. Thanks!

Silent renew with refresh token not working

Hello,

As oidc-client-js got archived, I was looking for an alternative that can be used with any provider, and I jump into your project. So I played a bit with it testing, various configurations and I have some questions:

Currently the function OIDCClient.getIdToken returns the raw idToken do you think it could be meaningful to add a way to get a parsed idToken ? Or maybe adding parseJwt to the list of exported function, in order to be able to decode it if needed ?

I tried the library with response_type="code", autoSilentRenew=true, and useRefreshToken=true. However during the silentLogin it was silently not working. After logging SILENT_RENEW_ERROR event error, I was able to get the error:

TypeError: Cannot read property 'nonce' of undefined
    at OIDCClient._callee23$ (plusauth-oidc-client.es.js:9460)
    at tryCatch (plusauth-oidc-client.es.js:4566)
    at Generator.invoke [as _invoke] (plusauth-oidc-client.es.js:4796)
    at Generator.next (plusauth-oidc-client.es.js:4621)
    at fulfilled (plusauth-oidc-client.es.js:5428)

The issue comes from the fact that in the function silentLogin calls the function handleTokenResult with the second parameter being undefined, because the variable finalState is equal to an empty object.
And then in the handleTokenResult, it tries to access nonce of undefined.

Best regards

Issuer validation

Hello,

I have some questions about the validation of the issuer.
From the documentation the issuer identifier is a case sensitive URL using the https scheme that contains scheme, host, and optionally, port number and path components and no query or fragment components.

So http://openid.net/specs/connect/1.0/issuer could be a valid issuer, but it isn't.
Also, when doing some tests locally, I use some local issuer on http://localhost:45543 for instance, but it is not a valid uri, so I had to comment locally the check.

https://github.com/PlusAuth/plusauth-oidc-client-js/blob/af8a49d4b36e916b03ab7eec1efcc6c5064ea157/src/utils/url.ts#L3-L6
https://github.com/PlusAuth/plusauth-oidc-client-js/blob/af8a49d4b36e916b03ab7eec1efcc6c5064ea157/src/client.ts#L83-L85

Best regards

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.