Skip to content

Commit 71072c0

Browse files
committed
Avoid storing the encrypted oat token and its obfuscated version in the DB at all
It is a safer approach. Also we do not need to ever read the decrypted token value after creation.
1 parent e1135d5 commit 71072c0

File tree

3 files changed

+1
-57
lines changed

3 files changed

+1
-57
lines changed

apps/webapp/app/services/organizationAccessToken.server.ts

Lines changed: 1 addition & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
import { type OrganizationAccessToken } from "@trigger.dev/database";
21
import { customAlphabet } from "nanoid";
32
import { z } from "zod";
43
import { prisma } from "~/db.server";
54
import { logger } from "./logger.server";
6-
import { decryptToken, encryptToken, hashToken } from "~/utils/tokens.server";
7-
import { env } from "~/env.server";
5+
import { hashToken } from "~/utils/tokens.server";
86

97
const tokenValueLength = 40;
108
//lowercase only, removed 0 and l to avoid confusion
@@ -21,7 +19,6 @@ export async function getValidOrganizationAccessTokens(organizationId: string) {
2119
select: {
2220
id: true,
2321
name: true,
24-
obfuscatedToken: true,
2522
createdAt: true,
2623
lastAccessedAt: true,
2724
expiresAt: true,
@@ -36,7 +33,6 @@ export async function getValidOrganizationAccessTokens(organizationId: string) {
3633
return organizationAccessTokens.map((oat) => ({
3734
id: oat.id,
3835
name: oat.name,
39-
obfuscatedToken: oat.obfuscatedToken,
4036
createdAt: oat.createdAt,
4137
lastAccessedAt: oat.lastAccessedAt,
4238
expiresAt: oat.expiresAt,
@@ -63,12 +59,6 @@ export type OrganizationAccessTokenAuthenticationResult = {
6359
organizationId: string;
6460
};
6561

66-
const EncryptedSecretValueSchema = z.object({
67-
nonce: z.string(),
68-
ciphertext: z.string(),
69-
tag: z.string(),
70-
});
71-
7262
const AuthorizationHeaderSchema = z.string().regex(/^Bearer .+$/);
7363

7464
export async function authenticateApiRequestWithOrganizationAccessToken(
@@ -125,15 +115,6 @@ export async function authenticateOrganizationAccessToken(
125115
},
126116
});
127117

128-
const decryptedToken = decryptOrganizationAccessToken(organizationAccessToken);
129-
130-
if (decryptedToken !== token) {
131-
logger.error(
132-
`OrganizationAccessToken with id: ${organizationAccessToken.id} was found in the database with hash ${hashedToken}, but the decrypted token did not match the provided token.`
133-
);
134-
return;
135-
}
136-
137118
return {
138119
organizationId: organizationAccessToken.organizationId,
139120
};
@@ -149,14 +130,11 @@ export async function createOrganizationAccessToken({
149130
expiresAt,
150131
}: CreateOrganizationAccessTokenOptions) {
151132
const token = createToken();
152-
const encryptedToken = encryptToken(token, env.ENCRYPTION_KEY);
153133

154134
const organizationAccessToken = await prisma.organizationAccessToken.create({
155135
data: {
156136
name,
157137
organizationId,
158-
encryptedToken,
159-
obfuscatedToken: obfuscateToken(token),
160138
hashedToken: hashToken(token),
161139
expiresAt,
162140
},
@@ -167,7 +145,6 @@ export async function createOrganizationAccessToken({
167145
name,
168146
organizationId,
169147
token,
170-
obfuscatedToken: organizationAccessToken.obfuscatedToken,
171148
expiresAt: organizationAccessToken.expiresAt,
172149
};
173150
}
@@ -181,28 +158,3 @@ const tokenPrefix = "tr_oat_";
181158
function createToken() {
182159
return `${tokenPrefix}${tokenGenerator()}`;
183160
}
184-
185-
function obfuscateToken(token: string) {
186-
const withoutPrefix = token.replace(tokenPrefix, "");
187-
const obfuscated = `${withoutPrefix.slice(0, 4)}${"•".repeat(18)}${withoutPrefix.slice(-4)}`;
188-
return `${tokenPrefix}${obfuscated}`;
189-
}
190-
191-
function decryptOrganizationAccessToken(organizationAccessToken: OrganizationAccessToken) {
192-
const encryptedData = EncryptedSecretValueSchema.safeParse(
193-
organizationAccessToken.encryptedToken
194-
);
195-
if (!encryptedData.success) {
196-
throw new Error(
197-
`Unable to parse encrypted OrganizationAccessToken with id: ${organizationAccessToken.id}: ${encryptedData.error.message}`
198-
);
199-
}
200-
201-
const decryptedToken = decryptToken(
202-
encryptedData.data.nonce,
203-
encryptedData.data.ciphertext,
204-
encryptedData.data.tag,
205-
env.ENCRYPTION_KEY
206-
);
207-
return decryptedToken;
208-
}
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ CREATE TABLE "OrganizationAccessToken" (
44
"id" TEXT NOT NULL,
55
"name" TEXT NOT NULL,
66
"type" "OrganizationAccessTokenType" NOT NULL DEFAULT 'USER',
7-
"encryptedToken" JSONB NOT NULL,
8-
"obfuscatedToken" TEXT NOT NULL,
97
"hashedToken" TEXT NOT NULL,
108
"organizationId" TEXT NOT NULL,
119
"expiresAt" TIMESTAMP(3),

internal-packages/database/prisma/schema.prisma

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -147,12 +147,6 @@ model OrganizationAccessToken {
147147
/// Used to differentiate between user-generated and system-generated tokens
148148
type OrganizationAccessTokenType @default(USER)
149149
150-
/// This is the token encrypted using the ENCRYPTION_KEY
151-
encryptedToken Json
152-
153-
/// This is shown in the UI, with ********
154-
obfuscatedToken String
155-
156150
/// This is used to find the token in the database
157151
hashedToken String @unique
158152

0 commit comments

Comments
 (0)