I've integrated the Keycloak adapter in my Spring Boot application, as described in the documentation. The workflow is working. Initially, I was using the session token-store in the properties, but I want to get rid of that and be stateless. So, I changed the option to a cookie token-store.
I can see that my Spring Boot app does send the Keycloak access token in the KEYCLOAK_ADAPTER_STATE
cookie (screenshot). As expected, it's flagged as an HTTP cookie.
However, further angular http requests do not send that cookie when I query my back-end, even if I turn on the withCredentials option in the query.
let options : RequestOptions = new RequestOptions();
options.withCredentials = true;
this.http.get('myservice', options)
How can I use that token in stateless http calls ?
Many thanks !
As explained in the angular-keycloak documentation HttpClient interceptor by default will add the Authorization header in the format of: Authorization: Bearer TOKEN
for all the HTTP requests from your application to the server.
You can configure request URLs that you want to exclude from adding the HTTP Authorization header with the keycloak token in the HTTPClient interceptor configuration.
The HttpClient interceptor can be configured in the keycloak initializer function in the app-init.ts (refer the angular-keycloak documentation) as below;
import { KeycloakService } from 'keycloak-angular';
export function initializer(keycloak: KeycloakService): () => Promise<any> {
return (): Promise<any> => keycloak.init({
config: {
url: 'http://localhost:8080/auth',
realm: 'your-realm',
clientId: 'client-id'
},
initOptions: {
onLoad: 'login-required',
checkLoginIframe: false
},
enableBearerInterceptor: true,
bearerPrefix: 'Bearer',
bearerExcludedUrls: [
'/assets',
'/clients/public']
});
}
Use Interceptors:
HTTP Interception is a major feature of @angular/common/http. With interception, you declare interceptors that inspect and transform HTTP requests from your application to the server. The same interceptors may also inspect and transform the server's responses on their way back to the application. Multiple interceptors form a forward-and-backward chain of request/response handlers
import { AuthService } from '../auth.service';
@Injectable() export class AuthInterceptor implements HttpInterceptor { constructor(private auth: AuthService) {} intercept(req: HttpRequest<any>, next: HttpHandler) { // Get the auth token from the service. const authToken = this.auth.getAuthorizationToken(); // Clone the request and replace the original headers with // cloned headers, updated with the authorization. const authReq = req.clone({ headers: req.headers.set('Authorization', authToken) }); // send cloned request with header to the next handler. return next.handle(authReq); } }
...
I think you should set
options.withCredentials = true;
to any requests
import { Injectable } from '@angular/core';
import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse, HttpErrorResponse} from '@angular/common/http';
import {Router} from '@angular/router';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/do';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private router: Router) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
req = req.clone({
withCredentials: true
});
return next
.handle(req)
.do(event => {
if (event instanceof HttpResponse) {}
}, (error: any) => {
if (error instanceof HttpErrorResponse) {
if (error.status === 401) {
this.router.navigate(['/login']);
}
}
});
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With