Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auth package documentation #424

Merged
merged 4 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/auth/src/context/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ import {
import { LoginGov } from '../provider.js';
import { type AuthRepository } from '../repository/index.js';

/**
* The `BaseAuthContext` class implements the `AuthServiceContext` interface,
* providing an authentication context for user sessions and database interactions.
* It integrates with a repository for database operations, a third-party login provider,
* and various utilities for managing cookies and user sessions.
*/
export class BaseAuthContext implements AuthServiceContext {
private lucia?: Lucia;

Expand Down
16 changes: 12 additions & 4 deletions packages/auth/src/lucia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,28 @@ import { Lucia } from 'lucia';

import { type Database } from '@atj/database';

/**
* Factory function to create a SQLite Lucia adapter.
*
* @param {Sqlite3Database} db - The SQLite3 database instance used to initialize the adapter.
*/
export const createSqliteLuciaAdapter = (db: Sqlite3Database) => {
const adapter = new BetterSqlite3Adapter(db, {
return new BetterSqlite3Adapter(db, {
user: 'users',
session: 'sessions',
});
return adapter;
};

/**
* Factory function to create a Postgres Lucia adapter.
*
* @param {Sqlite3Database} pgPool - The SQLite3 database instance used to initialize the adapter.
*/
export const createPostgresLuciaAdapter = (pgPool: any) => {
const adapter = new NodePostgresAdapter(pgPool, {
return new NodePostgresAdapter(pgPool, {
user: 'users',
session: 'sessions',
});
return adapter;
};

declare module 'lucia' {
Expand Down
5 changes: 5 additions & 0 deletions packages/auth/src/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ export type LoginGovOptions = {
redirectURI?: string;
};

/**
* The LoginGov class implements the OAuth2ProviderWithPKCE interface
* and provides functionality to authenticate users using Login.gov's
* OAuth 2.0 with PKCE flow.
*/
export class LoginGov implements OAuth2ProviderWithPKCE {
private client: OAuth2Client;
//private clientSecret: string;
Expand Down
7 changes: 6 additions & 1 deletion packages/auth/src/repository/create-session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ type Session = {
userId: string;
};

/**
* Asynchronously creates a new session in the database.
*
* @param {DatabaseContext} ctx - The database context used to manage the connection and provide access to the database engine.
* @param {Session} session - The session data to be inserted, containing properties such as id, expiration time, session token, and user id.
*/
export const createSession = async (ctx: DatabaseContext, session: Session) => {
const db = await ctx.getKysely();
const result = await db.transaction().execute(async trx => {
Expand All @@ -17,7 +23,6 @@ export const createSession = async (ctx: DatabaseContext, session: Session) => {
expires_at: dateValue(ctx.engine, session.expiresAt),
session_token: session.sessionToken,
user_id: session.userId,
//...session.attributes,
})
.execute();
});
Expand Down
6 changes: 6 additions & 0 deletions packages/auth/src/repository/create-user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ import { randomUUID } from 'crypto';

import { type DatabaseContext } from '@atj/database';

/**
* Asynchronously creates a new user record in the database.
*
* @param {DatabaseContext} ctx - The database context used to interact with the database.
* @param {string} email - The email address of the user to be created.
*/
export const createUser = async (ctx: DatabaseContext, email: string) => {
const id = randomUUID();

Expand Down
6 changes: 6 additions & 0 deletions packages/auth/src/repository/get-user-id.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { type DatabaseContext } from '@atj/database';

/**
* Retrieves the unique identifier (ID) of a user based on their email address.
*
* @param {DatabaseContext} ctx - The database context used to establish a connection and perform the query.
* @param {string} email - The email address of the user whose ID is to be retrieved.
*/
export const getUserId = async (ctx: DatabaseContext, email: string) => {
const db = await ctx.getKysely();
const user = await db.transaction().execute(trx => {
Expand Down
11 changes: 11 additions & 0 deletions packages/auth/src/repository/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ import { createSession } from './create-session.js';
import { createUser } from './create-user.js';
import { getUserId } from './get-user-id.js';

/**
* Factory function to create an authentication repository.
*
* @param {DatabaseContext} ctx - The database context used for initializing the repository.
* @returns Returns an authentication service object with methods to handle user authentication and management.
*
* The returned service object provides the following methods:
* - `createSession`
* - `createUser`
* - `getUserId`
*/
export const createAuthRepository = (ctx: DatabaseContext) =>
createService(ctx, {
createSession,
Expand Down
8 changes: 8 additions & 0 deletions packages/auth/src/services/get-provider-redirect.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { generateCodeVerifier, generateState } from 'arctic';
import { type AuthServiceContext } from './index.js';

/**
* Asynchronously generates a redirection URL for an OAuth authorization request and associated cookies.
*
* This function interacts with the provided authentication service context to create an authorization
* URL, including necessary state and verification parameters for security measures.
*
* @param {AuthServiceContext} ctx - The authentication service context used to interact with the provider.
*/
export const getProviderRedirect = async (ctx: AuthServiceContext) => {
const state = generateState();
const codeVerifier = generateCodeVerifier();
Expand Down
5 changes: 5 additions & 0 deletions packages/auth/src/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ export type AuthServiceContext = {
isUserAuthorized: (email: string) => Promise<boolean>;
};

/**
* Factory function to create an authentication service.
*
* @param {AuthServiceContext} ctx - The context required to initialize the authentication service.
*/
export const createAuthService = (ctx: AuthServiceContext) =>
createService(ctx, {
getProviderRedirect,
Expand Down
9 changes: 7 additions & 2 deletions packages/auth/src/services/logout.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { type Session } from 'lucia';
import { type AuthServiceContext } from './index.js';

/**
* Logs out a user by invalidating their existing session and creating a blank session cookie.
*
* @param {AuthServiceContext} ctx - The authentication service context.
* @param {Session} session - The session object to be invalidated.
*/
export const logOut = async (ctx: AuthServiceContext, session: Session) => {
const lucia = await ctx.getLucia();
await lucia.invalidateSession(session.id);
const sessionCookie = lucia.createBlankSessionCookie();
return sessionCookie;
return lucia.createBlankSessionCookie();
};
14 changes: 14 additions & 0 deletions packages/auth/src/services/process-provider-callback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ type Params = {
state?: string | null;
};

/**
* Processes the provider callback for an OAuth-based authentication flow. Ensures data integrity and security through checks like nonce matching,
* state validation, and proper error handling.
*
* @param {AuthServiceContext} ctx - The context object containing authentication services, database access, and related utilities.
* @param {Params} params - The parameters received from the provider as part of the callback request.
* @param {Params & { nonce: string | null }} storedParams - Locally stored parameters including the nonce for verification and validation.
* @param {function} [fetchUserData=fetchUserDataImpl] - A function to fetch user data from the external provider using the access token.
*/
export const processProviderCallback = async (
ctx: AuthServiceContext,
params: Params,
Expand Down Expand Up @@ -91,6 +100,11 @@ export const processProviderCallback = async (
});
};

/**
* Fetches user data from the login-provider endpoint using the provided access token with bearer token auth.
*
* @param {string} accessToken - The access token to authorize the request.
*/
const fetchUserDataImpl = (accessToken: string) =>
fetch('https://idp.int.identitysandbox.gov/api/openid_connect/userinfo', {
headers: {
Expand Down
10 changes: 10 additions & 0 deletions packages/auth/src/services/process-session-cookie.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ import { type VoidResult } from '@atj/common';

import { type AuthServiceContext } from './index.js';

/**
* Processes the session cookie in the context of an authentication request.
* This function validates the session cookie from the incoming request and
* sets the appropriate user session in the given context. It checks the
* request's origin for security and handles session expiration or invalidation
* by creating blank session cookies when necessary.
*
* @param {AuthServiceContext} ctx - The authentication service context used to manage sessions and cookies.
* @param {Request} request - The incoming HTTP request object containing session and origin information.
*/
export const processSessionCookie = async (
ctx: AuthServiceContext,
request: Request
Expand Down
Loading