KOBI does not come with an authentication solution.
The first advantage of this choice is that it allow you to keep your existing authentication mecanism (in case of a legacy), or choose whatever you want to use for your new website.
The second is that KOBI is not bound to your information system (identity provider, user databases…).
What KOBI does
Propagate the authentication information to your applications through a JWT cookie.
From Designer, when configuring your site, under “security” you will find this kind of form :
cookie name : your authentication cookie name (ex : auth.jwt)
cookie domain : your site domain (ex : .my-domain.com)
http-only : true is highly recommanded
secured : true is highly recommanded
issuer : for Oauth, should be your client_id
public-key : the generated RSA public key
handle-refresh : if true, set the refresh-uri
refresh-uri : your authentication application path to refresh authentication (ex : https://my-auth-app/refresh)
login-path : the path to the login on your website (ex : /login)
Authentication application
You might want to ask for the KOBI team wether you should use fragments or applicative mode and Pages or Page Models, depends on your workflows, existing legacy…
Let’s keep it simple, we will create an application using the applicative mode that display a login form (use the according fragment documentation) and redirect to a callback with the authentication cookie set.
This applicative context should be set in a Page Model.
@Controller@RequestMapping@RequiredArgsConstructorpublicclassLoginController{privatefinalRequestSavingServicerequestSavingService;privatefinalOauthServiceoauthService;privatefinalJWTServicejwtService;privatefinalAuthenticationsConfigauthenticationsConfig;@ApplicationContext("lmfr-authentication")// Application context to embed the app in a Header/Footer Model
@GetMapping("/login")publicMono<String>getLoginApp(@RequestParam(name="callback")Stringcallback,ServerWebExchangeserverWebExchange,Modelmodel){//Save the request in a temporary cookie, returns a random generated state
returnthis.requestSavingService.saveRequest(serverWebExchange,"MY_CLIENT_ID",callback,"https://this-auth-app/callback").flatMap(state->this.oauthService.getOauthLoginUri(state,"MY_CLIENT_ID","https://this-auth-app/callback")).flatMap(oauthUri->{//add oauth uri to template model
model.addAttribute("src",oauthUri);// We do the redirection in Javascript client-side, in order to set the cookie (request save)
returnMono.just("/components/login/login-redirect");});}//Come back from Oauth with a code, get an access token, create the JWT cookie and return to the callback
@GetMapping("/callback")publicMono<String>getCallback(@RequestParam(name="code")Stringcode,@RequestParam(name="state")Stringstate,Modelmodel,ServerWebExchangeserverWebExchange){//Retrieve our saved request from cookies
returnthis.requestSavingService.getSavedRequest(serverWebExchange).flatMap(savedRequest->{//Check Oauth returned our code & state and verify state against the one we saved initialy
if(state==null||!state.equals(savedRequest.getState())){returnMono.error(newAccessDeniedException());}//Exchange the code for an AT, fetch user-infos and create the JWT token
returnoauthService.getAccessToken(code,savedRequest.getProvider(),savedRequest.getRedirectUri()).map(accessToken->this.oauthService.getUserInfos(accessToken.getIdToken(),savedRequest.getProvider())).flatMap(userInfos->this.jwtService.createJwtToken(userInfos)).flatMap(jwt->{//Add the jwt cookie in the response
serverWebExchange.getResponse().addCookie(ResponseCookie.from("auth.jwt",jwt).build());//Delete the saved request cookie
this.requestSavingService.deleteSavedRequest(serverWebExchange,savedRequest.getProvider());returnMono.just("redirect:"+savedRequest.getCallback());});});}}
For the JWT creation feel free to use your own implementation or existing library, else you can use the kobi-starter “KobiUser” class (JAVA) :
1
2
3
4
5
6
7
8
9
10
KobiUseruser=newKobiUser.KobiUserBuilder("MY_CLIENT_ID","Kobi",expireDate).withAccessToken(accessToken).withRefreshToken(refreshToken).withIdToken(idToken).withUserId(userId).withAttributes(attributes)// Map of user info
.withRoles(roles).build();StringjwtToken=user.getJwtToken(this.algorithm,this.objectMapper));
Workflow
If your component does not receive the auth.jwt in its request, and requires to be authentication, it can respond with a 401.
When Gluer receive a 401 from a primary fragment or applicative mode it will redirect to your login page with a callback parameter.
Once logged in, Gluer will check the auth.jwt cookie (signature and validity date), if OK it will be sent to each components.
If the JWT is expired, Gluer will call the refresh-uri (if enabled) with all the cookies from the incoming request and set back the cookie from the response to the component’s request and final client response.
If the refresh is disabled or the JWT signature is invalid, the cookie will be deleted.