Skip to main content
The @feathersjs/authentication-client package provides client-side authentication for Feathers applications, handling JWT storage, authentication state, and automatic token management.

Installation

npm install @feathersjs/authentication-client

Setup

Initialize the authentication client plugin:
import authClient from '@feathersjs/authentication-client'

app.configure(authClient(options))

Options

interface AuthenticationClientOptions {
  storage?: Storage
  header?: string
  scheme?: string
  storageKey?: string
  locationKey?: string
  locationErrorKey?: string
  jwtStrategy?: string
  path?: string
  Authentication?: ClientConstructor
}
storage
Storage
default:"localStorage or MemoryStorage"
Storage backend for storing the JWT. Defaults to window.localStorage in browsers, MemoryStorage otherwise
header
string
default:"Authorization"
The HTTP header name for sending the JWT
scheme
string
default:"Bearer"
The HTTP authentication scheme
storageKey
string
default:"feathers-jwt"
The key name for storing the JWT in storage
locationKey
string
default:"access_token"
The key name for getting the JWT from the window location hash
locationErrorKey
string
default:"error"
The key name for getting errors from the window location hash
jwtStrategy
string
default:"jwt"
The name of the JWT authentication strategy
path
string
default:"/authentication"
The path of the authentication service
Example:
import { feathers } from '@feathersjs/feathers'
import authClient from '@feathersjs/authentication-client'

const app = feathers()

app.configure(authClient({
  storage: window.localStorage,
  storageKey: 'my-app-jwt'
}))

AuthenticationClient

The main authentication client class. After configuration, the methods are available directly on the app instance.

authenticate

Authenticate with the server using a specific strategy.
app.authenticate(authentication?: AuthenticationRequest, params?: Params): Promise<AuthenticationResult>
authentication
AuthenticationRequest
The authentication data. If not provided, will attempt reauthentication with stored token
interface AuthenticationRequest {
  strategy?: string
  [key: string]: any
}
params
Params
Additional service call parameters
accessToken
string
The JWT access token
authentication
object
Authentication metadata including strategy and payload
user
object
The authenticated user/entity object
Examples:
// Authenticate with local strategy
const result = await app.authenticate({
  strategy: 'local',
  email: '[email protected]',
  password: 'secret'
})

console.log(result.accessToken)
console.log(result.user)

// Reauthenticate with stored token
try {
  await app.authenticate()
  console.log('Already authenticated')
} catch (error) {
  console.log('Need to login')
}

// Authenticate with OAuth token
const result = await app.authenticate({
  strategy: 'jwt',
  accessToken: 'existing-token'
})

reAuthenticate

Try to reauthenticate using the token from storage. Does nothing if already authenticated unless force is true.
app.reAuthenticate(
  force?: boolean,
  strategy?: string,
  authParams?: Params
): Promise<AuthenticationResult>
force
boolean
default:"false"
Force reauthentication with the server even if already authenticated
strategy
string
The name of the strategy to use. Defaults to options.jwtStrategy
authParams
Params
Additional authentication parameters
Example:
// Try to reauthenticate on app startup
app.reAuthenticate()
  .then(result => {
    console.log('Authenticated', result.user)
  })
  .catch(() => {
    console.log('Not authenticated')
  })

// Force reauthentication
await app.reAuthenticate(true)

logout

Log out the current user and remove their token.
app.logout(): Promise<AuthenticationResult | null>
Example:
await app.logout()
console.log('User logged out')

Token Management

getAccessToken

Get the access token from storage or window location hash.
app.authentication.getAccessToken(): Promise<string | null>
Example:
const token = await app.authentication.getAccessToken()
if (token) {
  console.log('Token found:', token)
}

setAccessToken

Set the access token in storage.
app.authentication.setAccessToken(accessToken: string): Promise<string>
accessToken
string
required
The access token to store
Example:
await app.authentication.setAccessToken('new-token')

removeAccessToken

Remove the access token from storage.
app.authentication.removeAccessToken(): Promise<string>
Example:
await app.authentication.removeAccessToken()

Properties

authenticated

Indicates whether the client is currently authenticated.
app.authentication.authenticated: boolean
Example:
if (app.authentication.authenticated) {
  console.log('User is authenticated')
}

storage

Access to the storage backend.
app.authentication.storage: Storage

Events

The authentication client emits events on the app instance:

login

Emitted after successful authentication.
app.on('login', (authResult) => {
  console.log('Logged in', authResult.user)
})

authenticated

Emitted after successful authentication (same as login).
app.on('authenticated', (authResult) => {
  console.log('Authenticated', authResult.user)
})

logout

