Recently I've been working on simple web application for managing students and users. Application will be published on the internet, so it needs proper access control. I wanted to learn some new stuff, so I decided to use Angular5 with Oauth2 authentication. I didn't want to use any options as "Login with Facebook", or "Login with Google". I wanted my Spring Boot app to work as the authentication server and the resource server.
I read a little abouth Oauth2 and different flows possible, and it turns out, that preffered flow to use with web application is IMPLICIT flow.
Implicit flow uses only one token. It doesn't have a refresh token, as it could be overtaken by an attacker.
Access token has defined validity period. In other flows, where refresh token exists it is used to get another access token when the first one expires.
In theory in implicit flow user should just log again, but forcing a user to log in during active session is not an option.
There is a method called "silent token refresh", when there is invisible iframe present on a web page. When access token validity period is finishing, it automaticaly make request to authentication server for a new token with parameter "prompt=none".
In Spring default path to get Oauth2 token is:
It supports silent token refresh by default. It is very well described in documentation:
I read a little abouth Oauth2 and different flows possible, and it turns out, that preffered flow to use with web application is IMPLICIT flow.
Implicit flow uses only one token. It doesn't have a refresh token, as it could be overtaken by an attacker.
Access token has defined validity period. In other flows, where refresh token exists it is used to get another access token when the first one expires.
In theory in implicit flow user should just log again, but forcing a user to log in during active session is not an option.
There is a method called "silent token refresh", when there is invisible iframe present on a web page. When access token validity period is finishing, it automaticaly make request to authentication server for a new token with parameter "prompt=none".
In Spring default path to get Oauth2 token is:
/oauth/authorize?response_type=token&client_id=your-client-id&prompt=none
On angular5 frontend I use angular-oauth2-oidc library for authorization. It supports silent token refresh by default. It is very well described in documentation:
https://manfredsteyer.github.io/angular-oauth2-oidc/docs/additional-documentation/refreshing-a-token-(silent-refresh).html
so I will not write about it here.
so I will not write about it here.
When I tried to use that method with SpringBoot as authentication server, I discovered that it doesn't work by default. When I send request to backend for new token, DefaultTokenServices.createAccessToken method is called.
It checks if existing token is valid. When a token is valid, it just returns existing token, instead of generating new one.
It checks if existing token is valid. When a token is valid, it just returns existing token, instead of generating new one.
I was looking for any good solution on the internet, but I didn't find any, so I decided to override default behaviour of DefaultTokenServices class, to support "prompt=none" param.
Here is a code of my CustomTokenServicess class:
When my CustomTokenServices class discovers there is "prompt=none" param presents, it assumes, that app wants to silently refresh token, so it removes current token and generates new one, otherwise it just uses DefaultTokenServices functionality.
It might not be a perfect solution, but it works very well.
On my github You can find complete working applicaction with sample usage of this method:
https://github.com/aogorek/springboot-oauth2-angular2
It uses SpringBoot2, Spring Security 5, Angular5, Material Design, custom login page, and few other interesting things.
so go, clone the repository, test it, and feel free to comment. I'm curious of Your opinion about this solution. Maybe You have better idea to solve this scenario?
It might not be a perfect solution, but it works very well.
On my github You can find complete working applicaction with sample usage of this method:
https://github.com/aogorek/springboot-oauth2-angular2
It uses SpringBoot2, Spring Security 5, Angular5, Material Design, custom login page, and few other interesting things.
so go, clone the repository, test it, and feel free to comment. I'm curious of Your opinion about this solution. Maybe You have better idea to solve this scenario?
How do you configure resource service with a individual project? Please
ReplyDeletethanks for this project , but i think there is a problem with the silent refresh token because i get a token expired error . in the session storage the token is refreshed .
ReplyDeleteIn line 60, the refresh token will always be null and it is never initialized with a value. What is the point of that? Also implicit flow doesn't support refresh tokens, so there seems to be no need for creating one anyway.
ReplyDeleteNice articel, This article help me very well. Thank you. Also please check my article on my site about What Is Angular?.
ReplyDelete