Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions projects/lib/src/auth.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ export class AuthConfig {
*/
public tokenEndpoint?: string = null;

/**
* Url of the revocation endpoint as defined by OpenId Connect and OAuth 2.
*/
public revocationEndpoint?: string = null;

/**
* Names of known parameters sent out in the TokenResponse. https://tools.ietf.org/html/rfc6749#section-5.1
*/
Expand Down
3 changes: 2 additions & 1 deletion projects/lib/src/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ export type EventType =
| 'session_terminated'
| 'logout'
| 'popup_closed'
| 'popup_blocked';
| 'popup_blocked'
| 'token_revoke_error';

export abstract class OAuthEvent {
constructor(readonly type: EventType) {}
Expand Down
78 changes: 75 additions & 3 deletions projects/lib/src/oauth-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,7 @@ export class OAuthService extends AuthConfig implements OnDestroy {

this.discoveryDocumentLoaded = true;
this.discoveryDocumentLoadedSubject.next(doc);
this.revocationEndpoint = doc.revocation_endpoint;

if (this.sessionChecksEnabled) {
this.restartSessionChecksIfStillLoggedIn();
Expand Down Expand Up @@ -625,6 +626,14 @@ export class OAuthService extends AuthConfig implements OnDestroy {
);
}

errors = this.validateUrlFromDiscoveryDocument(doc.revocation_endpoint);
if (errors.length > 0) {
this.logger.error(
'error validating revocation_endpoint in discovery document',
errors
);
}

errors = this.validateUrlFromDiscoveryDocument(doc.userinfo_endpoint);
if (errors.length > 0) {
this.logger.error(
Expand Down Expand Up @@ -804,7 +813,8 @@ export class OAuthService extends AuthConfig implements OnDestroy {
this.storeAccessTokenResponse(
tokenResponse.access_token,
tokenResponse.refresh_token,
tokenResponse.expires_in,
tokenResponse.expires_in ||
this.fallbackAccessTokenExpirationTimeInSec,
tokenResponse.scope,
this.extractRecognizedCustomParameters(tokenResponse)
);
Expand Down Expand Up @@ -890,7 +900,8 @@ export class OAuthService extends AuthConfig implements OnDestroy {
this.storeAccessTokenResponse(
tokenResponse.access_token,
tokenResponse.refresh_token,
tokenResponse.expires_in,
tokenResponse.expires_in ||
this.fallbackAccessTokenExpirationTimeInSec,
tokenResponse.scope,
this.extractRecognizedCustomParameters(tokenResponse)
);
Expand Down Expand Up @@ -1729,7 +1740,8 @@ export class OAuthService extends AuthConfig implements OnDestroy {
this.storeAccessTokenResponse(
tokenResponse.access_token,
tokenResponse.refresh_token,
tokenResponse.expires_in,
tokenResponse.expires_in ||
this.fallbackAccessTokenExpirationTimeInSec,
tokenResponse.scope,
this.extractRecognizedCustomParameters(tokenResponse)
);
Expand Down Expand Up @@ -2538,4 +2550,64 @@ export class OAuthService extends AuthConfig implements OnDestroy {
});
return foundParameters;
}

/**
* Revokes the auth token to secure the vulnarability
* of the token issued allowing the authorization server to clean
* up any security credentials associated with the authorization
*/
public revokeTokenAndLogout(): Promise<any> {
let revoke_endpoint = this.revocationEndpoint;
let current_access_token = this.getAccessToken();
let params = new HttpParams()
.set('token', current_access_token)
.set('token_type_hint', 'access_token');

let headers = new HttpHeaders().set(
'Content-Type',
'application/x-www-form-urlencoded'
);

if (this.useHttpBasicAuth) {
const header = btoa(`${this.clientId}:${this.dummyClientSecret}`);
headers = headers.set('Authorization', 'Basic ' + header);
}

if (!this.useHttpBasicAuth) {
params = params.set('client_id', this.clientId);
}

if (!this.useHttpBasicAuth && this.dummyClientSecret) {
params = params.set('client_secret', this.dummyClientSecret);
}

if (this.customQueryParams) {
for (const key of Object.getOwnPropertyNames(this.customQueryParams)) {
params = params.set(key, this.customQueryParams[key]);
}
}

return new Promise((resolve, reject) => {
if (current_access_token) {
this.http
.post<any>(revoke_endpoint, params, { headers })
.subscribe(
res => {
this.logOut();
resolve(res);
this.logger.info('Token successfully revoked');
},
err => {
this.logger.error('Error revoking token', err);
this.eventsSubject.next(
new OAuthErrorEvent('token_revoke_error', err)
);
reject(err);
}
);
} else {
this.logger.warn('User not logged in to revoke token.');
}
});
}
}
1 change: 1 addition & 0 deletions projects/lib/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,4 +187,5 @@ export interface OidcDiscoveryDoc {
claims_parameter_supported: boolean;
service_documentation: string;
ui_locales_supported: string[];
revocation_endpoint: string;
}