Emitted after logout.
app.on('logout', (authResult) => {
  console.log('Logged out')
})

Hooks

authentication

Automatically adds authentication information to service calls.
import { hooks } from '@feathersjs/authentication-client'

app.hooks([hooks.authentication()])
This hook is automatically added when you configure the authentication client.

populateHeader

Automatically populates the Authorization header with the JWT for external requests.
import { hooks } from '@feathersjs/authentication-client'

app.hooks([hooks.populateHeader()])
This hook is automatically added when you configure the authentication client.

Storage

The authentication client uses a storage interface for persisting JWTs.

Storage Interface

interface Storage {
  getItem(key: string): Promise<string | null>
  setItem(key: string, value: string): Promise<string>
  removeItem(key: string): Promise<string>
}

Built-in Storage

Default Storage

Automatically uses localStorage in browsers, falls back to MemoryStorage.
import { defaultStorage } from '@feathersjs/authentication-client'

app.configure(authClient({ storage: defaultStorage }))

MemoryStorage

In-memory storage for environments without localStorage.
import { MemoryStorage } from '@feathersjs/authentication-client'

app.configure(authClient({ storage: new MemoryStorage() }))

Custom Storage

Implement the Storage interface for custom storage backends:
class CustomStorage {
  async getItem(key) {
    // Retrieve from custom storage
    return myStorage.get(key)
  }

  async setItem(key, value) {
    // Store in custom storage
    return myStorage.set(key, value)
  }

  async removeItem(key) {
    // Remove from custom storage
    return myStorage.delete(key)
  }
}

app.configure(authClient({ storage: new CustomStorage() }))

Complete Example

Browser Application

import { feathers } from '@feathersjs/feathers'
import socketio from '@feathersjs/socketio-client'
import io from 'socket.io-client'
import authClient from '@feathersjs/authentication-client'

const socket = io('http://localhost:3030')
const app = feathers()

app.configure(socketio(socket))
app.configure(authClient({
  storage: window.localStorage
}))

// Try to authenticate on startup
app.reAuthenticate()
  .then(result => {
    console.log('Already authenticated', result.user)
  })
  .catch(() => {
    console.log('Not authenticated')
  })

// Login form handler
const loginForm = document.getElementById('login-form')
loginForm.addEventListener('submit', async (e) => {
  e.preventDefault()
  
  try {
    const result = await app.authenticate({
      strategy: 'local',
      email: e.target.email.value,
      password: e.target.password.value
    })
    
    console.log('Logged in', result.user)
  } catch (error) {
    console.error('Login failed', error)
  }
})

// Logout button handler
const logoutButton = document.getElementById('logout-button')
logoutButton.addEventListener('click', async () => {
  await app.logout()
  console.log('Logged out')
})

// Listen for authentication events
app.on('login', result => {
  console.log('Login event', result.user)
})

app.on('logout', () => {
  console.log('Logout event')
})

React Example

import React, { useState, useEffect } from 'react'
import app from './feathers-client'

function App() {
  const [user, setUser] = useState(null)
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    // Try to reauthenticate on mount
    app.reAuthenticate()
      .then(result => setUser(result.user))
      .catch(() => setUser(null))
      .finally(() => setLoading(false))

    // Listen for login/logout events
    app.on('login', result => setUser(result.user))
    app.on('logout', () => setUser(null))
  }, [])

  const handleLogin = async (email, password) => {
    try {
      const result = await app.authenticate({
        strategy: 'local',
        email,
        password
      })
      setUser(result.user)
    } catch (error) {
      console.error('Login failed', error)
    }
  }

  const handleLogout = async () => {
    await app.logout()
    setUser(null)
  }

  if (loading) return <div>Loading...</div>

  return (
    <div>
      {user ? (
        <div>
          <p>Welcome, {user.email}</p>
          <button onClick={handleLogout}>Logout</button>
        </div>
      ) : (
        <LoginForm onSubmit={handleLogin} />
      )}
    </div>
  )
}

Node.js Client

import { feathers } from '@feathersjs/feathers'
import socketio from '@feathersjs/socketio-client'
import io from 'socket.io-client'
import authClient, { MemoryStorage } from '@feathersjs/authentication-client'

const socket = io('http://localhost:3030')
const app = feathers()

app.configure(socketio(socket))
app.configure(authClient({
  storage: new MemoryStorage()
}))

// Authenticate
const result = await app.authenticate({
  strategy: 'local',
  email: '[email protected]',
  password: 'secret'
})

console.log('Authenticated', result.user)

// Make authenticated requests
const messages = await app.service('messages').find()
console.log(messages)

Build docs developers (and LLMs) love