I have successfully implemented Keycloak within my application, with the ability to login via Github.
Since I want to save the user's information in my own database, I have written an EventListenerProvider (in JAVA), to store the user's Keycloak ID and E-mail in my own database.
When the user registers and/or login's through Github, I want to also get the Github token (and if need be the refresh token) and store it in my database. Preferably I would do this by creating an EventListener of sorts that does this during the registration process.
Is this possible at all and what is the best way to do this (preferably during registration or first sign-up moment)? Thanks in advance for any advice or pointers, much appreciated.
I have read the documentation and seen that this can be done through Keycloak API call, but that's not what I am looking for.
Related
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 come across a number of articles that discuss a similar matter but I cannot find a definitive answer.
My company would like to begin using Identity Server 3, however one of the requirements is to be able to authenticate an external user without them having to manually enter their credentials.
This must be capable of providing single sign on capabilities also as we have 3 different systems and our users should only have to sign in once.
Essentially, the external user has their own CRM.
The CRM holds their username and password for our software.
They then click a button in their CRM to launch our application
This redirects them to our website with a payload containing their credentials
We call a web service to authenticate the user
It is fundamental that we do not change this process for our partners.
Can I implement a custom service provider to provide the authentication or is there some other way of achieving this? If so, could you point me in the right direction for how this can be done?
Many thanks
Craig
I would assume that you'd create a mechanism for their CRM to get a token at the time the client logs into their site and then have them send that token via url to your callback page. This would use the machine-to-machine type grant, or the client-credentials flow. Then that page could validate the token and log the user in. There would have to be some sort of unique identifier between the two systems like email or something. Just an idea.
Since LinkedIn discontinued their network updates RSS feeds, I haven't been able to find any "simple" mechanism to gain access to update feeds w/o going through the oauth process requiring the user to authenticate first. The few examples I've seen posted here all assume you've obtained the auth token first. Is that even possible?
In case anyone else inquires: https://developer.linkedin.com/support/faq
If your application requires you to make API calls in an automated way
- without user interaction, you need to bootstrap the first access token request by manually signing in, and then ensure that your
application refreshes the token automatically prior to expiry to avoid
the need for additional human authentication.
What is the best practise for authorization and authentication of users in REST spring boot?
I am building web app with standard pages + REST API for mobile. I looked at many articles about Spring security and basically most of them goes with some sort of fitler approach that will allow or block REST calls. In my case, however, I have some auth logic based on who the user is. For example, there is a /update API that updates user information, and user can update himself, but cannot update other person.
Initially I thought to use next auth schema:
User calls auth API and pass name/password or cookie
System generates short life token, saves in it's database.
User get this token, updates his cookie (so JS in web application can read and use it)
When REST call is being make cookies are passed. At Controller, token is extracted, checked for expiration, query is done to database to validate token and get user id.
Based on user id, REST will be permited or blocked.
Is this the right approach to implement? I have a pretty big mess in my head after reading articles about spring boot security.
At least: session auth will not work for me (REST is stateless). I want to make auth for mobile device without storing login/password there.
Does it make sense to pass this token in the REST body itself? What in case of GET method?
Many thanks for sharing your knowledge.
Did you find a solution to your problem?
I have answered this problem elsewhere, if you are sure you won't want to open up the API to other developers/clients in the future (if you do then you should look at OAuth) then a simple token based solution will work.
Something basically along the lines of this:
Setup a standard html login page, that you can use for user login to the app
setup spring security to return a cookie on sucessful login with an authentication token
in your mobile app, embed a WebView (or equivalent) and load this login form - allow the user to login via that webview, on response grab the cookie and store the token (as mobile is generally single user, you can keep that pretty long to save mobile users having to keep logging in)
Add a security filter to the the REST API to authenticate against the token (from the mobile app pass the token in the header for example) - then you will be able to use normal spring authentication context for current users etc.
This approach is suggested by Google here: (EDIT: Google seems to have changed the page I originally read to be about using Google+ sign in and OAuth2.0 - I can't see a link to their general Mobile/API docs so here it is in the web archive :) )
I have also written up my implementation here:
Overview of the approach using Spring security
The code & details
Although this was really just an experiment/Proof of concept, it might be useful in your thinking.
Cookie approach seems perfect for the use case. Token can be tied up with user id. Filter can extract cookie and pass user id for example as header to apis - that should take care of GET...
I've been reading a lot about the topic but all I find are obsolete or partial answers, which don't really help me that much and actually just confused me more.
I'm writing a Rest API (Node+Express+MongoDB) that is accessed by a web app (hosted on the same domain than the API) and an Android app.
I want the API to be accessed only by my applications and only by authorized users.
I also want the users to be able to signup and login only using their Facebook account, and I need to be able to access some basic info like name, profile pic and email.
A possible scenario that I have in mind is:
The user logs-in on the web app using Facebook, the app is granted
permission to access the user Facebook information and receives an
access token.
The web app asks the API to confirm that this user
is actually registered on our system, sending the email and the
token received by Facebook.
The API verifies that the user
exists, it stores into the DB (or Redis) the username, the token and
a timestamp and then goes back to the client app.
Each time the
client app hits one of the API endpoint, it will have to provide the
username and the token, other than other info.
The API each time
verifies that the provided pair username/token matches the most
recent pair username/token stored into the DB (using the timestamp
to order), and that no more than 1 hour has passed since we stored
these info (again using the timestamp). If that's the case, the API
will process the request, otherwise will issue a 401 Unauthorized
response.
Does this make sense?
Does this approach have any macroscopic security hole that I'm missing?
One problem I see using MongoDB to store these info is that the collection will quickly become bloated with old tokens.
In this sense I think it would be best to use Redis with an expire policy of 1 hour so that old info will be automatically removed by Redis.
I think the better solution would be this:
Login via Facebook
Pass the Facebook AccessToken to the server (over SSL for the
android app, and for the web app just have it redirect to an API endpoint
after FB login)
Check the fb_access_token given, make sure its valid. Get user_id,email and cross-reference this with existing users to
see if its a new or old one.
Now, create a random, separate api_access_token that you give back to the webapp and android app. If you need Facebook for
anything other than login, store that fb_access_token and in your
DB associate it with the new api_access_token and your user_id.
For every call hereafter, send api_access_token to authenticate it. If you need the fb_access_token for getting more info, you can
do so by retrieving it from the DB.
In summary: Whenever you can, avoid passing the fb_access_token. If the api_access_token is compromised, you have more control to see who the attacker is, what they're doing etc than if they were to get ahold of the fb_access_token. You also have more control over settings an expiration date, extending fb_access_tokens, etc
Just make sure whenever you pass a access_token of any sort via HTTP, use SSL.
I know I'm late to the party, but I'd like to add a visual representation of this process as I'm dealing with this problem right now (specifically in dealing with the communication between the mobile app and the web api by securing it with a 3rd party provider like facebook).
For simplicity, I haven't included error checks, this is mostly just to outline a reasonable approach. Also for simplicity, I haven't included Tommy's suggestion to only pass your own custom api token once the authorization flow is over, although I agree that this is probably a good approach.
Please feel free to criticize this approach though, and I'll update as necessary.
Also, in this scenario, "My App" refers to a mobile application.