Based on the following example https://vaadin.com/blog/jwt-authentication-with-vaadin-flow-for-better-developer-and-user-experience, I'm trying to implement hybrid-stateless application.
Based on the information inside of the JWT token, I'm be able to fetch the required data from DB and cache it in HTTP Session after the application redeploy. I'm almost done with this, but I have one issue. My application uses Keycloak as SSO. In order to proper implement logout functionality, I have to kill Keycloak session as well. I know how to get all user sessions on all devices and kill them all… but I'd like to kill the only Keycloak session - specific to the current user browser. I know how to get Keycloak user session ID from OAuth2AuthenticationToken in my KeycloakVaadinAuthenticationSuccessHandler. But I aso need to persist it's value in JWT token in order to be able to fetch it after the application restart.
Is it possible to add a custom attribute to JWT token generated by the setStatelessAuthentication functionality? If so - please show how
Related
I'm building an application where I want to be able to create and authenticate users using Discord and OAuth2. The reasons are:
The application can be considered a "companion" app to a Discord community I am running, and
I don't want the users or myself to have to deal with usernames and passwords
The application consists of a client desktop application and backend services. I have a fairly basic understanding on how I authorize the user with Discord:
Client application goes to backend endpoint /oauth/login and the user is redirected to the Discord app approval page
The user confirms and is redirected to the backend callback /oauth/callback with a code that can be used to fetch a pair of access and refresh tokens.
Frankly, from this point I am kind of stumped on how the rest of the authentication should work. I assume at least the following:
I need to create a user entry in my database with at least an UID (for simplicity the same as the one for the user in Discord), the access and refresh token pair. If user is already created, update the database with the new tokens.
Whenever the application needs user information from Discord it should use the access token. If it has expired, exchange the refresh token with Discord to get a new token pair.
But now what? This only authenticates the user against Discord. I want to leverage the fact that the user is authenticated with Discord to be authenticated to my application. Here are some general questions I have:
Do I make a new token for the user to use for subsequent requests to my backend endpoints? Or do I return the Discord access token to the desktop client?
What do I do when the token expires? Do I also need a "exchange" endpoint for the desktop client to refresh the token (possibly that just forwards to Discord to get a new token, depending on the answer to my previous question).
This all feels like it should be very basic, but I am out of my comfort zone here and need some help to be unblocked.
Thanks for reading!
Your own application should effectively have its own session system.
The easiest is likely to just use HttpOnly cookie-based sessions, which something like a Redis store (or Memory store if this is a toy project).
The session data on the server should contain information on which user is currently logged in. You should probably store the discord access and refresh token in a database.
The simplest way to deal with refreshing, is to simply call their refresh token endpoint as soon as you get a 401 response. If discord provides information on how long access tokens are valid, you could also preemptively refresh instead of only doing this when you get the 401. Your server does the refreshing, you don't need an endpoint for this.
Generally I can recommend that your server handles all interactions with the discord API, and never your client. (aside from the initial authorization step).
I'm trying to implement jwt for authentication for my backend and frontend. I have 2 apps (.net core mvc) one is backend other one is frontend
I send login request and then i get access and refresh token etc. Those parts are ok.
Question:
But problem is that front end has no idea that i have token from backend API that's why there is no session created on frontend yet. So i cannot redirect user to protected areas of website [Authorize]
First thing comes to my mind is after i get access token from backend API ı should post it to front end controller via ajax. Lets say "/Account/Login" and this frontend controller will validate token (because it has same key with backend) then it will create session for this user and will return success from ajax call.
Is this correct approach for this kind of login flow ? Are there any alternatives ?
How is your user talking with the backend app? Directly or through frontend app? I would presume that they make a request to the frontend app and the frontend talks to backend. In such a scenario frontend can easily create a session for the user and associate the token from backend with the session.
If the user is talking directly to backend app, then I would go with your idea - the backend app would have to somehow notify frontend app that it now has a token for the user.
Another solution is to create some shared session mechanism (there are some readily available solutions for that). Your backend app can create a shared session and associate the token with it, and then the frontend app can use the same shared session.
I built a login system using Flask OIDC and Keycloak. In my system, there is some endpoints decorated with oidc.require_login() that calls the Keycloak login page.
My goal is, after the user successfully logged in, my system checks if the user name exists in a specific database.
How can I set a function to be called every time someone successfully logged in with Keycloak and do this verification at the database?
According to your needs there are several ways to create the user in the backend.
The easiest way would be to just check the JWT token on every request. OIDC is based on JWT and that token is available on any request (which should already be done to find user roles etc). So your application can check that JWT and extract the username from it (see here for details about the JWT format). With the username you can check your internal database and create the user, if it doesnt exist. But at that time you'll not have access to any user credentials any more. It is just SSO and you need to trust Keycloak and the JWT... Also - you'll never be informed, if the user will be deleted in Keycloak, which could be an issue.
There is a callback API in Keycloak in form of the Admin URL per client. But the documentation is not clear. It says: It’s used by the Keycloak server to send backend requests to the application for various tasks, like logout users or push revocation policies. But I cannot find a complete list of "tasks". I saw only logout events. see Keycloak documentation and the documentation only talks about that. If I add an admin url to a test client, I did not get any requests at login time.
a different but more complicated way would be to create your own UserStorage SPI in Keycloak. It would be Java of course, but only some classes. There is an HTTP example or have a look at the LDAP user storage SPI, which supports registration too. If you choose that for your realm and a user tries to login to Keycloak (Login form), the SPI can call your backend to check the user. It also could be "used" to create the user in the backend by checking the Keycloak local storage and only if there is a local Keycloak user, call the backend. That isn't the reason, why you should implement the UserStorage SPI, but it's possible. If you think, this is a good idea, I would prefer to use your backend storage as the one and only storage or build a different one, that then could call your real backend in case of a new user. I would use this one by not using Keycloak local stored users but, by using your own database.
next (maybe last one). You can write an EventListener SPI to read all events and only filter the login events, see here and here. I think, that would be the easiest one. But be aware. In that case, the HTTP call to your backend coming from the event itself is based on a normal HTTP request (without OIDC at that time).
The last two examples create a JAR (which is explained in the links). That JAR with the SPI must be deployed in keycloaks standalone/deployments folder. The EventListener should be active by default, the UserStorage SPI must be activated per realm.
But - be aware - Keycloak/SSO/JWT - should not be used by creating users in multiple backends. Syncing the users between all backends in a SSO environment is maybe the wrong way. Most information is located in the JWT or can be called by a backend from one central user identity management. Do not store a user more then once. If you need the user reference in your backend - link just to the username or userid (string) instead of a complete entity.
There is no direct way of doing this, other sotfware like Openam, Okta allow you to trigger specific flows in a post-login configuration.
In keycloak, you can try to create your custom authn flow(using Default Identity Provider, its the only option that allow a redirect), and then select this flow in your Identity provider in post login flow.
The idea here is that after login, the user will be redirected to a link ( an api call that will verify his presence on the external database, and sent him back to keycloak once the verification is done.
More info here
I have a user microservice. This microservice uses token authorization. Now it's consumed by web application. Workflow looks like this:
user logs in to web application using AzureAd OpenIdConnect;
web application receives access token (authorization code flow);
web application gets user details from user service passing access token in HTTP request header.
Also I have a daemon microservice where I don't have a user context. I want to allow this daemon service to get user details from user service too. I'm going to use client credentials flow for that case.
How to organize user service rest api properly?
I'm thinking about this approach:
user's data is available at this URL /users/{userId}/info;
applications with user context (i.e. access token is issued for particular user using authorization code flow) can consume data only for current user or current user is an admin and can work with another user's data;
daemon applications without current user (i.e. access token is issued for the application itself using client credentials flow) can read data for any user.
What is the best practices for such cases?
I think the best and more restful approach to define this API is to build a unique endpoint /users/{id}.
Where id can be an actual real user id or a predefined value like 'me'. It is the user service the one who has to retrieve from the token the user information in case that the id value is 'me'.
The other changes that I would make is to use users instead of user because rest good practices say that the elements in the URL are collection.
And the last one, to not use info because it is redundant. Because when you query for an entity obviously you want its info
I've got an application where back-end and front-end are served from different hosts and are two different applications (both Symfony 3 based).
One of them (back-end ofc) handles business logic and keeps users and their roles in it's DB. Back-end provides REST API to be used by front-end. I have no possibility to modify back-end code as it's not my project - I just want to create a front-end for it.
Currently, I'm trying to create front-end app in Symfony 3 but I'm not sure how to make the front-end app authenticate against a remote API and keep no user data (or as little as possible) on its side.
After passing credentials to the backend via REST API a token is sent to front-end application and following API requests (e.g. data the front-end app would present to the user are to be sent with token received after successful authentication).
My question again: How can I authenticate against remote custom (non-OAuth) API from Symfony 3?
And additionally: How to handle token properly later? (it has to be used while making every request after successful authentication). What is the easiest way to achieve this?
I've been struggling to find decent info (maybe a tutorial?) I'm a noob in Symfony :(
Most articles describe providing an API which allows clients to connect to it, not making a client app in Symfony.
What I found:
Symfony2 authentication via 3rd Party REST API - most relevant, though it describes a flow for Symfony 2 and the accepted answer describes what should be done only briefly
https://blog.vandenbrand.org/2012/06/19/symfony2-authentication-provider-authenticate-against-webservice/ - concerning Symfony 2
http://symfony.com/doc/current/security/custom_authentication_provider.html - probably the most on topic, however, I don't understand where will app keep it's users (is writing a custom user provider necessary in this example?)
You've already found the answer on your question. That's custom authentication provider. You can keep the tokens in your frontend app storage, and just authenticate them. On login, you should create the token via request to backend app, save it in your token storage and that's all. Then you only need to authenticate the token (just see an example of auth provider).
Regarding keeping user data in your frontend app, it's up to you. You don't have to keep any data, therefore if you'd like to show some details (i.e. user name and so on) you have to store that details too (or retrieve it each request - but that will impact the performance). At least you can use caching for that.
So the possible approach is:
On login(with login form or elsewhere), just authenticate user in login handler (create your own auth provider as described there - don't worry about Symfony 2, security component is almost the same - there are some incompatibilities, but the direction is correct). After successful authentication, store token in your frontend storage (also you can store some user details you need like name and so on).
On each request, authenticate the user using the token that's kept in your frontend app storage (that's another auth provider) - you don't need to send request to your backend app.