Reputation: 1
Please help. This error occurs when refreshAccessToken is caled from interceptor.But code excecution continues.
ERROR TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.
This is http Interceptor that calls refresh token if time has passed.
import {Injectable} from '@angular/core';
import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http';
import {Observable} from 'rxjs';
import {AuthService} from "../../../services/auth.service";
import {SharedService} from "../../../services/shared.service";
import * as moment from "moment";
@Injectable()
export class HttpInterceptorInterceptor implements HttpInterceptor {
constructor(private sharedService: SharedService, private authService: AuthService) {
}
putTokenInRequest(request: HttpRequest<any>, access_token: any): HttpRequest<any> {
return request = request.clone({
setHeaders: {
Authorization: `Bearer ${access_token}`
}
})
}
excludeRequest(request: HttpRequest<any>): boolean {
let request_to_exclude = [
"/protocol/openid-connect/token"
]
let exclude = false
for (let req of request_to_exclude) {
if (request.url.toString().includes(req)) {
exclude = true
}
}
return exclude;
}
intercept(request: HttpRequest<any>, next: HttpHandler) :any{
if (this.excludeRequest(request) != true) {
//before every request check if access token has expired
let access_token_expire_date = localStorage.getItem("access_token_expire_date")
//subtract 10 sc for safety
if (moment().isAfter(moment(access_token_expire_date).subtract(10, 's'))) {
console.log("access_token_expired")
let refreshToken = localStorage.getItem("refresh_token")
this.authService.refreshAccessToken(refreshToken).subscribe(response => {
localStorage.setItem("refresh_token", response.refresh_token)
localStorage.setItem("access_token", response.access_token)
let access_token_expire_date = moment().add(response.expires_in, 's')
let refresh_expire_date = moment().add(response.refresh_expires_in, 's')
localStorage.setItem('access_token_expire_date', access_token_expire_date.toString())
localStorage.setItem('refresh_expire_date', refresh_expire_date.toString())
return next.handle(this.putTokenInRequest(request, response.access_token))
})
} else {
//if access_token is active again.
let access_token = localStorage.getItem('access_token')
return next.handle(this.putTokenInRequest(request, access_token))
}
}
else {
//if request is excluded from interception just move on and don,t change it.
return next.handle(request);
}
}
}
service
import {Injectable} from '@angular/core';
import {HttpClient, HttpHeaders, HttpParams} from "@angular/common/http";
import {environment} from "../../environments/environment";
import {Observable} from "rxjs";
@Injectable({
providedIn: 'root'
})
export class AuthService {
keyckloakUrl
baseUrl
constructor(private http: HttpClient) {
this.keyckloakUrl = environment.keyckloakUrl;
this.baseUrl = environment.baseUrl;
}
getExccessToken(code: any): Observable<any> {
const params = new HttpParams({
fromObject: {
client_id: 'authorization_code_grant_type',
grant_type: 'authorization_code',
code: code,
redirect_uri:'http://localhost:4200/dashboard/token_redirect'
}
});
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/x-www-form-urlencoded',
})
};
return this.http.post(`${this.keyckloakUrl}/realms/master/protocol/openid-connect/token`, params.toString(),httpOptions);
}
// logout():Observable<any>{
// return this.http.get(` http://localhost:8088/auth/realms/master/protocol/openid-connect/logout?redirect_uri=http://localhost:4200`);
// }
refreshAccessToken(refreshToken:any):Observable<any>{
// const params = new HttpParams({
// fromObject: {
// client_id: 'authorization_code_grant_type',
// grant_type: 'refresh_token',
// refresh_token: refreshToken,
// }
// });
// const httpOptions = {
// headers: new HttpHeaders({
// 'Content-Type': 'application/x-www-form-urlencoded',
// })
// };
let body = new URLSearchParams();
body.set('client_id', 'authorization_code_grant_type');
body.set('grant_type', 'refresh_token');
body.set('refresh_token', refreshToken);
let options = {
headers: new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
};
debugger
return this.http.post<any>(`${this.keyckloakUrl}/realms/master/protocol/openid-connect/token`, body.toString(),options);
}
logout():Observable<any>{
return this.http.post(`${this.baseUrl}/logout`,{})
}
}
Upvotes: 0
Views: 414
Reputation: 569
This is what a proper interceptor
interface look like according to Angular official documentation
interface HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>
}
You're modifying the return type for intercept
to any
and lost all your types safety
.
intercept(request: HttpRequest<any>, next: HttpHandler) :any
If you didn't do that, any decent code editor would highlight the problem for you.
And if you just take a look at this code block:
if (moment().isAfter(moment(access_token_expire_date).subtract(10, 's'))) {
console.log("access_token_expired")
let refreshToken = localStorage.getItem("refresh_token")
this.authService.refreshAccessToken(refreshToken).subscribe(response => {
localStorage.setItem("refresh_token", response.refresh_token)
localStorage.setItem("access_token", response.access_token)
let access_token_expire_date = moment().add(response.expires_in, 's')
let refresh_expire_date = moment().add(response.refresh_expires_in, 's')
localStorage.setItem('access_token_expire_date', access_token_expire_date.toString())
localStorage.setItem('refresh_expire_date', refresh_expire_date.toString())
return next.handle(this.putTokenInRequest(request, response.access_token))
})
You're not returning anything for the intercept
function, the return next.handle(this.putTokenInRequest(request, response.access_token))
is inside the callback for your subscribe
, therefor what you're returning is basically void
or undefined
So all you have to do is return the stream
instead:
...
let refreshToken = localStorage.getItem('refresh_token');
return this.authService.refreshAccessToken(refreshToken).pipe(
map((response) => {
localStorage.setItem('refresh_token', response.refresh_token);
localStorage.setItem('access_token', response.access_token);
let access_token_expire_date = moment().add(response.expires_in, 's');
let refresh_expire_date = moment().add(
response.refresh_expires_in,
's'
);
localStorage.setItem(
'access_token_expire_date',
access_token_expire_date.toString()
);
localStorage.setItem(
'refresh_expire_date',
refresh_expire_date.toString()
);
return next.handle(
this.putTokenInRequest(request, response.access_token)
);
})
);
Upvotes: 1