Skip to content

Commit aa3ea01

Browse files
Merge pull request #35 from jeroenheijmans/34-iframe-silent-refresh-for-code-flow
Workaround for iframe based silent refresh for code flow
2 parents 3b13ef9 + eb308d0 commit aa3ea01

File tree

3 files changed

+20
-19
lines changed

3 files changed

+20
-19
lines changed

src/app/core/auth-config.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export const authConfig: AuthConfig = {
66
responseType: 'code',
77
redirectUri: window.location.origin + '/index.html',
88
silentRefreshRedirectUri: window.location.origin + '/silent-refresh.html',
9-
scope: 'openid profile email offline_access api',
9+
scope: 'openid profile email api', // Ask offline_access to support refresh token refreshes
1010
silentRefreshTimeout: 5000, // For faster testing
1111
timeoutFactor: 0.25, // For faster testing
1212
sessionChecksEnabled: true,

src/app/core/auth.service.ts

+6-17
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Injectable } from '@angular/core';
22
import { Router } from '@angular/router';
3-
import { OAuthErrorEvent, OAuthService } from 'angular-oauth2-oidc';
3+
import { OAuthErrorEvent, OAuthService, OAuthEvent, TokenResponse } from 'angular-oauth2-oidc';
44
import { BehaviorSubject, combineLatest, Observable, ReplaySubject } from 'rxjs';
55
import { filter, map } from 'rxjs/operators';
66

@@ -76,10 +76,6 @@ export class AuthService {
7676
.pipe(filter(e => ['session_terminated', 'session_error'].includes(e.type)))
7777
.subscribe(e => this.navigateToLoginPage());
7878

79-
// This *does* work with v9.0.0 as it detects code+pkce flow and sets up
80-
// refreshToken() calls that require offline_access, instead of actually
81-
// calling silentRefresh, which would fail because of this issue:
82-
// https://github.com/manfredsteyer/angular-oauth2-oidc/issues/600
8379
this.oauthService.setupAutomaticSilentRefresh();
8480
}
8581

@@ -110,7 +106,7 @@ export class AuthService {
110106
// 2. SILENT LOGIN:
111107
// Try to log in via a refresh because then we can prevent
112108
// needing to redirect the user:
113-
return this.startWithRefresh()
109+
return this.tryNoPromptRefresh()
114110
.then(() => Promise.resolve())
115111
.catch(result => {
116112
// Subset of situations from https://openid.net/specs/openid-connect-core-1_0.html#AuthError
@@ -164,15 +160,14 @@ export class AuthService {
164160
.catch(() => this.isDoneLoadingSubject$.next(true));
165161
}
166162

167-
private startWithRefresh() {
163+
private tryNoPromptRefresh(): Promise<TokenResponse | OAuthEvent> {
168164
if (this.oauthService.getRefreshToken()) {
169165
console.log('Found a refresh token, trying to use it.');
170166
return this.oauthService.refreshToken();
171167
}
172168

173-
// No silent refresh via iframe is supported for code flow yet.
174-
// See also: https://github.com/manfredsteyer/angular-oauth2-oidc/issues/600
175-
return Promise.reject();
169+
console.log('Found no refresh token, trying iframe based refresh');
170+
return this.oauthService.silentRefresh();
176171
}
177172

178173
public login(targetUrl?: string) {
@@ -182,13 +177,7 @@ export class AuthService {
182177
}
183178

184179
public logout() { this.oauthService.logOut(); }
185-
public refresh() {
186-
// Silent refresh via iframe is not supported (yet?) for the code+pkce flow.
187-
// See also: https://github.com/manfredsteyer/angular-oauth2-oidc/issues/600
188-
// this.oauthService.silentRefresh();
189-
// So for now we do this instead:
190-
this.oauthService.refreshToken();
191-
}
180+
public refresh() { this.tryNoPromptRefresh(); }
192181
public hasValidToken() { return this.oauthService.hasValidAccessToken(); }
193182

194183
// These normally won't be exposed from a service like this, but

src/silent-refresh.html

+13-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,19 @@
22
<html>
33
<body>
44
<script>
5-
parent.postMessage(location.hash, location.origin);
5+
console.log("The silent-refresh.html file was loaded and now posting to the parent.");
6+
7+
// For code flow with IdentityServer4 the redirect will contain the new code in
8+
// the location.search. However, the oauth library expects it in the hash fragment
9+
// so we need to "fake" that.
10+
//
11+
// We can't just set `silentRefreshMessagePrefix` on AuthConfig, because the normal
12+
// redirect after interactive login *does* use the hash fragment, so we'd break that.
13+
//
14+
// See also: https://github.com/manfredsteyer/angular-oauth2-oidc/issues/777
15+
const fakeHashFragment = location.search.replace(/^\?/, "#");
16+
17+
parent.postMessage(fakeHashFragment, location.origin);
618
</script>
719
</body>
820
</html>

0 commit comments

Comments
 (0)