I'm trying to set up a refresh token strategy to refresh JWT in angular with GraphQL and apollo client when my request returns a 401. Error detection works, but I can't get to the service injection. Angular returns me an error in the console about circular dependency detection
ERROR Error: NG0200: Circular dependency in DI detected for AuthService
and I have no idea how to solve it. There is screen of the error Screen of the error
This is my graphql.module.ts:
import { NgModule } from '@angular/core';
import { APOLLO_OPTIONS } from 'apollo-angular';
import { ApolloLink, InMemoryCache } from '@apollo/client/core';
import { HttpLink } from 'apollo-angular/http';
import { environment } from 'src/environments/environment';
import { setContext } from '@apollo/client/link/context';
import { onError } from "@apollo/client/link/error";
import { AuthService } from './services/auth/auth.service';
const uri = environment.apiUrl + 'graphql'; // <-- add the URL of the GraphQL server here
export function createApollo(httpLink: HttpLink, authService: AuthService) {
const basic = setContext((operation, context) => ({
headers: {
Accept: 'charset=utf-8'
}
}));
const error = onError(({ graphQLErrors, networkError, response, operation }) => {
if (graphQLErrors[0].extensions.exception.status == 401) {
authService.refreshToken().subscribe(res => {
console.log(res)
})
}
})
const auth = setContext((operation, context) => {
const token = localStorage.getItem('JWT_TOKEN');
if (token === null) {
return {};
} else {
return {
headers: {
Authorization: `Bearer ${token}`
}
};
}
});
const link = ApolloLink.from([basic, error, auth, httpLink.create({ uri })]);
const cache = new InMemoryCache();
return {
link,
cache
}
}
@NgModule({
providers: [
{
provide: APOLLO_OPTIONS,
useFactory: createApollo,
deps: [HttpLink, AuthService],
},
],
})
export class GraphQLModule { }
And this is my auth.service.ts
import { Injectable } from '@angular/core';
import { Apollo } from 'apollo-angular';
import { LoginResponse, LOGIN_MUTATION, MeQueryResponse, ME_QUERY, RefreshTokenResponse, REFRESH_TOKEN_MUTATION, User } from 'src/app/models/graphql';
import { tap } from 'rxjs/operators';
import { Tokens } from 'src/app/models/tokens';
import { Storage } from '@ionic/storage';
import { Router } from '@angular/router';
import { BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class AuthService {
private readonly JWT_TOKEN = 'JWT_TOKEN';
private readonly REFRESH_TOKEN = 'REFRESH_TOKEN';
private loggedUser: string;
USER = new BehaviorSubject<User>(null);
isAdmin!: boolean;
constructor(private apollo: Apollo, private router: Router, private storage: Storage) { }
login(email: string, password: string) {
return this.apollo.mutate<LoginResponse>({
mutation: LOGIN_MUTATION,
variables: {
email,
password
}
})
.pipe(
tap(tokens => this.doLoginUser(email, tokens.data.login)),
);
}
getMe() {
return this.apollo.query<MeQueryResponse>({
query: ME_QUERY
})
.pipe(
tap(user => this.doSaveUser(user.data.me))
)
}
isLoggedIn() {
return !!this.getJwtToken();
}
refreshToken() {
return this.apollo.mutate<RefreshTokenResponse>({
mutation: REFRESH_TOKEN_MUTATION
})
.pipe
(
tap(tokens => this.storeJwtToken(tokens.data.returnToken.token))
)
}
getJwtToken() {
return localStorage.getItem(this.JWT_TOKEN);
}
getRefreshToken() {
return localStorage.getItem(this.REFRESH_TOKEN);
}
logoutUser() {
this.loggedUser = null;
this.router.navigate(["/auth/login"])
this.removeTokens();
}
/* doLoadUser() {
this.storage.get('USER').then(res => {
if (res) {
this.USER.next(res);
this.isAdmin = res.isAdmin;
}
})
} */
user() {
return this.USER;
}
private doSaveUser(user: User) {
this.USER.next(user);
this.isAdmin = user.isAdmin;
this.storage.set('USER', user);
}
private doLoginUser(email: string, tokens: Tokens) {
this.loggedUser = email;
this.storeTokens(tokens);
}
private storeJwtToken(jwt: string) {
localStorage.setItem(this.JWT_TOKEN, jwt);
}
private storeTokens(tokens: Tokens) {
localStorage.setItem(this.JWT_TOKEN, tokens.token);
localStorage.setItem(this.REFRESH_TOKEN, tokens.refreshToken);
}
private removeTokens() {
localStorage.removeItem(this.JWT_TOKEN);
localStorage.removeItem(this.REFRESH_TOKEN);
}
}
Any ideas? Any help would be greatly appreciated