aboutsummaryrefslogtreecommitdiff
path: root/src/lib/auth.ts
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-01-24 13:09:50 +0000
committerFuwn <[email protected]>2026-01-24 13:09:50 +0000
commit396acf3bbbe00a192cb0ea0a9ccf91b1d8d2850b (patch)
treeb9df4ca6a70db45cfffbae6fdd7252e20fb8e93c /src/lib/auth.ts
downloadumami-main.tar.xz
umami-main.zip
Initial commitHEADmain
Created from https://vercel.com/new
Diffstat (limited to 'src/lib/auth.ts')
-rw-r--r--src/lib/auth.ts80
1 files changed, 80 insertions, 0 deletions
diff --git a/src/lib/auth.ts b/src/lib/auth.ts
new file mode 100644
index 0000000..ba6d8b0
--- /dev/null
+++ b/src/lib/auth.ts
@@ -0,0 +1,80 @@
+import debug from 'debug';
+import { ROLE_PERMISSIONS, ROLES, SHARE_TOKEN_HEADER } from '@/lib/constants';
+import { secret } from '@/lib/crypto';
+import { getRandomChars } from '@/lib/generate';
+import { createSecureToken, parseSecureToken, parseToken } from '@/lib/jwt';
+import redis from '@/lib/redis';
+import { ensureArray } from '@/lib/utils';
+import { getUser } from '@/queries/prisma/user';
+
+const log = debug('umami:auth');
+
+export function getBearerToken(request: Request) {
+ const auth = request.headers.get('authorization');
+
+ return auth?.split(' ')[1];
+}
+
+export async function checkAuth(request: Request) {
+ const token = getBearerToken(request);
+ const payload = parseSecureToken(token, secret());
+ const shareToken = await parseShareToken(request);
+
+ let user = null;
+ const { userId, authKey } = payload || {};
+
+ if (userId) {
+ user = await getUser(userId);
+ } else if (redis.enabled && authKey) {
+ const key = await redis.client.get(authKey);
+
+ if (key?.userId) {
+ user = await getUser(key.userId);
+ }
+ }
+
+ log({ token, payload, authKey, shareToken, user });
+
+ if (!user?.id && !shareToken) {
+ log('User not authorized');
+ return null;
+ }
+
+ if (user) {
+ user.isAdmin = user.role === ROLES.admin;
+ }
+
+ return {
+ token,
+ authKey,
+ shareToken,
+ user,
+ };
+}
+
+export async function saveAuth(data: any, expire = 0) {
+ const authKey = `auth:${getRandomChars(32)}`;
+
+ if (redis.enabled) {
+ await redis.client.set(authKey, data);
+
+ if (expire) {
+ await redis.client.expire(authKey, expire);
+ }
+ }
+
+ return createSecureToken({ authKey }, secret());
+}
+
+export async function hasPermission(role: string, permission: string | string[]) {
+ return ensureArray(permission).some(e => ROLE_PERMISSIONS[role]?.includes(e));
+}
+
+export function parseShareToken(request: Request) {
+ try {
+ return parseToken(request.headers.get(SHARE_TOKEN_HEADER), secret());
+ } catch (e) {
+ log(e);
+ return null;
+ }
+}