import { ClientOptions, Logger } from './types' // TODO - remove this if/when we decide to abandon this idea. // There's some WIP/research commented out here that could be used for building adapters for auth0/okta/cognito/etc // using a common interface (similar to redwoodjs's auth solution). Could be cool, but not sure it's worth the effort at // this point. // // Not using any of this for now in favor of simple getCredentials option. Better not to maintain auth state // internally until we're sure we can provide a nice abstraction for it. export interface AuthStateChangeEvent { type: 'LOGGED_IN' | 'LOGGED_OUT' | 'SET_TOKEN' | 'ERROR' token?: string | null } // Just sketching out idea for now. export interface AuthAdapter { login: ({ username, password }: { username: string; password: string }) => Promise<{ accessToken: string }> logout: () => Promise getUser: () => Promise isAuthenticated: () => Promise } export const createAuth = (options: ClientOptions, { _logger }: { _logger: Logger }) => { const _onAuthStateChangeCallbacks = [] as ((event: AuthStateChangeEvent) => void)[] function _fireAuthStateChangedCallbacks(event: AuthStateChangeEvent) { _onAuthStateChangeCallbacks.forEach((callback) => callback(event)) } function _onAuthStateChange(callback: (event: AuthStateChangeEvent) => void) { _onAuthStateChangeCallbacks.push(callback) } // Update type when there is more than one provider and we know what the interface should be // @eslint-disable-next-line let authAdapter: AuthAdapter | null // if (options?.auth?.provider === 'VENDIA_USER') { // authAdapter = getVendiaUserAuth({ _logger }) // } const auth = { login: async ({ username, password }: { username: string; password: string }) => { if (authAdapter === null) { throw new Error('auth.provider must be set via options to use this method.') } _logger('Logging in...') const tokens = await authAdapter.login({ username, password }) _fireAuthStateChangedCallbacks({ type: 'SET_TOKEN', token: tokens.accessToken }) _fireAuthStateChangedCallbacks({ type: 'LOGGED_IN' }) }, logout: () => { if (authAdapter === null) { throw new Error('auth.provider must be set via options to use this method.') } _logger('Logging out...') authAdapter.logout() _fireAuthStateChangedCallbacks({ type: 'SET_TOKEN', token: null }) _fireAuthStateChangedCallbacks({ type: 'LOGGED_OUT' }) }, getUser: () => { if (authAdapter === null) { throw new Error('auth.provider must be set via options to use this method.') } _logger('Getting user...') return authAdapter.getUser() }, isAuthenticated: () => { if (authAdapter === null) { throw new Error('auth.provider must be set via options to use this method.') } _logger('Checking if authenticated...') return authAdapter.isAuthenticated() }, onAuthStateChange: _onAuthStateChange, /** * Set a JWT token to use with Vendia's Custom JWT auth option * @param token - the JWT access token created by your auth provider. Do not add the "Bearer" prefix to the token. */ setToken: (token: string | null) => { _fireAuthStateChangedCallbacks({ type: 'SET_TOKEN', token }) }, } return { // Internal _onAuthStateChange: _onAuthStateChange, // Public auth, } }