diff --git a/core/fetch/src/fetch.ts b/core/fetch/src/fetch.ts index 671eb4fac..17a8d8d24 100644 --- a/core/fetch/src/fetch.ts +++ b/core/fetch/src/fetch.ts @@ -196,6 +196,10 @@ function _processOptions(options: FetchOptions): Required { options.headers.Authorization = `Bearer ${options.token}`; } + if (options.userAuth != null) { + options.headers.Authorization = `Bearer ${options.userAuth.id}/${options.userAuth.token}`; + } + return options as Required; } diff --git a/core/fetch/src/type.ts b/core/fetch/src/type.ts index c22c75ef9..f5dc95780 100644 --- a/core/fetch/src/type.ts +++ b/core/fetch/src/type.ts @@ -1,4 +1,4 @@ -import type {Methods, QueryParameters, StringifyableRecord} from '@alwatr/type'; +import type {Methods, QueryParameters, StringifyableRecord, UserAuth} from '@alwatr/type'; export type CacheStrategy = | 'network_only' @@ -102,6 +102,11 @@ export interface FetchOptions extends RequestInit { * Add token to Authentication bearer header. */ token?: string; + + /** + * Add user id and token to Authentication bearer header. + */ + userAuth?: UserAuth; } export type StringifyableFetchOptions = Pick< diff --git a/core/nano-server/src/nano-server.ts b/core/nano-server/src/nano-server.ts index 0c55f4279..9daf3d5fc 100644 --- a/core/nano-server/src/nano-server.ts +++ b/core/nano-server/src/nano-server.ts @@ -16,6 +16,7 @@ import type { ParamValueType, QueryParameters, StringifyableRecord, + UserAuth, } from '@alwatr/type'; import type {IncomingMessage, ServerResponse} from 'node:http'; import type {Duplex} from 'node:stream'; @@ -405,7 +406,7 @@ export class AlwatrConnection { /** * Get the token placed in the request header. */ - getToken(): string | null { + getAuthBearer(): string | null { const auth = this.incomingMessage.headers.authorization?.split(' '); if (auth == null || auth[0].toLowerCase() !== 'bearer') { @@ -497,10 +498,9 @@ export class AlwatrConnection { * ``` */ requireToken(validator?: ((token: string) => boolean) | Array | string): string { - const token = this.getToken(); + const token = this.getAuthBearer(); if (token == null) { - // eslint-disable-next-line no-throw-literal throw { ok: false, statusCode: 401, @@ -519,7 +519,6 @@ export class AlwatrConnection { else if (typeof validator === 'function') { if (validator(token) === true) return token; } - // eslint-disable-next-line no-throw-literal throw { ok: false, statusCode: 403, @@ -527,6 +526,27 @@ export class AlwatrConnection { }; } + /** + * Parse and get request user auth (include id and token). + * + * Example: + * ```ts + * const userAuth = connection.requireUserAuth(); + * ``` + */ + getUserAuth(): UserAuth | null { + const auth = this.getAuthBearer() + ?.split('/') + .filter((item) => item.trim() !== ''); + + return auth == null || auth.length !== 2 + ? null + : { + id: auth[0], + token: auth[1], + }; + } + /** * Parse query param and validate with param type. */