node.js - Securing Electron app with Keycloak - TagMerge
5Securing Electron app with KeycloakSecuring Electron app with Keycloak

Securing Electron app with Keycloak

Asked 1 years ago
1
5 answers

To use Keycloak in build Electron You must add server listener in your main.js:

const Keycloak = http.createServer((request, response) => {
  response.writeHeader(200, {"Content-Type": "text/html"});  
  var readSream = fs.createReadStream(__static + '/index.html','utf8')
  readSream.pipe(response);
});
Keycloak.listen(3000);

Next add file index.html to folder __static. In this file add JS script like in this instruction. And you must add ipcRenderer and send token to main.js:

   keycloak.init({ onLoad: 'login-required', redirectUri: 'http://localhost:3000' }).success(function(authenticated) {
       if (authenticated) {               
           ipcRenderer.send('keycloak-token', keycloak.token);
       }
   }).error(function() {
       console.log('error');
   });

Remember to add http://localhost:3000 in Keycloak setting in redirectUri.

Next in main.js you can send token to check autorization:

  ipcMain.on('keycloak-token', (event, token) => {
    const winURL = process.env.NODE_ENV === 'development'
  ? `http://localhost:9080?token=${token}`
  : `file://${__dirname}/index.html?token=${token}`

    mainWindow.loadURL(winURL);
  });

Source: link

0

  import Keycloak from 'keycloak-js';

  if (!process.env.NODE_ENV || process.env.NODE_ENV === 'development') {
    // don't need keycloak in development mode, change the condition to if (false) to force keycloak to be required locally
  } else {
    keycloak.init({ onLoad: 'login-required', checkLoginIframeInterval: 1 }).success((authenticated) => {
      if (authenticated) {
        sessionStorage.setItem('kctoken', keycloak.token);

        setInterval(() => {
          keycloak.updateToken(10).error(() => keycloak.logout());
          sessionStorage.setItem('kctoken', keycloak.token);
        }, 10000);
      } else {
        keycloak.login();
      }
    });
  }

Try that and post back thanks :)

Source: link

0

Finally, I've managed to implement Keycloak authentication with Electron app. The thing is to fork a temporary http server from the main process of your app. This server should listen to a redirect request after successful Keycloak login. Of course, for this to work you should specify the address of this server in the *Valid Redirect URIs input of your Keycloak client, say http://localhost:33333. When the request comes to the server, you parse it and extract the 'search' part of the request. Then you append this 'search' part to your index.html path and load mainWindow from it:

const url = `file://${path.join(__dirname, '../index.html')}${searchString}`;
mainWindow.loadURL(url);

Works good for me.

PS. I can elaborate on this solution with sample code upon request.

Source: link

0

$ curl https://downloads.jboss.org/keycloak/11.0.3/keycloak-11.0.3.zip --output keycloak-11.0.3.zip
$ unzip keycloak-11.0.3.zip
$ cd keycloak-11.0.3/bin/
$ ./add-user-keycloak.sh -r master -u admin -p admin
$ ./standalone
docker run -p 8080:8080 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin quay.io/keycloak/keycloak:11.0.3
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@CrossOrigin("*")
@RestController
@RequestMapping("/api/heroes")
public class HeroController {

    private List<Hero> someHeroes = List.of(
            new Hero(1, "Ken"),
            new Hero(2, "Yannick"),
            new Hero(3, "Pieter"));

    @GetMapping
    public List<Hero> heroes() {
        return someHeroes;
    }

    @GetMapping("/{id}")
    public Hero hero(@PathVariable("id") String id) {
        return someHeroes.stream()
                .filter(h -> Integer.toString(h.getId()).equals(id))
                .findFirst()
                .orElse(null);
    }
}

class Hero {
    private final int id;
    private final String name;

    public Hero(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() { return id; }

    public String getName() { return name; }
}
$ curl -LO https://angular.io/generated/zips/toh-pt6/toh-pt6.zip
$ unzip toh-pt6.zip -d toh
$ cd toh
$ npm i
export class HeroService {

  private heroesUrl = 'http://localhost:9090/api/heroes';
  ...
}

Source: link

0

{
  "realm" : "demo",
  "resource" : "customer-portal",
  "realm-public-key" : "MIGfMA0GCSqGSIb3D...31LwIDAQAB",
  "auth-server-url" : "https://localhost:8443",
  "ssl-required" : "external",
  "use-resource-role-mappings" : false,
  "enable-cors" : true,
  "cors-max-age" : 1000,
  "cors-allowed-methods" : "POST, PUT, DELETE, GET",
  "cors-exposed-headers" : "WWW-Authenticate, My-custom-exposed-Header",
  "bearer-only" : false,
  "enable-basic-auth" : false,
  "expose-token" : true,
  "verify-token-audience" : true,
  "credentials" : {
    "secret" : "234234-234234-234234"
  },

  "connection-pool-size" : 20,
  "socket-timeout-millis" : 5000,
  "connection-timeout-millis" : 6000,
  "connection-ttl-millis" : 500,
  "disable-trust-manager" : false,
  "allow-any-hostname" : false,
  "truststore" : "path/to/truststore.jks",
  "truststore-password" : "geheim",
  "client-keystore" : "path/to/client-keystore.jks",
  "client-keystore-password" : "geheim",
  "client-key-password" : "geheim",
  "token-minimum-time-to-live" : 10,
  "min-time-between-jwks-requests" : 10,
  "public-key-cache-ttl" : 86400,
  "redirect-rewrite-rules" : {
    "^/wsmaster/api/(.*)$" : "/api/$1"
  }
}
$ cd $WILDFLY_HOME
$ unzip keycloak-wildfly-adapter-dist-17.0.0.zip
$ cd $EAP_HOME
$ unzip keycloak-eap7-adapter-dist-17.0.0.zip
$ cd $EAP_HOME
$ unzip keycloak-eap6-adapter-dist-17.0.0.zip
$ cd $JBOSS_HOME
$ unzip keycloak-as7-adapter-dist-17.0.0.zip

Source: link

Recent Questions on node.js

    Programming Languages