Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .infra/Pulumi.adhoc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,6 @@ config:
secure: v1:GhL76XX0Y/yzoYG8:6kARUQHVOxbIP/WXxH+2IX91ADp650ZrEG7H+6FXuakJuzhDHTpk+q37jUq1hzHzp8xNbNFlud4=
appleClientId:
secure: v1:pK4ks8kCNPZO/KJc:REutw/UeJumYLJWA8cPy5iL83yaVgOOZh9azOyo7zcyj
appleClientSecret:
secure: v1:8TOrQ25yzgkRxr2C:n6FB51tbRNAl5bujHFjsn6a7kxEWlirmhX4wj/iWGM5BSc7n+8AxQkxhiLhe6xE0aXvfTPMUurfvbRMBHfkzbrJi7sZkMX7ZsseUHZLbyphA6+L3VxwsVvehArNx5iVJ8MzZW/LxsXZ50AtUjuXzLvaJKQtImdU9MLSPKy/EEOClTBSIn0leHJuEuDI4l7uFUN845qb+R6buTvy26jzaBNxTM//zLvf+2LN+iIbCKXsm77NdRT76x+Zr3rBQSnEWMZJjo4SE3eW5PJ30ZD0XJxung1CcErhWtVeHOkOQjGs4p6OGO/5S3NXK+RS65qQnMPoYiYPhkKhcmd/2FJqruzV7J93FGyw5+LUJ/AqPKpdCRNi1gMS5RPg+SG6Q5YiqvcMWiNbKPCsLStL3bZ2DKyvfBJx9XFWWSDcCFfft
facebookClientId:
secure: v1:HK6y83jsUMlifn1s:lVkv/LDrS8XKQDZtux2UgCCDMU+nAq1W2b1PNngYWQ==
facebookClientSecret:
Expand All @@ -126,5 +124,12 @@ config:
api:temporal:
chain: ''
key: ''
api:appleAuth:
teamId:
secure: v1:Ktskb12lh2HtPDRC:N+t3MbLzM274/SMsnN0cejzScaxF6I62sic=
keyId:
secure: v1:AeanAY9fDkWD2gSg:zleimS/qqmb3SCjeHTQ7Mp8QINMs/DcqFE0=
signingKey:
secure: v1:+2csKe943/E3qzYp:aOG0lDimtWcUCbASDNy9RpxsKnb6eV3JJ31xYtbs9NA3yeoDVBsMvLK0sba0r7lRgGg/SIqCHawAa/GyC4v3dW8rVfgbiAyvLEf0rdaXItVYM2HUimTK+bj+DQ6bLY9nol8JqaRaHfg7NicC+QHnCQogxsiUiS/U9GsXiBEWTQYBW50YSMMKBCzQV2OJU23434f6/EVL1m4scyKHL4wPUDVWi19lOhBAlWTutSXLWt113fafaaS44AIb64mspiThAeuQUAof1tSFn9dc+WgCyekQRQ7RGBcgoANubMthpU540cP3B9PU93TOnh6It1XOC3dYjsMTSWZjNFCXIeJs8+Y8NqbL/g1oOhFn3LrTtJ7c
secretsprovider: gcpkms://projects/daily-ops/locations/global/keyRings/pulumi/cryptoKeys/adhoc-secrets
encryptedkey: CiQAUBCtsAuGPHI7MeeWrccjf/ydEN57pW/AH+8NWsRvdPXM6e8SSABTzSDRfy71YqxOXL5RHxmOL5aU0fwHtiyHj4R5XRZbwtTUivxPk0qEIMtvbQSBCu7NE6CSd+uvaq5B/yz0DU8FWvGuYUzJXQ==
9 changes: 7 additions & 2 deletions .infra/Pulumi.prod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -257,8 +257,6 @@ config:
secure: AAABAEfjThwIBs0n3204XYFwZxshz0PuyY1bW1STItI8wzIb9z8WZcGcVpLHER0=
facebookClientSecret:
secure: AAABAPPqGlgKF6TZr2fIXHfVNcQEnRwrFfEScvb5Ogi+BEI9z9nSz47AF0KDM/dnSrV9ijKcRGloq3d3M34QAQ==
appleClientSecret:
secure: AAABAKJ1kXfmD4g3p/fZg5Gbid2scaPO4VQeK2VAWyZW/J54OvGGFuWg34X+YLyTPJbsyA6TsutCdSQsO9hRWXIzNFjZK9XZo4PmnCD5/MJbReYI6M3ayqc8M2bLBRaaDSj0/nrop+P9J3cMy/944b1F271lXOsCgNrHn4dkYLX0tkIuCnu86VSPaxJ9bRPRy83igX8w7P0gE5vKrnmLj29CSXk7iZGB1yikFPWddHLZUCxkX8gZ15kanvg6bvVdkrlotKdl8kV12iClSDc5gYDG/qsHsuHTixQ3vTmwf2R7svAAA3DeD6gJhXobRkbpNQMYMmwm2lwMzvwv394gMCKJ4/OsruktloyorRKIZP3jSrgs4XHT/buQC87H7n9WxGU/twKvzpbpkqi3ibdNhh9wKYVhTe/HCbZvv8rsCX+wbEeb
appleClientId:
secure: AAABABe5GePYDxcK+9QGqmQV7zE3Pv5wWtGkfFOV1MosH+KVFIfK6Is=
googleIosClientId:
Expand All @@ -274,3 +272,10 @@ config:
gcp:project: devkit-prod
gcp:region: us-central1
api:tag: 8a7bc7c1afab1d2bce67a6bc22e1be2662135cc4
api:appleAuth:
teamId:
secure: AAABACONn3aOuJjNxn+VlHZL1YCA7swTqY6JzEGvnhcMtawnjot1qAOb
keyId:
secure: AAABAH16I8xQAJjTyasPQzLDqd3AAo7q4dMEBGHVbgJJVvSviQelQT09
signingKey:
secure: AAABAGxRaqkffmtnKxeVFwStkBB2QUM1t5XtIOBJN0T/AcAJOac8oaovU/4H41JxFS5tnOOvWqN6HLvyejByOZ6UtxF6DqC27mvRiOKu863MKg7JrL3wPhHqEEgDJmdoGfqJw4Yady/CLRMqn58TCUwwNHRlcESng2RmwT9+BDXZywRFXfE5NKp41qLtLeOU6piAooQghHjVX6EQd8AG9Ffl2ehijRcwNnpgkQR8oz1V+Ilat6fvn9qQT1bjrBSE6oagdOxeLBdsVOmoa0H6ZbocsGmtvETEypK1uW62QD/Ar2PYtRSsFhvY9YiUf5qMxa6Kp1fJ4IdupoOKaAZY3yHlTFHXkU6pg0GGpfhktfaEgZaEgxcoknpQzPwEknjiAQ==
28 changes: 28 additions & 0 deletions .infra/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,34 @@ const envVars: Record<string, Input<string>> = {
redisPort: redis.port.apply((port) => port.toString()),
};

