Skip to content

Commit 5abcd07

Browse files
Merge pull request #770 from Varada-Schneider/master
There is no explicit way to revoke an access token when the user logs out
2 parents 5dd15e1 + c799ead commit 5abcd07

File tree

4 files changed

+83
-4
lines changed

4 files changed

+83
-4
lines changed

projects/lib/src/auth.config.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ export class AuthConfig {
6464
*/
6565
public tokenEndpoint?: string = null;
6666

67+
/**
68+
* Url of the revocation endpoint as defined by OpenId Connect and OAuth 2.
69+
*/
70+
public revocationEndpoint?: string = null;
71+
6772
/**
6873
* Names of known parameters sent out in the TokenResponse. https://tools.ietf.org/html/rfc6749#section-5.1
6974
*/

projects/lib/src/events.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ export type EventType =
2121
| 'session_terminated'
2222
| 'logout'
2323
| 'popup_closed'
24-
| 'popup_blocked';
24+
| 'popup_blocked'
25+
| 'token_revoke_error';
2526

2627
export abstract class OAuthEvent {
2728
constructor(readonly type: EventType) {}

projects/lib/src/oauth-service.ts

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,7 @@ export class OAuthService extends AuthConfig implements OnDestroy {
523523

524524
this.discoveryDocumentLoaded = true;
525525
this.discoveryDocumentLoadedSubject.next(doc);
526+
this.revocationEndpoint = doc.revocation_endpoint;
526527

527528
if (this.sessionChecksEnabled) {
528529
this.restartSessionChecksIfStillLoggedIn();
@@ -625,6 +626,14 @@ export class OAuthService extends AuthConfig implements OnDestroy {
625626
);
626627
}
627628

629+
errors = this.validateUrlFromDiscoveryDocument(doc.revocation_endpoint);
630+
if (errors.length > 0) {
631+
this.logger.error(
632+
'error validating revocation_endpoint in discovery document',
633+
errors
634+
);
635+
}
636+
628637
errors = this.validateUrlFromDiscoveryDocument(doc.userinfo_endpoint);
629638
if (errors.length > 0) {
630639
this.logger.error(
@@ -804,7 +813,8 @@ export class OAuthService extends AuthConfig implements OnDestroy {
804813
this.storeAccessTokenResponse(
805814
tokenResponse.access_token,
806815
tokenResponse.refresh_token,
807-
tokenResponse.expires_in,
816+
tokenResponse.expires_in ||
817+
this.fallbackAccessTokenExpirationTimeInSec,
808818
tokenResponse.scope,
809819
this.extractRecognizedCustomParameters(tokenResponse)
810820
);
@@ -890,7 +900,8 @@ export class OAuthService extends AuthConfig implements OnDestroy {
890900
this.storeAccessTokenResponse(
891901
tokenResponse.access_token,
892902
tokenResponse.refresh_token,
893-
tokenResponse.expires_in,
903+
tokenResponse.expires_in ||
904+
this.fallbackAccessTokenExpirationTimeInSec,
894905
tokenResponse.scope,
895906
this.extractRecognizedCustomParameters(tokenResponse)
896907
);
@@ -1729,7 +1740,8 @@ export class OAuthService extends AuthConfig implements OnDestroy {
17291740
this.storeAccessTokenResponse(
17301741
tokenResponse.access_token,
17311742
tokenResponse.refresh_token,
1732-
tokenResponse.expires_in,
1743+
tokenResponse.expires_in ||
1744+
this.fallbackAccessTokenExpirationTimeInSec,
17331745
tokenResponse.scope,
17341746
this.extractRecognizedCustomParameters(tokenResponse)
17351747
);
@@ -2538,4 +2550,64 @@ export class OAuthService extends AuthConfig implements OnDestroy {
25382550
});
25392551
return foundParameters;
25402552
}
2553+
2554+
/**
2555+
* Revokes the auth token to secure the vulnarability
2556+
* of the token issued allowing the authorization server to clean
2557+
* up any security credentials associated with the authorization
2558+
*/
2559+
public revokeTokenAndLogout(): Promise<any> {
2560+
let revoke_endpoint = this.revocationEndpoint;
2561+
let current_access_token = this.getAccessToken();
2562+
let params = new HttpParams()
2563+
.set('token', current_access_token)
2564+
.set('token_type_hint', 'access_token');
2565+
2566+
let headers = new HttpHeaders().set(
2567+
'Content-Type',
2568+
'application/x-www-form-urlencoded'
2569+
);
2570+
2571+
if (this.useHttpBasicAuth) {
2572+
const header = btoa(`${this.clientId}:${this.dummyClientSecret}`);
2573+
headers = headers.set('Authorization', 'Basic ' + header);
2574+
}
2575+
2576+
if (!this.useHttpBasicAuth) {
2577+
params = params.set('client_id', this.clientId);
2578+
}
2579+
2580+
if (!this.useHttpBasicAuth && this.dummyClientSecret) {
2581+
params = params.set('client_secret', this.dummyClientSecret);
2582+
}
2583+
2584+
if (this.customQueryParams) {
2585+
for (const key of Object.getOwnPropertyNames(this.customQueryParams)) {
2586+
params = params.set(key, this.customQueryParams[key]);
2587+
}
2588+
}
2589+
2590+
return new Promise((resolve, reject) => {
2591+
if (current_access_token) {
2592+
this.http
2593+
.post<any>(revoke_endpoint, params, { headers })
2594+
.subscribe(
2595+
res => {
2596+
this.logOut();
2597+
resolve(res);
2598+
this.logger.info('Token successfully revoked');
2599+
},
2600+
err => {
2601+
this.logger.error('Error revoking token', err);
2602+
this.eventsSubject.next(
2603+
new OAuthErrorEvent('token_revoke_error', err)
2604+
);
2605+
reject(err);
2606+
}
2607+
);
2608+
} else {
2609+
this.logger.warn('User not logged in to revoke token.');
2610+
}
2611+
});
2612+
}
25412613
}

projects/lib/src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,4 +187,5 @@ export interface OidcDiscoveryDoc {
187187
claims_parameter_supported: boolean;
188188
service_documentation: string;
189189
ui_locales_supported: string[];
190+
revocation_endpoint: string;
190191
}

0 commit comments

Comments
 (0)