In this example, we will use simple email/password authentication. Logux supports any authentication, including OAuth or WebAuthn.
We will show two of the most popular cases:
- You already have Ruby/PHP/Python back-end server and HTML page with email and password fields. When user passed authentication back-end server redirects them and insert user ID and token as <meta>tags.
- You keep all your business logic in Logux Server and use HTTP just to send static HTML. In this case, Logux client connects as a guest and sends authentication action. Logux server sends action with a user ID and token back to the client. The client will save them to localStorage.
If you need another way, you can combine methods.
Method 1: HTML Form and Meta Tags
Method 1: Server
Go to your back-end server.
Add jwt to Gemfile and call bundle:
gem 'jwt'Add JWT secret key to local .env:
LOGUX_CONTROL_SECRET=secret
LOGUX_URL=http://localhost:31338
JWT_SECRET=secretEdit config/initializers/logux.rb:
config.auth_rule = lambda do |user_id, token|
  # Allow only local users until we will have a proper authentication
  Rails.env.development?
  data = JWT.decode token, ENV['JWT_SECRET'], { algorithm: 'HS256' }
  data[0]['sub'] == user_id
endAdd <meta> tags to application layout used for authenticated user:
    meta( name="userId" content=current_user.id )
    meta( name="token" content=JWT.encode({ sub: current_user.id }, ENV['JWT_SECRET'], 'HS256') )Add JWT secret key to proper storage for your environment. Local .env is a good option.
LOGUX_CONTROL_SECRET=secret
LOGUX_URL=http://localhost:31338
JWT_SECRET=secretAdd library to support JWT. Add code to check userId and token from Logux:
data = JWT.decode(token, ENV['JWT_SECRET'])
return data.sub == userIdGenerate token to use in HTML template:
token = JWT.encode({ sub: userId }, ENV['JWT_SECRET'])Add this token and user ID to HTML templates used for authenticated user:
    <meta name="userId" content=<?= userId ?>>
    <meta name="token" content=<?= token ?>>Method 1: Client
Use these <meta> values in the store:
let userId = document.querySelector('meta[name=userId]')
let token = document.querySelector('meta[name=token]')
if (!userId) {
  location.href = process.env.NODE_ENV === 'development'
    ? 'http://localhost:3000/login'
    : 'https://example.com/login'
}
const client = new CrossTabClient({
  subprotocol: 10,
  server: process.env.NODE_ENV === 'development'
    ? 'ws://localhost:31337'
    : 'wss://logux.example.com',
  userId: 'anonymous', // TODO: We will fill it in next chapter
  token: '' // TODO: We will fill it in next chapter
  userId: userId.content,
  token: token.content
})let userId = document.querySelector('meta[name=userId]')
let token = document.querySelector('meta[name=token]')
if (!userId) {
  location.href = process.env.NODE_ENV === 'development'
    ? 'http://localhost:3000/login'
    : 'https://example.com/login'
}
const client = new CrossTabClient({
  subprotocol: 10,
  server: process.env.NODE_ENV === 'development'
    ? 'ws://localhost:31337'
    : 'wss://logux.example.com',
  userId: 'anonymous',
  token: ''
  userId: userId.content,
  token: token.content
})Method 1: Check the Result
Start back-end server and Logux client. Try to sign-in into application.
Method 2: Everything in Logux
Method 2: Server
Go to Logux Server and add the library to generate JWT:
npm i jwt-simple bcryptpnpm add jwt-simple bcryptyarn add jwt-simple bcryptLoad it in the index.js:
const { Server } = require('@logux/server')
const bcrypt = require('bcrypt')
const jwt = require('jwt-simple')
const pg = require('pg-promise')Add JWT secret key to local .env config file:
DATABASE_URL=postgres://localhost/server-logux
JWT_SECRET=secretGo back to index.js and replace server.auth(…) with this code:
server.auth(({ userId, token }) => {
  if (userId === 'anonymous') {
    return true
  } else {
    try {
      const data = jwt.decode(token, process.env.JWT_SECRET)
      return data.sub === userId
    } catch (e) {
      return false
    }
  }
})
server.type('login', {
  async access (ctx) {
    return ctx.userId === 'anonymous'
  },
  async process (ctx, action, meta) {
    const user = await db.oneOrNone('SELECT * FROM users WHERE email = $1', action.email)
    if (!user) {
      server.undo(action, meta, 'Unknown email')
    } else if (await bcrypt.compare(action.password, hash)) {
      let token = jwt.encode({ sub: user.id }, process.env.JWT_SECRET)
      ctx.sendBack({ type: 'login/done', userId: user.id, token })
    } else {
      server.undo(action, meta, 'Wrong password')
    }
  }
})Method 2: Client
In this example, we will implement sign-in outside of the application’s store, because guests don't need it. You can implement it the way you want, according to your design.
Sign-in user with simple Logux Client, save userId and token to localStorage and redirect to application:
import { Client } from '@logux/client'
function login (email, password) {
  let client = new Client({
    subprotocol: 10,
    server: process.env.NODE_ENV === 'development'
      ? 'ws://localhost:31337'
      : 'wss://logux.example.com',
    userId: 'anonymous'
  })
  client.type('login/done', action => {
    localStorage.setItem('userId', action.userId)
    localStorage.setItem('token', action.token)
    location.href = process.env.NODE_ENV === 'development'
      ? 'http://localhost:3000/dashboard'
      : 'https://app.example.com/dashboard'
  })
  client.type('logux/undo', action => {
    alert(action.reason)
  })
  client.start()
  client.log.add({ type: 'login', email, password }, { sync: true })
})Use these localStorage values in the store:
if (!localStorage.getItem('userId')) {
  location.href = process.env.NODE_ENV === 'development'
    ? 'http://localhost:3000/login'
    : 'https://example.com/login'
}
const client = new CrossTabClient({
  subprotocol: 10,
  server: process.env.NODE_ENV === 'development'
    ? 'ws://localhost:31337'
    : 'wss://logux.example.com',
  userId: 'anonymous', // TODO: We will fill it in next chapter
  token: '' // TODO: We will fill it in next chapter
  userId: localStorage.getItem('userId'),
  token: localStorage.getItem('token')
})if (!localStorage.getItem('userId')) {
  location.href = process.env.NODE_ENV === 'development'
    ? 'http://localhost:3000/login'
    : 'https://example.com/login'
}
const client = new CrossTabClient({
  subprotocol: 10,
  server: process.env.NODE_ENV === 'development'
    ? 'ws://localhost:31337'
    : 'wss://logux.example.com',
  userId: 'anonymous',
  token: ''
  userId: localStorage.getItem('userId'),
  token: localStorage.getItem('token')
})Method 2: Check the Result
In the next steps, you will need a good sign-up form, email verification, and many other things for proper authentication. They highly depend on your application and out of this guide topic.