const appleAuth = config.getObject<{
teamId: string;
keyId: string;
signingKey: string;
}>('appleAuth');

if (appleAuth) {
envVars.appleTeamId = appleAuth.teamId;
envVars.appleKeyId = appleAuth.keyId;
envVars.appleSigningKeyPath = '/opt/app/apple/AuthKey.p8';

vols.volumes.push({
name: 'apple-auth',
secret: { secretName: 'apple-auth-secret' },
});
vols.volumeMounts.push({
name: 'apple-auth',
mountPath: '/opt/app/apple',
});

additionalSecrets.push({
name: 'apple-auth-secret',
data: {
'AuthKey.p8': Buffer.from(appleAuth.signingKey).toString('base64'),
},
});
}

createSubscriptionsFromWorkers(
name,
isAdhocEnv,
Expand Down
50 changes: 49 additions & 1 deletion src/betterAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,55 @@ import { singleRedisClient } from './redis';
import { User } from './entity/user/User';
import { fetchOptions } from './http';
import { retryFetch } from './integrations/retry';
import * as crypto from 'crypto';
import * as fs from 'fs';
import { cookies, extractRootDomain } from './cookies';

const GOOGLE_CERTS_URL = 'https://www.googleapis.com/oauth2/v3/certs';

const generateAppleClientSecret = (): string | undefined => {
const {
APPLE_CLIENT_ID,
APPLE_TEAM_ID,
APPLE_KEY_ID,
APPLE_SIGNING_KEY_PATH,
} = process.env;

if (
!APPLE_CLIENT_ID ||
!APPLE_TEAM_ID ||
!APPLE_KEY_ID ||
!APPLE_SIGNING_KEY_PATH
) {
return undefined;
}

const privateKey = fs.readFileSync(APPLE_SIGNING_KEY_PATH, 'utf8');

const toBase64Url = (data: object): string =>
Buffer.from(JSON.stringify(data)).toString('base64url');

const header = toBase64Url({ alg: 'ES256', kid: APPLE_KEY_ID, typ: 'JWT' });
const now = Math.floor(Date.now() / 1000);
const payload = toBase64Url({
iss: APPLE_TEAM_ID,
iat: now,
exp: now + 7 * 24 * 60 * 60, // 7 days — regenerated on every app start
aud: 'https://appleid.apple.com',
sub: APPLE_CLIENT_ID,
});

const signingInput = `${header}.${payload}`;
const signature = crypto
.sign('SHA256', Buffer.from(signingInput), {
key: privateKey,
dsaEncoding: 'ieee-p1363',
})
.toString('base64url');

return `${signingInput}.${signature}`;
};

const getGooglePublicKey = async (kid: string) => {
const res = await fetch(GOOGLE_CERTS_URL);
const { keys } = (await res.json()) as {
Expand Down Expand Up @@ -617,7 +662,10 @@ const createAuth = (): BetterAuthHandler => {
...(process.env.APPLE_CLIENT_ID && {
apple: {
clientId: process.env.APPLE_CLIENT_ID,
clientSecret: process.env.APPLE_CLIENT_SECRET ?? '',
clientSecret:
generateAppleClientSecret() ??
process.env.APPLE_CLIENT_SECRET ??
'',
appBundleIdentifier: process.env.APPLE_APP_BUNDLE_ID || undefined,
redirectURI: getSocialRedirectUri('apple'),
},
Expand Down
Loading