Ivan Arantes:
Here in the company we have an angular 4.3 app and I've been working with OAuth and JWT authentication + Spring Boot/Security backend. The authentication is working fine, but i have problems when i want to renew the Token after it expires using 'refresh_token'.
Firefox and Chrome are not saving the Response cookies with the refreshToken, so when i do the Ajax post method to receive a new accessToken, the cookie is not being sent together and then i get the error message at the backend "Cannot convert access token to JSON" which i believe it's because the token is null.
I have already searched for others questions but none of them helped me :(
It works fine on IE 11.
URIConstantes.LOGIN = 'http://localhost:9090/oauth/token';
Here is the code for login request that works but do not store cookie:
login(formGroup: FormGroup): Observable
{
const headers = new Headers();
headers.append('Authorization', 'Basic xxxxxxxxxxxx')
headers.append('Content-Type', 'application/x-www-form-urlencoded');
let user = formGroup.get('username').value;
let password = formGroup.get('password').value;
const body = 'username=' + user + '&password=' + password + '&grant_type=password';
return this.http.post(URIConstantes.LOGIN, body, {headers: headers})
.map((response: Response) => {
let token = response.json()['access_token'];
if (token != null) {
this.token = token;
this.saveTokenToLocalStorage(token);
return true;
} else {
// return false to indicate failed login
return false;
}
});
}
Generate new access token method:
obterNovoAccessToken(): Observable {
const headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded')
headers.append('Authorization', 'Basic xxxxxxxxxxxxx')
const body = 'grant_type=refresh_token';
return this.http.post(URIConstantes.LOGIN, body, { headers, withCredentials: true })
.map(response => {
console.log(response);
this.armazenarToken(response.json()['access_token']);
console.log('Novo access token criado!');
}).catch(
response => {
console.error('Erro ao renovar token.', response.json());
return Promise.resolve(null);
});
}
RefreshTokenPostProcessor class:
@ControllerAdvice
public class RefreshTokenPostProcessor implements ResponseBodyAdvice{
@Override
public boolean supports(MethodParameter returnType, Class extends HttpMessageConverter>> converterType) {
return returnType.getMethod().getName().equals("postAccessToken");
}
@Override
public OAuth2AccessToken beforeBodyWrite(OAuth2AccessToken body, MethodParameter returnType,
MediaType selectedContentType, Class extends HttpMessageConverter>> selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response) {
HttpServletRequest req = ((ServletServerHttpRequest) request).getServletRequest();
HttpServletResponse resp = ((ServletServerHttpResponse) response).getServletResponse();
DefaultOAuth2AccessToken token = (DefaultOAuth2AccessToken) body;
String refreshToken = body.getRefreshToken().getValue();
adicionarRefreshTokenNoCookie(refreshToken, req, resp);
removerRefreshTokenDoBody(token);
return body;
}
private void removerRefreshTokenDoBody(DefaultOAuth2AccessToken token) {
token.setRefreshToken(null);
}
//add token on cookie response
private void adicionarRefreshTokenNoCookie(String refreshToken, HttpServletRequest req, HttpServletResponse resp) {
Cookie refreshTokenCookie = new Cookie("refreshToken", refreshToken);
refreshTokenCookie.setHttpOnly(true);
refreshTokenCookie.setSecure(false);
refreshTokenCookie.setPath(req.getContextPath() + "/oauth/token");
refreshTokenCookie.setMaxAge(2592000);
resp.addCookie(refreshTokenCookie);
}
}
Response cookie after login:
refreshToken:
value: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
expires: 2017-10-01T21:03:13.000Z,
path: '/oauth/token',
httpOnly: true
What I've already tried without success:
- Added 'Domain: Localhost' on response header.
- Checked if the origin-request matches CORS 'Access-Control-Allow-Origin'
Thank you very much!
Posted in S.E.F
via StackOverflow & StackExchange Atomic Web Robots
This Question have been answered
HERE