For web based applications, there are various authentication mechanisms available. To let your hapi server support a selected one, pick a plugin from the hapi ecosystem, provide the required configuration and you’re ready to go.
At some point, most of us hapi developers trap into an unknown authentication strategy <name> in <route-path>
error and didn’t realize why this occurs.
Actually, the fix is kind of straight forward. Read on to get the details!
hapi Series Overview
- What You’ll Build
- Prepare Your Project: Stack & Structure
- Environment Variables and Storing Secrets
- Set Up MongoDB and Connect With Mongoose
- Sending Emails in Node.js
- Load the User’s Profile Picture From Gravatar Using Virtuals in Mongoose
- Implement a User Profile Editing Screen
- Generate a Username in Mongoose Middleware
- Displaying Seasons and Episodes for TV Shows with Mongoose Relationship Population
- Implementing Pagination for Movies
- Implement a Watchlist
- Create a Full Text Search with MongoDB
- Create a REST API with JSON Endpoints
- Update Mongoose Models for JSON Responses
- API Pagination for TV Shows
- Customize API Endpoints with Query Parameters
- Always Throw and Handle API Validation Errors
- Advanced API Validation With Custom Errors
- Create an API Documentation with Swagger
- Customize Your Swagger API Documentation URL
- Describe Endpoint Details in Your Swagger API Documentation
- 10 Tips on API Testing With Postman
- JWT Authentication in Swagger API Documentation
- API Versioning with Request Headers
- API Login With Username and Password to Generate a JWT
- JWT Authentication and Private API Endpoints
- Refresh Tokens With JWT Authentication
- Create a JWT Utility
- JWT Refresh Token for Multiple Devices
- Check Refresh Token in Authentication Strategy
- Rate Limit Your Refresh Token API Endpoint
- How to Revoke a JWT
- Invalidate JWTs With Blacklists
- JWT Logout (Part 1/2)
- JWT “Immediate” Logout (Part 2/2)
- A Better Place to Invalidate Tokens
- How to Switch the JWT Signing Algorithm
- Roll Your Own Refresh Token Authentication Scheme
- JWT Claims 101
- Use JWT With Asymmetric Signatures (RS256 & Co.)
- Encrypt the JWT Payload (The Simple Way)
- Increase JWT Security Beyond the Signature
- Unsigned JSON Web Tokens (Unsecured JWS)
- JWK and JWKS Overview
- Provide a JWKS API Endpoint
- Create a JWK from a Shared Secret
- JWT Verification via JWKS API Endpoint
- What is JOSE in JWT
- Encrypt a JWT (the JWE Way)
- Authenticate Encrypted JWTs (JWE)
- Encrypted and Signed JWT (Nested JWT)
- Bringing Back JWT Decoding and Authentication
- Bringing Back JWT Claims in the JWT Payload
- Basic Authentication With Username and Password
- Authentication and Remember Me Using Cookies
- How to Set a Default Authentication Strategy
- Define Multiple Authentication Strategies for a Route
- Restrict User Access With Scopes
- Show „Insufficient Scope“ View for Routes With Restricted Access
- Access Restriction With Dynamic and Advanced Scopes
- hapi - How to Fix „unknown authentication strategy“
- Authenticate with GitHub And Remember the Login
- Authenticate with GitLab And Remember the User
- How to Combine Bell With Another Authentication Strategy
- Custom OAuth Bell Strategy to Connect With any Server
- Redirect to Previous Page After Login
- How to Implement a Complete Sign Up Flow With Email and Password
- How to Implement a Complete Login Flow
- Implement a Password-Reset Flow
- Views in hapi 9 (and above)
- How to Render and Reply Views
- How to Reply and Render Pug Views (Using Pug 2.0)
- How to Create a Dynamic Handlebars Layout Template
- Create and Use Handlebars Partial Views
- Create and Use Custom Handlebars Helpers
- Specify a Different Handlebars Layout for a Specific View
- How to Create Jade-Like Layout Blocks in Handlebars
- Use Vue.js Mustache Tags in Handlebars Templates
- How to Use Multiple Handlebars Layouts
- How to Access and Handle Request Payload
- Access Request Headers
- How to Manage Cookies and HTTP States Across Requests
- Detect and Get the Client IP Address
- How to Upload Files
- Quick Access to Logged In User in Route Handlers
- How to Fix “handler method did not return a value, a promise, or throw an error”
- How to Fix “X must return an error, a takeover response, or a continue signal”
- Query Parameter Validation With Joi
- Path Parameter Validation With Joi
- Request Payload Validation With Joi
- Validate Query and Path Parameters, Payload and Headers All at Once on Your Routes
- Validate Request Headers With Joi
- Reply Custom View for Failed Validations
- Handle Failed Validations and Show Errors Details at Inputs
- How to Fix AssertionError, Cannot validate HEAD or GET requests
The Problem
Independent of your app’s authentication strategy, the following error stack trace probably feels familiar:
$ node server.js
/Users/marcuspoehls/Dev/JS/nodejs-tutorials-hapi/node_modules/hapi/node_modules/hoek/lib/index.js:736
throw new Error(msgs.join(' ') || 'Unknown error');
^
Error: Unknown authentication strategy session in /
at Object.exports.assert (/Users/marcuspoehls/Dev/JS/nodejs-tutorials-hapi/node_modules/hapi/node_modules/hoek/lib/index.js:736:11)
…
In essence, the defined authentication strategy called session
is not available for the route with path /
. Now you might think that you’re creating the session
strategy in your project and hapi still can’t find it. So what’s the issue?
The Solution(s)
The actual problem is that the session
strategy is created too late. A route that requires the session
strategy is registered before session
is known to the server.
Now that you know the problem (a strategy not created when the route with related authentication scheme should be registered), you can put your solution in place. Depending on your application setup, there are different approaches on how to implement the solution.
Create a Dedicated Authentication Plugin
Composing your application with individual plugins is the recommended way in hapi. If you’re already splitting the different parts of your apps into separate plugins, there’s a straightforward way to fix the problem: create a dedicated authentication
plugin.
Create the Plugin
The following snippet illustrates the authentication
plugin by using the hapi-auth-cookie
dependency to create the session
strategy.
Let’s name the following snippet authentication.js
, so we can easily refer to it:
authentication.js
const Hoek = require('hoek')
async function register (server, options) {
// register dependency to hapi-auth-cookie
// and make sure it’s available to this plugin
await server.register({
plugin: require('hapi-auth-cookie')
})
// configure the "session" strategy
server.auth.strategy('session', 'cookie', {
password: 'ThisIsASecretPasswordForTheAuthCookie',
redirectTo: '/',
isSecure: process.env.NODE_ENV === 'production'
})
}
exports.plugin = {
register,
name: 'authentication',
version: '1.0.0',
once: true
}
The code snippet above uses the hapi-auth-cookie
module as a dependency. Also, this specific authentication
plugin (see the plugin’s name attribute) registers its dependencies itself. Please make sure you don’t register the hapi-auth-cookie
twice to your hapi server, then you’ll get an error.
Notice the once: true
within the plugin’s attributes. This configuration tells hapi to register this plugin only once on the same server.
What about server.dependency
?
Did you think about using server.dependency([ 'hapi-auth-cookie' ])
to declare the dependency between authentication
and hapi-auth-cookie
(or further plugins)?
Sadly, hapi doesn’t make sure that plugins are registered in order and therefore you need to make sure the hapi-auth-cookie
plugin is definitely registered before authentication
should be plugged into your server.
Now that you’ve set the dependency within your authentication
plugin, go ahead and create the session
strategy based on the cookie
scheme. You need to do that within the callback function of server.register()
.
With the call of next()
, hapi knows that your plugin is registered and the next one can be processed.
Use Authentication Plugin in Your App
In your plugins that require authentication and specifically the session
strategy, register the authentication
plugin (from the code block above) as a dependency.
The authentication
plugin is your custom one (from the code block above, which we named authentication.js
). Of course, you can name it whatever you want :)
Let’s name the following snippet your-plugin.js
to get a reference within this tutorial.
your-plugin.js
async function register (server, options) {
await server.register([
{
register: require('./path/to/authentication')
}
{
register: require('vision') // if you want view rendering support
},
])
// your plugin logic goes here
// like "server.route(yourRoutes)"
// tell hapi it’s safe to process the next plugin :)
}
Within your application plugins that rely on the authentication
plugin as a dependency, make sure you install it. The once: true
attribute of authentication
makes sure hapi only registers the plugin once for the same server.
Having the dependencies installed, do your individual configuration, add routes, extend the request lifecycle, etc.
Register Plugins to Your Server
The dedicated authentication
plugin is a requirement for other plugins. Individual plugins should make sure their dependencies are installed by doing it themselves.
That’s why you only need to register your “main” plugins and they individually handle their dependencies themselves.
const Hapi = require('hapi')
const server = new Hapi.Server()
// register plugins to server instance
async function liftOff () {
server.register([
{
plugin: require('./path/to/your-plugin')
},
{
plugin: require('./path/to/another-plugin')
},
{
plugin: require('./path/to/the-fancy-funky-plugin')
}
])
try {
await server.start()
console.log('Server running at: ' + server.info.uri)
} catch (err) {
console.log(err)
process.exit(1)
}
}
liftOff()
Not Using Plugins: Ensure a Server Composition Flow
If you don’t compose your hapi app with individual plugins, make sure that you register the used plugins (e.g., vision
, inert
, etc.) first. Then create the authentication strategies, set the view configuration or do everything else you want to use in your routes.
Having the plugins registered, views configured or authentication in place, register all your routes to the hapi server instance. Adding the routes to the hapi server with (all batteries included) should go well.
Outlook
In this tutorial you’ve learned how to fix the actual problem for the „unknown authentication strategy“ error. This error occurs, because the given strategy is not available to the server yet while a route should be added and requires the strategy.
Solve this problem by creating a dedicated authentication plugin that can be defined as a dependency for your individual application plugins. If you don’t use plugins to compose your app, make sure your application flow follows the correct path of registering dependencies first, configure the authentication strategies and than add routes.
Want to learn more on how to access and handle the request payload in hapi? The linked tutorial is for you!
We’re happy to hear your thoughts and comments. Please don’t hesitate to use the comments below or find us on Twitter @futurestud_io. Let us know what you think!
Enjoy coding & make it rock!