From e6eec8e89217b87fc4387c8ea3b5c6e9dc8ac24b Mon Sep 17 00:00:00 2001 From: Josh Fyne Date: Wed, 18 Sep 2019 11:42:56 -0400 Subject: [PATCH 1/2] https://github.com/manfredsteyer/angular-oauth2-oidc/issues/628 Generate a code_verifier and then base64url encode it --- projects/lib/src/oauth-service.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/projects/lib/src/oauth-service.ts b/projects/lib/src/oauth-service.ts index 2b9de9dc..c354fd52 100644 --- a/projects/lib/src/oauth-service.ts +++ b/projects/lib/src/oauth-service.ts @@ -2087,7 +2087,7 @@ export class OAuthService extends AuthConfig implements OnDestroy { * This alphabet uses a-z A-Z 0-9 _- symbols. * Symbols order was changed for better gzip compression. */ - const url = 'Uint8ArdomValuesObj012345679BCDEFGHIJKLMNPQRSTWXYZ_cfghkpqvwxyz-'; + const unreserved = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~'; let size = 45; let id = ''; @@ -2095,15 +2095,15 @@ export class OAuthService extends AuthConfig implements OnDestroy { if (crypto) { const bytes = crypto.getRandomValues(new Uint8Array(size)); while (0 < size--) { - id += url[bytes[size] & 63]; + id += unreserved[bytes[size] & 63]; } } else { while (0 < size--) { - id += url[Math.random() * 64 | 0]; + id += unreserved[Math.random() * 64 | 0]; } } - resolve(id); + resolve(base64UrlEncode(id)); }); } From a906a6b355647717b1add3f1883d9b06ab17345f Mon Sep 17 00:00:00 2001 From: Josh Fyne Date: Wed, 18 Sep 2019 12:27:02 -0400 Subject: [PATCH 2/2] Fixing the random string generation. --- projects/lib/src/oauth-service.ts | 42 +++++++++++++++---------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/projects/lib/src/oauth-service.ts b/projects/lib/src/oauth-service.ts index c354fd52..bc7e1d71 100644 --- a/projects/lib/src/oauth-service.ts +++ b/projects/lib/src/oauth-service.ts @@ -778,8 +778,7 @@ export class OAuthService extends AuthConfig implements OnDestroy { tap(result => this.storeIdToken(result)), map(_ => tokenResponse) ); - } - else { + } else { return of(tokenResponse); } })) @@ -1264,7 +1263,7 @@ export class OAuthService extends AuthConfig implements OnDestroy { } return url; - + } initImplicitFlowInternal( @@ -1374,8 +1373,7 @@ export class OAuthService extends AuthConfig implements OnDestroy { public tryLogin(options: LoginOptions = null): Promise { if (this.config.responseType === 'code') { return this.tryLoginCodeFlow().then(_ => true); - } - else { + } else { return this.tryLoginImplicitFlow(options); } } @@ -1397,7 +1395,7 @@ export class OAuthService extends AuthConfig implements OnDestroy { public tryLoginCodeFlow(): Promise { - const parts = this.parseQueryString(window.location.search) + const parts = this.parseQueryString(window.location.search); const code = parts['code']; const state = parts['state']; @@ -1503,32 +1501,32 @@ export class OAuthService extends AuthConfig implements OnDestroy { (tokenResponse) => { this.debug('refresh tokenResponse', tokenResponse); this.storeAccessTokenResponse( - tokenResponse.access_token, - tokenResponse.refresh_token, + tokenResponse.access_token, + tokenResponse.refresh_token, tokenResponse.expires_in, tokenResponse.scope); if (this.oidc && tokenResponse.id_token) { - this.processIdToken(tokenResponse.id_token, tokenResponse.access_token). + this.processIdToken(tokenResponse.id_token, tokenResponse.access_token). then(result => { this.storeIdToken(result); - + this.eventsSubject.next(new OAuthSuccessEvent('token_received')); this.eventsSubject.next(new OAuthSuccessEvent('token_refreshed')); - + resolve(tokenResponse); }) .catch(reason => { this.eventsSubject.next(new OAuthErrorEvent('token_validation_error', reason)); console.error('Error validating tokens'); console.error(reason); - + reject(reason); }); } else { this.eventsSubject.next(new OAuthSuccessEvent('token_received')); this.eventsSubject.next(new OAuthSuccessEvent('token_refreshed')); - + resolve(tokenResponse); } }, @@ -1688,7 +1686,7 @@ export class OAuthService extends AuthConfig implements OnDestroy { ): boolean { const savedNonce = this._storage.getItem('nonce'); if (savedNonce !== nonceInState) { - + const err = 'Validating access_token failed, wrong state/nonce.'; console.error(err, savedNonce, nonceInState); return false; @@ -2084,8 +2082,10 @@ export class OAuthService extends AuthConfig implements OnDestroy { } /* - * This alphabet uses a-z A-Z 0-9 _- symbols. - * Symbols order was changed for better gzip compression. + * This alphabet is from: + * https://tools.ietf.org/html/rfc7636#section-4.1 + * + * [A-Z] / [a-z] / [0-9] / "-" / "." / "_" / "~" */ const unreserved = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~'; let size = 45; @@ -2093,13 +2093,13 @@ export class OAuthService extends AuthConfig implements OnDestroy { const crypto = self.crypto || self['msCrypto']; if (crypto) { - const bytes = crypto.getRandomValues(new Uint8Array(size)); - while (0 < size--) { - id += unreserved[bytes[size] & 63]; - } + let bytes = new Uint8Array(size); + crypto.getRandomValues(bytes); + bytes = bytes.map(x => unreserved.charCodeAt(x % unreserved.length)); + id = String.fromCharCode.apply(null, bytes); } else { while (0 < size--) { - id += unreserved[Math.random() * 64 | 0]; + id += unreserved[Math.random() * unreserved.length | 0]; } }