skip to Main Content

I’m building a React Native app and I’m trying to connect it with the Keycloak instance I’m already using.

I could successfully setup logging in and out to the app with expo-keycloak (my app’s managed by Expo). This works fine for the most part, but I would like to have a native login form (so one that’s built with RN’s UI components and lives on it’s own screen) instead of opening a webview with Keycloak’s HTML-based form.

All the libraries and tutorials I’ve found so far use a webview and deep linking for a callback URL. Is there a library that I can integrate with my custom-made in-app forms or do I have to write this from scratch using KC’s REST API? I was looking into offline tokens, but I don’t get how to get an access token automatically with the offline token before making authenticated requests (almost all of the API endpoints I would have to call inside the app require an Authentication header with the access token added as the Bearer token).

I would also like to keep the user logged in "forever", as in until they don’t explicitly log out – as it’s common in mobile apps. My current KC setup shows the Login screen again after restarting the app, and when pressing the login button, it starts the webview again but without having to fill in the form again (so I’m automatically redirected to the app after a short blink of the webview). Why is that?

To be clear I’m not looking for a complete solution, it’s enough if someone just points me in the right direction or explains how to do this conceptually.

2

Answers


  1. I don’t think it is possible in Keycloak currently to do an OAuth flow without redirecting directly to Keycloak (so without using Keycloak’s screens). You could embed the login flow in an iframe, but you would have to make sure that your Keycloak installation is served from the same domain as your frontend app, as you may run into some cross-domain issues otherwise.

    I would also like to keep the user logged in "forever", as in until they don’t explicitly log out – as it’s common in mobile apps. My current KC setup shows the Login screen again after restarting the app, and when pressing the login button, it starts the webview again but without having to fill in the form again (so I’m automatically redirected to the app after a short blink of the webview). Why is that?

    What happens here is that an SSO session kicks in. Your app asks Keycloak for an access token and Keycloak needs to authenticate the user before it releases the token. It checks that the user has recently logged in (so there is an active session for her) and instantly issues new tokens to your app. This is the desired behavior for what you need — to keep the user logged in "forever". The user still has to click that login button, but she is logged in automatically.

    Login or Signup to reply.
  2. I’ve done this in a react app without any libraries.

    You need 3 endpoints that are already exposed by Keycloak and a simple token refresh mechanism.

    I’m providing CURL requests to simplify things. In the react client, make sure to use URLSearchParams for the body of the request (this took me a day to debug cors errors). For more info I suggest this tutorial or the official documentation Admin REST API

    1. Login / request token

     curl --location --request POST 'http://keycloakurl:keycloakport/realms/yourrealm/protocol/openid-connect/token' 
    --header 'Content-Type: application/x-www-form-urlencoded' 
    --data-urlencode 'client_id=yourclient' 
    --data-urlencode 'grant_type=password' 
    --data-urlencode 'username=youruser' 
    --data-urlencode 'password=yourpass' 
    --data-urlencode 'client_secret=yoursecret'
    

    2. Refresh token

    This is obtained from the login step. You should store this token in a store or in local browser storage. This should be refreshed according to your keycloak config (every 5 min by default)

    curl --location --request POST 'http://keycloakurl:keycloakport/realms/yourrealm/protocol/openid-connect/token' 
    --header 'Content-Type: application/x-www-form-urlencoded' 
    --data-urlencode 'client_id=yourclient' 
    --data-urlencode 'client_secret=yoursecret' 
    --data-urlencode 'grant_type=refresh_token' 
    --data-urlencode 'refresh_token=eyJhbGciOiJI.....
    
    

    3. Logout

    curl --location --request POST 'http://keycloakurl:keycloakport/realms/yourrealm/protocol/openid-connect/logout' 
    --header 'Content-Type: application/x-www-form-urlencoded' 
    --data-urlencode 'refresh_token=eyJhbGciOiJIU.....' 
    --data-urlencode 'client_id=yourclient' 
    --data-urlencode 'client_secret=yoursecret'
    
    

    In my client I’m using React + Redux + RxJS so I’m updating my token like this :

      const token = useSelector((state: AppState) => state.auth?.token);
      const tokenReceivedTime = useSelector((state: AppState) => state.auth?.tokenReceivedTime);
    
      // Refresh token
      useEffect(() => {
        if (!token || !token.expires_in || !tokenReceivedTime) return;
    
        const tokenExpiryTime = tokenReceivedTime / 1000 + token.expires_in;
    
        const checkTokenExpiry = () => {
          const currentTime = Date.now() / 1000;
          if (currentTime >= tokenExpiryTime) {
            console.info("Token expired, refreshing...");
            dispatch(refreshToken());
          }
        }
    
        const interval = setInterval(checkTokenExpiry, 60000);
        return () => clearInterval(interval);
    
      }, [token, tokenReceivedTime, dispatch]);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search