Skip to content

Commit d0830fa

Browse files
committed
Add warnOnInsecureuserIdentifierKey
1 parent e74e613 commit d0830fa

24 files changed

+108
-0
lines changed

generate-routes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ import type {
240240
} from '@seamapi/types/connect'
241241
import type { SetNonNullable } from 'type-fest'
242242
243+
import { warnOnInsecureuserIdentifierKey } from './auth.js'
243244
import {
244245
type Client,
245246
type ClientOptions,

src/lib/seam/connect/auth.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ const getAuthHeadersForApiKey = ({
4646
)
4747
}
4848

49+
if (isPublishableKey(apiKey)) {
50+
throw new SeamHttpInvalidTokenError(
51+
'A Publishable Key cannot be used as an apiKey',
52+
)
53+
}
54+
4955
if (!isSeamToken(apiKey)) {
5056
throw new SeamHttpInvalidTokenError(
5157
`Unknown or invalid apiKey format, expected token to start with ${tokenPrefix}`,
@@ -72,6 +78,12 @@ const getAuthHeadersForClientSessionToken = ({
7278
)
7379
}
7480

81+
if (isPublishableKey(clientSessionToken)) {
82+
throw new SeamHttpInvalidTokenError(
83+
'A Publishable Key cannot be used as a clientSessionToken',
84+
)
85+
}
86+
7587
if (!isClientSessionToken(clientSessionToken)) {
7688
throw new SeamHttpInvalidTokenError(
7789
`Unknown or invalid clientSessionToken format, expected token to start with ${clientSessionTokenPrefix}`,
@@ -85,6 +97,30 @@ const getAuthHeadersForClientSessionToken = ({
8597
}
8698

8799
const getAuthHeadersForPublishableKey = (publishableKey: string): Headers => {
100+
if (isJwt(publishableKey)) {
101+
throw new SeamHttpInvalidTokenError(
102+
'A JWT cannot be used as a publishableKey',
103+
)
104+
}
105+
106+
if (isAccessToken(publishableKey)) {
107+
throw new SeamHttpInvalidTokenError(
108+
'An Access Token cannot be used as a publishableKey',
109+
)
110+
}
111+
112+
if (isClientSessionToken(publishableKey)) {
113+
throw new SeamHttpInvalidTokenError(
114+
'A Client Session Token Key cannot be used as a publishableKey',
115+
)
116+
}
117+
118+
if (!isPublishableKey(publishableKey)) {
119+
throw new SeamHttpInvalidTokenError(
120+
`Unknown or invalid publishableKey format, expected token to start with ${publishableKeyTokenPrefix}`,
121+
)
122+
}
123+
88124
return {
89125
'seam-publishable-key': publishableKey,
90126
}
@@ -98,10 +134,29 @@ export class SeamHttpInvalidTokenError extends Error {
98134
}
99135
}
100136

137+
export const warnOnInsecureuserIdentifierKey = (
138+
userIdentifierKey: string,
139+
): void => {
140+
if (isEmail(userIdentifierKey)) {
141+
// eslint-disable-next-line no-console
142+
console.warn(
143+
...[
144+
'Using an email for the userIdentifierKey is insecure and may return an error in the future!',
145+
'This is insecure because an email is common knowledge or easily guessed.',
146+
'Use something with sufficient entropy known only to the owner of the client session.',
147+
'For help choosing a user identifier key see',
148+
'https://docs.seam.co/latest/seam-components/overview/get-started-with-client-side-components#3-select-a-user-identifier-key',
149+
],
150+
)
151+
}
152+
}
153+
101154
const tokenPrefix = 'seam_'
102155

103156
const clientSessionTokenPrefix = 'seam_cst'
104157

158+
const publishableKeyTokenPrefix = 'seam_pk'
159+
105160
const isClientSessionToken = (token: string): boolean =>
106161
token.startsWith(clientSessionTokenPrefix)
107162

@@ -110,3 +165,10 @@ const isAccessToken = (token: string): boolean => token.startsWith('seam_at')
110165
const isJwt = (token: string): boolean => token.startsWith('ey')
111166

112167
const isSeamToken = (token: string): boolean => token.startsWith(tokenPrefix)
168+
169+
const isPublishableKey = (token: string): boolean =>
170+
token.startsWith(publishableKeyTokenPrefix)
171+
172+
// SOURCE: https://stackoverflow.com/a/46181
173+
const isEmail = (value: string): boolean =>
174+
/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)

src/lib/seam/connect/routes/access-codes-unmanaged.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
} from 'lib/seam/connect/options.js'
2424
import { parseOptions } from 'lib/seam/connect/parse-options.js'
2525

26+
import { warnOnInsecureuserIdentifierKey } from './auth.js'
2627
import { SeamHttpClientSessions } from './client-sessions.js'
2728

2829
export class SeamHttpAccessCodesUnmanaged {
@@ -74,6 +75,7 @@ export class SeamHttpAccessCodesUnmanaged {
7475
userIdentifierKey: string,
7576
options: ClientOptions = {},
7677
): Promise<SeamHttpAccessCodesUnmanaged> {
78+
warnOnInsecureuserIdentifierKey(userIdentifierKey)
7779
const clientOptions = parseOptions({ ...options, publishableKey })
7880
const client = createClient(clientOptions)
7981
const clientSessions = SeamHttpClientSessions.fromClient(client)

src/lib/seam/connect/routes/access-codes.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
import { parseOptions } from 'lib/seam/connect/parse-options.js'
2525

2626
import { SeamHttpAccessCodesUnmanaged } from './access-codes-unmanaged.js'
27+
import { warnOnInsecureuserIdentifierKey } from './auth.js'
2728
import { SeamHttpClientSessions } from './client-sessions.js'
2829

2930
export class SeamHttpAccessCodes {
@@ -75,6 +76,7 @@ export class SeamHttpAccessCodes {
7576
userIdentifierKey: string,
7677
options: ClientOptions = {},
7778
): Promise<SeamHttpAccessCodes> {
79+
warnOnInsecureuserIdentifierKey(userIdentifierKey)
7880
const clientOptions = parseOptions({ ...options, publishableKey })
7981
const client = createClient(clientOptions)
8082
const clientSessions = SeamHttpClientSessions.fromClient(client)

src/lib/seam/connect/routes/acs-access-groups.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
} from 'lib/seam/connect/options.js'
2424
import { parseOptions } from 'lib/seam/connect/parse-options.js'
2525

26+
import { warnOnInsecureuserIdentifierKey } from './auth.js'
2627
import { SeamHttpClientSessions } from './client-sessions.js'
2728

2829
export class SeamHttpAcsAccessGroups {
@@ -74,6 +75,7 @@ export class SeamHttpAcsAccessGroups {
7475
userIdentifierKey: string,
7576
options: ClientOptions = {},
7677
): Promise<SeamHttpAcsAccessGroups> {
78+
warnOnInsecureuserIdentifierKey(userIdentifierKey)
7779
const clientOptions = parseOptions({ ...options, publishableKey })
7880
const client = createClient(clientOptions)
7981
const clientSessions = SeamHttpClientSessions.fromClient(client)

src/lib/seam/connect/routes/acs-credentials.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
} from 'lib/seam/connect/options.js'
2424
import { parseOptions } from 'lib/seam/connect/parse-options.js'
2525

26+
import { warnOnInsecureuserIdentifierKey } from './auth.js'
2627
import { SeamHttpClientSessions } from './client-sessions.js'
2728

2829
export class SeamHttpAcsCredentials {
@@ -74,6 +75,7 @@ export class SeamHttpAcsCredentials {
7475
userIdentifierKey: string,
7576
options: ClientOptions = {},
7677
): Promise<SeamHttpAcsCredentials> {
78+
warnOnInsecureuserIdentifierKey(userIdentifierKey)
7779
const clientOptions = parseOptions({ ...options, publishableKey })
7880
const client = createClient(clientOptions)
7981
const clientSessions = SeamHttpClientSessions.fromClient(client)

src/lib/seam/connect/routes/acs-systems.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
} from 'lib/seam/connect/options.js'
2424
import { parseOptions } from 'lib/seam/connect/parse-options.js'
2525

26+
import { warnOnInsecureuserIdentifierKey } from './auth.js'
2627
import { SeamHttpClientSessions } from './client-sessions.js'
2728

2829
export class SeamHttpAcsSystems {
@@ -74,6 +75,7 @@ export class SeamHttpAcsSystems {
7475
userIdentifierKey: string,
7576
options: ClientOptions = {},
7677
): Promise<SeamHttpAcsSystems> {
78+
warnOnInsecureuserIdentifierKey(userIdentifierKey)
7779
const clientOptions = parseOptions({ ...options, publishableKey })
7880
const client = createClient(clientOptions)
7981
const clientSessions = SeamHttpClientSessions.fromClient(client)

src/lib/seam/connect/routes/acs-users.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
} from 'lib/seam/connect/options.js'
2424
import { parseOptions } from 'lib/seam/connect/parse-options.js'
2525

26+
import { warnOnInsecureuserIdentifierKey } from './auth.js'
2627
import { SeamHttpClientSessions } from './client-sessions.js'
2728

2829
export class SeamHttpAcsUsers {
@@ -74,6 +75,7 @@ export class SeamHttpAcsUsers {
7475
userIdentifierKey: string,
7576
options: ClientOptions = {},
7677
): Promise<SeamHttpAcsUsers> {
78+
warnOnInsecureuserIdentifierKey(userIdentifierKey)
7779
const clientOptions = parseOptions({ ...options, publishableKey })
7880
const client = createClient(clientOptions)
7981
const clientSessions = SeamHttpClientSessions.fromClient(client)

src/lib/seam/connect/routes/acs.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { SeamHttpAcsAccessGroups } from './acs-access-groups.js'
2424
import { SeamHttpAcsCredentials } from './acs-credentials.js'
2525
import { SeamHttpAcsSystems } from './acs-systems.js'
2626
import { SeamHttpAcsUsers } from './acs-users.js'
27+
import { warnOnInsecureuserIdentifierKey } from './auth.js'
2728
import { SeamHttpClientSessions } from './client-sessions.js'
2829

2930
export class SeamHttpAcs {
@@ -75,6 +76,7 @@ export class SeamHttpAcs {
7576
userIdentifierKey: string,
7677
options: ClientOptions = {},
7778
): Promise<SeamHttpAcs> {
79+
warnOnInsecureuserIdentifierKey(userIdentifierKey)
7880
const clientOptions = parseOptions({ ...options, publishableKey })
7981
const client = createClient(clientOptions)
8082
const clientSessions = SeamHttpClientSessions.fromClient(client)

src/lib/seam/connect/routes/action-attempts.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
} from 'lib/seam/connect/options.js'
2424
import { parseOptions } from 'lib/seam/connect/parse-options.js'
2525

26+
import { warnOnInsecureuserIdentifierKey } from './auth.js'
2627
import { SeamHttpClientSessions } from './client-sessions.js'
2728

2829
export class SeamHttpActionAttempts {
@@ -74,6 +75,7 @@ export class SeamHttpActionAttempts {
7475
userIdentifierKey: string,
7576
options: ClientOptions = {},
7677
): Promise<SeamHttpActionAttempts> {
78+
warnOnInsecureuserIdentifierKey(userIdentifierKey)
7779
const clientOptions = parseOptions({ ...options, publishableKey })
7880
const client = createClient(clientOptions)
7981
const clientSessions = SeamHttpClientSessions.fromClient(client)

0 commit comments

Comments
 (0)