Skip to content

Commit

Permalink
feat(token-revocation): also revoke refresh_token
Browse files Browse the repository at this point in the history
  • Loading branch information
manfredsteyer committed Mar 28, 2020
1 parent 5abcd07 commit 429ed2c
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 20 deletions.
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,15 @@ Please note, that this dependency is not needed for the **code flow**, which is
### Breaking change in 9.1.0

The use of `encodeURIComponent` on the argument passed to `initImplicitFlow` and its Code Flow counterparts was mandatory before this version.

Since that was considered a _bug_, the need to do so was removed.
Now the reverse is true **if you're upgrading from before 9.0.0**: you need to remove any call to encode URI components in your own application, as the library will now do it for you.

## Tested Environment

Successfully tested with **Angular 9** and its Router, PathLocationStrategy as well as HashLocationStrategy and CommonJS-Bundling via webpack. At server side we've used IdentityServer (.NET / .NET Core) and Redhat's Keycloak (Java).

**Angular 9**: Use 9.x versions of this library (should also work with older Angular versions!).
**Angular 9**: Use 9.x versions of this library (**should also work with older Angular versions!**).

**Angular 8**: Use 8.x versions of this library.

Expand Down Expand Up @@ -90,6 +91,7 @@ Successfully tested with **Angular 9** and its Router, PathLocationStrategy as w
- Hook for further custom validations
- Single-Sign-Out by redirecting to the auth-server's logout-endpoint
- Tested with all modern browsers and IE
- Token Revocation according to [RFC 7009](https://tools.ietf.org/html/rfc7009#section-2.2)
## Sample-Auth-Server
Expand Down Expand Up @@ -204,6 +206,20 @@ this.oauthService.configure(authCodeFlowConfig);
this.oauthService.loadDiscoveryDocumentAndTryLogin();
```
### Logging out
The logOut method clears the used token store (by default ``sessionStorage``) and forwards the user to the auth servers logout endpoint if one was configured (manually or via the discovery document).
```typescript
this.oauthService.logOut();
```
If you want to revoke the existing access token and the existing refresh token before logging out, use the following method:
```typescript
this.oauthService.revokeTokenAndLogout();
```
### Skipping the Login Form
If you don't want to display a login form that tells the user that they are redirected to the identity server, you can use the convenience function `this.oauthService.loadDiscoveryDocumentAndLogin();` instead of `this.oauthService.loadDiscoveryDocumentAndTryLogin();` when setting up the library.
Expand Down
46 changes: 33 additions & 13 deletions projects/lib/src/oauth-service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Injectable, NgZone, Optional, OnDestroy, Inject } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { Observable, Subject, Subscription, of, race, from } from 'rxjs';
import { Observable, Subject, Subscription, of, race, from, combineLatest } from 'rxjs';
import {
filter,
delay,
Expand Down Expand Up @@ -2557,11 +2557,15 @@ export class OAuthService extends AuthConfig implements OnDestroy {
* 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 revokeEndpoint = this.revocationEndpoint;
let accessToken = this.getAccessToken();
let refreshToken = this.getRefreshToken();

if (!accessToken) {
return;
}

let params = new HttpParams();

let headers = new HttpHeaders().set(
'Content-Type',
Expand All @@ -2588,10 +2592,29 @@ export class OAuthService extends AuthConfig implements OnDestroy {
}

return new Promise((resolve, reject) => {
if (current_access_token) {
this.http
.post<any>(revoke_endpoint, params, { headers })
.subscribe(
let revokeAccessToken: Observable<void>;
let revokeRefreshToken: Observable<void>;

if (accessToken) {
let revokationParams = params
.set('token', accessToken)
.set('token_type_hint', 'access_token');
revokeAccessToken = this.http.post<void>(revokeEndpoint, revokationParams, { headers });
} else {
revokeAccessToken = of(null);
}

if (refreshToken) {
let revokationParams = params
.set('token', refreshToken)
.set('token_type_hint', 'refresh_token');
revokeRefreshToken = this.http.post<void>(revokeEndpoint, revokationParams, { headers });
} else {
revokeRefreshToken = of(null);
}

combineLatest([revokeAccessToken, revokeRefreshToken])
.subscribe(
res => {
this.logOut();
resolve(res);
Expand All @@ -2605,9 +2628,6 @@ export class OAuthService extends AuthConfig implements OnDestroy {
reject(err);
}
);
} else {
this.logger.warn('User not logged in to revoke token.');
}
});
}
}
10 changes: 8 additions & 2 deletions projects/sample/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,16 @@ export class AppComponent {

private configureCodeFlow() {
this.oauthService.configure(authCodeFlowConfig);
this.oauthService.loadDiscoveryDocumentAndTryLogin();
this.oauthService.loadDiscoveryDocumentAndTryLogin().then(_ => {
if (useHash) {
this.router.navigate(['/']);
}
});

// Optional
// this.oauthService.setupAutomaticSilentRefresh();
this.oauthService.setupAutomaticSilentRefresh();


}

private configureImplicitFlow() {
Expand Down
4 changes: 3 additions & 1 deletion projects/sample/src/app/auth-code-flow.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ export const authCodeFlowConfig: AuthConfig = {

sessionChecksEnabled: true,

timeoutFactor: 0.01
timeoutFactor: 0.01,
// disablePKCI: true,

clearHashAfterLogin: false,
};
3 changes: 2 additions & 1 deletion projects/sample/src/app/home/home.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ export class HomeComponent implements OnInit {
}

logout() {
this.oauthService.logOut();
// this.oauthService.logOut();
this.oauthService.revokeTokenAndLogout();
}

loadUserProfile(): void {
Expand Down
4 changes: 2 additions & 2 deletions projects/sample/src/flags.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Use HashLocationStrategy for routing?
export const useHash = false;
export const useHash = true;

// Set this to true, to use silent refresh; otherwise the example
// uses the refresh_token via an AJAX coll to get new tokens.
export const useSilentRefreshForCodeFlow = true;
export const useSilentRefreshForCodeFlow = false;

0 comments on commit 429ed2c

Please sign in to comment.