Welcome to Onyx!
Onyx is authentication middleware for Deno, inspired by Passport.js. Like Passport, Onyx prioritizes modularization and flexibility — it abstracts much of the authentication process away yet leaves exact control of the verification procedure up to the developer.
Onyx’s primary concern is keeping code clean and organized. Through the use of specialized instructions called strategies, which are held in individual modules, you can streamline your authentication process without importing unnecessary dependencies.
All you need is one line to get started.
import Onyx from
When you import the Onyx module, what you’re really importing is an object called ‘Onyx’ that has a number of built-in methods. A couple of those methods you will need to use as Oak middleware to use Onyx. Others are primarily used by Onyx under the hood to assist with the authentication process. However, if you are a developer interested in creating new or custom strategies for Onyx, it will likely be important to understand how these work.
Where to Start
First, though, let’s go over Onyx’s most vital methods: onyx.use()
, onyx.authenticate()
and onyx.initialize()
.
onyx.use
onyx.use()
configures and stores a strategy to to be implemented later on by Onyx. This step must be completed first in order to continue authentication process. After all, without a strategy, Onyx doesn’t have anything to use to complete the authentication process.
onyx.use(
new LocalStrategy(
async (username: string, password: string, done: Function) => {
// const { username, password } = context.state.onyx.user;
console.log(
`verify function invoked with username <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>u</mi><mi>s</mi><mi>e</mi><mi>r</mi><mi>n</mi><mi>a</mi><mi>m</mi><mi>e</mi></mrow><mi>a</mi><mi>n</mi><mi>d</mi><mi>p</mi><mi>a</mi><mi>s</mi><mi>s</mi><mi>w</mi><mi>o</mi><mi>r</mi><mi>d</mi></mrow><annotation encoding="application/x-tex">{username} and password </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal">u</span><span class="mord mathnormal" style="margin-right:0.02778em;">ser</span><span class="mord mathnormal">nam</span><span class="mord mathnormal">e</span></span><span class="mord mathnormal">an</span><span class="mord mathnormal">d</span><span class="mord mathnormal">p</span><span class="mord mathnormal">a</span><span class="mord mathnormal">ss</span><span class="mord mathnormal" style="margin-right:0.02691em;">w</span><span class="mord mathnormal" style="margin-right:0.02778em;">or</span><span class="mord mathnormal">d</span></span></span></span>{password}`
);
try {
const user = await User.findOne({ username });
if (user && password === user.password) await done(null, user);
else await done(null);
} catch (error) {
await done(error);
}
}
)
);
To be clear, the developer must provide the user verification callback that the strategy will use, so that it will work for your particular application.
onyx.authenticate
onyx.authenticate()
is the heart of Onyx — it’s what you will use to initiate an authenticate process.
When you want to authenticate a user, simply invoke onyx.authenticate()
and pass in a reference to the strategy you stored with onyx.use()
above.
onyx.authenticate('local');
onyx.initialize
As you might expect, onyx.initialize()
creates a new instance of Onyx for each user and sets up its initial state. Though it’s a simple line of code, it is vital for ensuring Onyx autehnticates each individual user properly.
app.use(onyx.initialize());
Because a new instance should be created for each user, in this example, we are using Oak’s app.use()
function, which will invoke onyx.initialize()
when a user makes an initial get request to the website/application.
Serialization and Deserialization
Use the following two functions if you are creating persistent sessions for your users.
onyx.serializeUser
Similar to onyx.use()
, onyx.serializeUser()
stores a callback that will be invoked later upon successful verification and authentication. This callback should serialize and store user information in some sort of session database.
onyx.serializeUser(async function (user: any, cb: Function) {
await cb(null, user._id.$oid);
});
Once again, the developer must provide the serializer callback that serializeUser()
will store.
onyx.deserializeUser
Stores a callback you write that will be invoked later upon successful verification and authentication. This callback should deserialize user information, checking to see if the user has an existing session. If so, it should then grab the relevant user data from wherever you stored it.
onyx.deserializeUser(async function (id: string, cb: Function) {
const _id = { $oid: id };
try {
const user = await User.findOne({ _id });
await cb(null, user);
} catch (error) {
await cb(error, null);
}
});
And yes, the developer must provide the deserializer callback that deserializeUser()
will store.
Digging Deeper
While the following methods are not required to authenticate with Onyx, you may find them useful to understand if you are creating a custom strategy.
onyx.unuse
onyx.unuse()
does exactly what it sounds like it does: It deletes the strategy you stored when using onyx.use()
.
onyx.unuse('local')
onyx.init
onyx.init()
is invoked every time a new instance of an Onyx object is created — it’s actually in Onyx’s constructor, so you probably won’t have to worry about calling it yourself.
It creates an instance of the session manager, which controls and creates user sessions.
Developed by
Connie Cho, Alice Fu, Chris Kopcow, George Kruchinina and Cedric Lee
Logo by Amanda Maduri