whodis-sdk
A simple sdk for easy, secure, best practices authentication with the whodis platform.
Setup and manage secure authentication for your app in seconds.
install
npm install --save whodis-sdk
examples
getAuthedClaimsFromHeaders
to securely get authenticated claims from headers containing a whodis auth token
import { getAuthedClaimsFromHeaders } from 'whodis-sdk';
const claims = await getAuthedClaimsFromHeaders({
headers: event.headers,
config: {
issuer: config.whodis.directory.issuer,
audience: config.whodis.directory.audience,
},
log
});
const userUuid = claims?.sub ?? null; // this is the userUuid that you can use to uniquely identify your users
note: assumes that the token was issued by whodis
and managed on the client by either whodis-client
or whodis-react
.
getUser
to lookup a user's data by uuid
import { getUser } from 'whodis-sdk';
const user = await getUser(
{
userUuid: string,
},
{
credentials: {
publicKey: config.whodis.api.publicKey,
privateKey: config.whodis.api.privateKey,
},
},
);
addUserContactMethod
to lookup a user's data by uuid
import { addUserContactMethod } from 'whodis-sdk';
const user = await addUserContactMethod(
{
userUuid: string,
contactMethod: {
type: 'EMAIL' | 'PHONE',
address: string,
}
},
{
credentials: {
publicKey: config.whodis.api.publicKey,
privateKey: config.whodis.api.privateKey,
},
},
);
docs
getAuthedClaimsFromHeaders({ headers, config, log })
getAuthedClaimsFromHeaders
extracts authenticated claims from the auth token found in the headers, if any exist. Additionally, it monitors authentication errors to proactively help with debugging and detect potential security attacks.
Operation:
- if there is no auth token in the headers, the function returns
null
- if there is an auth token and it can not be authenticated, the error will be logged, reported, and the function returns
null
- if there is an auth token and it is successfully authenticated, the function will return the token claims
const claims = await getAuthedClaimsFromHeaders({
// the headers hold the auth token well be authing
headers,
// the config provides the keys required to complete a secure authentication of a JWT
config: {
issuer: 'https://auth.whodis.io/__yourdirectoryuuid__', // must match up exactly with what is present on the token, to verify that the token was from the intended authority
audience: 'https://api.__yourwebsite__.com', // must match up exactly with what is present on the token, to verify the token was intended for you
},
// the log methods allow you to monitor authentication errors
log: {
warn: (message: string, metadata: Record<string, string>) => console.log(message, metadata), // replace this with your favorite log method
},
});
nuances
cookie based authentication
If your users are interacting with your app through the browser, there is no choice but to use cookie based token storage for security (due to all data accessible by JS being vulnerable to XSS).
Fortunately for us, browsers make it really challenging to work with cookies. A combination of CORS and Cookie security standards results in a very fine line of how your preflight-request responses have to look like in order for the cookie to be sent and the browser not to throw an error at the request.
Specifically:
- your client has to make the request with the flag
{ credentials: 'include' }
- your server's preflight response has to include the header
access-control-allow-credentials: true
- your server's preflight response has to include the header
access-control-allow-headers: content-type,authorization
- your server's preflight response has to include the header
access-control-allow-origin: __YOUR_WEBSITES_ORIGIN__
- where
__YOUR_WEBSITES_ORIGIN__
is the full origin uri listed in the request header by the browser (e.g.,https://www.yourdomain.com
)
- where
Typically, this is done by setting up a custom route that responds specifically to the OPTIONS
method on all paths of the api. (The OPTIONS
method is called by browsers in the preflight requests that browsers check the above settings with).
For example, if you are working with the serverless
framework you can setup an HTTP api gateway that handles all options requests with the following:
corsPreflightResponse:
handler: dist/contract/handlers/corsPreflightResponse.handler
events:
- httpApi:
method: OPTIONS
path: /user/{proxy+}
with the code of the handler as follows:
import Joi from 'joi';
import { createApiGatewayHandler } from 'simple-lambda-handler';
export const CORS_SETTINGS = {
// define each origin website that you want to support here (or set `origins: '*'` if you want to support all origins)
origins: ['https://www.yourwebsite.com', 'https://localhost.yourwebsite.com:3443'], // for example, support the main website and a localhost variant
// define that this server supports credentials
withCredentials: true, // with credentials, since tokens come in cookies from browser
};
// return a successful response each time
const handle = async (): Promise<{ statusCode: 200; headers?: any; body: undefined }> => {
return {
statusCode: 200,
body: undefined,
};
};
// export the handler
export const handler = createApiGatewayHandler({
log,
schema: Joi.object().unknown(true), // allow any input shape
logic: handle,
cors: CORS_SETTINGS,
});