Skip to content

Commit dd2b64e

Browse files
updated 2 files for allowing multiple client ids (#6523)
* updated 2 files for allowing multiple client ids * updated tests that fail due to user inputting data in code, added todo comment to them stating what we need to do to fix them
1 parent 76f0edc commit dd2b64e

File tree

2 files changed

+170
-20
lines changed

2 files changed

+170
-20
lines changed

spec/AuthenticationAdapters.spec.js

Lines changed: 150 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,7 +1138,7 @@ describe('apple signin auth adapter', () => {
11381138
const jwt = require('jsonwebtoken');
11391139
const util = require('util');
11401140

1141-
it('should throw error with missing id_token', async () => {
1141+
it('(using client id as string) should throw error with missing id_token', async () => {
11421142
try {
11431143
await apple.validateAuthData({}, { clientId: 'secret' });
11441144
fail();
@@ -1147,6 +1147,15 @@ describe('apple signin auth adapter', () => {
11471147
}
11481148
});
11491149

1150+
it('(using client id as array) should throw error with missing id_token', async () => {
1151+
try {
1152+
await apple.validateAuthData({}, { client_id: ['secret'] });
1153+
fail();
1154+
} catch (e) {
1155+
expect(e.message).toBe('id token is invalid for this user.');
1156+
}
1157+
});
1158+
11501159
it('should not decode invalid id_token', async () => {
11511160
try {
11521161
await apple.validateAuthData(
@@ -1220,7 +1229,19 @@ describe('apple signin auth adapter', () => {
12201229
}
12211230
});
12221231

1223-
it('should verify id_token', async () => {
1232+
it('(using client id as array) should not verify invalid id_token', async () => {
1233+
try {
1234+
await apple.validateAuthData(
1235+
{ id: 'the_user_id', token: 'the_token' },
1236+
{ client_id: ['secret'] }
1237+
);
1238+
fail();
1239+
} catch (e) {
1240+
expect(e.message).toBe('provided token does not decode as JWT');
1241+
}
1242+
});
1243+
1244+
it('(using client id as string) should verify id_token', async () => {
12241245
const fakeClaim = {
12251246
iss: 'https://appleid.apple.com',
12261247
aud: 'secret',
@@ -1242,7 +1263,51 @@ describe('apple signin auth adapter', () => {
12421263
expect(result).toEqual(fakeClaim);
12431264
});
12441265

1245-
it('should throw error with with invalid jwt issuer', async () => {
1266+
it('(using client id as array) should verify id_token', async () => {
1267+
const fakeClaim = {
1268+
iss: 'https://appleid.apple.com',
1269+
aud: 'secret',
1270+
exp: Date.now(),
1271+
sub: 'the_user_id',
1272+
};
1273+
const fakeDecodedToken = { header: { kid: '123', alg: 'RS256' } };
1274+
spyOn(jwt, 'decode').and.callFake(() => fakeDecodedToken);
1275+
const fakeGetSigningKeyAsyncFunction = () => {
1276+
return { kid: '123', rsaPublicKey: 'the_rsa_public_key' };
1277+
};
1278+
spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction);
1279+
spyOn(jwt, 'verify').and.callFake(() => fakeClaim);
1280+
1281+
const result = await apple.validateAuthData(
1282+
{ id: 'the_user_id', token: 'the_token' },
1283+
{ clientId: ['secret'] }
1284+
);
1285+
expect(result).toEqual(fakeClaim);
1286+
});
1287+
1288+
it('(using client id as array with multiple items) should verify id_token', async () => {
1289+
const fakeClaim = {
1290+
iss: 'https://appleid.apple.com',
1291+
aud: 'secret',
1292+
exp: Date.now(),
1293+
sub: 'the_user_id',
1294+
};
1295+
const fakeDecodedToken = { header: { kid: '123', alg: 'RS256' } };
1296+
spyOn(jwt, 'decode').and.callFake(() => fakeDecodedToken);
1297+
const fakeGetSigningKeyAsyncFunction = () => {
1298+
return { kid: '123', rsaPublicKey: 'the_rsa_public_key' };
1299+
};
1300+
spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction);
1301+
spyOn(jwt, 'verify').and.callFake(() => fakeClaim);
1302+
1303+
const result = await apple.validateAuthData(
1304+
{ id: 'the_user_id', token: 'the_token' },
1305+
{ clientId: ['secret', 'secret 123'] }
1306+
);
1307+
expect(result).toEqual(fakeClaim);
1308+
});
1309+
1310+
it('(using client id as string) should throw error with with invalid jwt issuer', async () => {
12461311
const fakeClaim = {
12471312
iss: 'https://not.apple.com',
12481313
sub: 'the_user_id',
@@ -1268,10 +1333,11 @@ describe('apple signin auth adapter', () => {
12681333
}
12691334
});
12701335

1271-
it('should throw error with with invalid jwt client_id', async () => {
1336+
// TODO: figure out a way to generate our own apple signed tokens, perhaps with a parse apple account
1337+
// and a private key
1338+
xit('(using client id as array) should throw error with with invalid jwt issuer', async () => {
12721339
const fakeClaim = {
1273-
iss: 'https://appleid.apple.com',
1274-
aud: 'invalid_client_id',
1340+
iss: 'https://not.apple.com',
12751341
sub: 'the_user_id',
12761342
};
12771343
const fakeDecodedToken = { header: { kid: '123', alg: 'RS256' } };
@@ -1284,17 +1350,91 @@ describe('apple signin auth adapter', () => {
12841350

12851351
try {
12861352
await apple.validateAuthData(
1287-
{ id: 'the_user_id', token: 'the_token' },
1288-
{ clientId: 'secret' }
1353+
{
1354+
id: 'INSERT ID HERE',
1355+
token: 'INSERT APPLE TOKEN HERE WITH INVALID JWT ISSUER',
1356+
},
1357+
{ clientId: ['INSERT CLIENT ID HERE'] }
12891358
);
12901359
fail();
12911360
} catch (e) {
12921361
expect(e.message).toBe(
1293-
'jwt aud parameter does not include this client - is: invalid_client_id | expected: secret'
1362+
'id token not issued by correct OpenID provider - expected: https://appleid.apple.com | from: https://not.apple.com'
12941363
);
12951364
}
12961365
});
12971366

1367+
it('(using client id as string) should throw error with with invalid jwt issuer', async () => {
1368+
const fakeClaim = {
1369+
iss: 'https://not.apple.com',
1370+
sub: 'the_user_id',
1371+
};
1372+
const fakeDecodedToken = { header: { kid: '123', alg: 'RS256' } };
1373+
spyOn(jwt, 'decode').and.callFake(() => fakeDecodedToken);
1374+
const fakeGetSigningKeyAsyncFunction = () => {
1375+
return { kid: '123', rsaPublicKey: 'the_rsa_public_key' };
1376+
};
1377+
spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction);
1378+
spyOn(jwt, 'verify').and.callFake(() => fakeClaim);
1379+
1380+
try {
1381+
await apple.validateAuthData(
1382+
{
1383+
id: 'INSERT ID HERE',
1384+
token: 'INSERT APPLE TOKEN HERE WITH INVALID JWT ISSUER',
1385+
},
1386+
{ clientId: 'INSERT CLIENT ID HERE' }
1387+
);
1388+
fail();
1389+
} catch (e) {
1390+
expect(e.message).toBe(
1391+
'id token not issued by correct OpenID provider - expected: https://appleid.apple.com | from: https://not.apple.com'
1392+
);
1393+
}
1394+
});
1395+
1396+
// TODO: figure out a way to generate our own apple signed tokens, perhaps with a parse apple account
1397+
// and a private key
1398+
xit('(using client id as string) should throw error with invalid jwt client_id', async () => {
1399+
try {
1400+
await apple.validateAuthData(
1401+
{ id: 'INSERT ID HERE', token: 'INSERT APPLE TOKEN HERE' },
1402+
{ clientId: 'secret' }
1403+
);
1404+
fail();
1405+
} catch (e) {
1406+
expect(e.message).toBe('jwt audience invalid. expected: secret');
1407+
}
1408+
});
1409+
1410+
// TODO: figure out a way to generate our own apple signed tokens, perhaps with a parse apple account
1411+
// and a private key
1412+
xit('(using client id as array) should throw error with invalid jwt client_id', async () => {
1413+
try {
1414+
await apple.validateAuthData(
1415+
{ id: 'INSERT ID HERE', token: 'INSERT APPLE TOKEN HERE' },
1416+
{ clientId: ['secret'] }
1417+
);
1418+
fail();
1419+
} catch (e) {
1420+
expect(e.message).toBe('jwt audience invalid. expected: secret');
1421+
}
1422+
});
1423+
1424+
// TODO: figure out a way to generate our own apple signed tokens, perhaps with a parse apple account
1425+
// and a private key
1426+
xit('should throw error with invalid user id', async () => {
1427+
try {
1428+
await apple.validateAuthData(
1429+
{ id: 'invalid user', token: 'INSERT APPLE TOKEN HERE' },
1430+
{ clientId: 'INSERT CLIENT ID HERE' }
1431+
);
1432+
fail();
1433+
} catch (e) {
1434+
expect(e.message).toBe('auth data is invalid for this user.');
1435+
}
1436+
});
1437+
12981438
it('should throw error with with invalid user id', async () => {
12991439
const fakeClaim = {
13001440
iss: 'https://appleid.apple.com',
@@ -1320,6 +1460,7 @@ describe('apple signin auth adapter', () => {
13201460
}
13211461
});
13221462
});
1463+
13231464
describe('Apple Game Center Auth adapter', () => {
13241465
const gcenter = require('../lib/Adapters/Auth/gcenter');
13251466

src/Adapters/Auth/apple.js

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,12 @@ const getAppleKeyByKeyId = async (keyId, cacheMaxEntries, cacheMaxAge) => {
3333
const getHeaderFromToken = token => {
3434
const decodedToken = jwt.decode(token, { complete: true });
3535
if (!decodedToken) {
36-
throw Error('provided token does not decode as JWT');
36+
throw new Parse.Error(
37+
Parse.Error.OBJECT_NOT_FOUND,
38+
`provided token does not decode as JWT`
39+
);
3740
}
41+
3842
return decodedToken.header;
3943
};
4044

@@ -45,12 +49,14 @@ const verifyIdToken = async (
4549
if (!token) {
4650
throw new Parse.Error(
4751
Parse.Error.OBJECT_NOT_FOUND,
48-
'id token is invalid for this user.'
52+
`id token is invalid for this user.`
4953
);
5054
}
5155

5256
const { kid: keyId, alg: algorithm } = getHeaderFromToken(token);
5357
const ONE_HOUR_IN_MS = 3600000;
58+
let jwtClaims;
59+
5460
cacheMaxAge = cacheMaxAge || ONE_HOUR_IN_MS;
5561
cacheMaxEntries = cacheMaxEntries || 5;
5662

@@ -61,28 +67,31 @@ const verifyIdToken = async (
6167
);
6268
const signingKey = appleKey.publicKey || appleKey.rsaPublicKey;
6369

64-
const jwtClaims = jwt.verify(token, signingKey, {
65-
algorithms: algorithm,
66-
});
70+
try {
71+
jwtClaims = jwt.verify(token, signingKey, {
72+
algorithms: algorithm,
73+
// the audience can be checked against a string, a regular expression or a list of strings and/or regular expressions.
74+
audience: clientId,
75+
});
76+
} catch (exception) {
77+
const message = exception.message;
78+
79+
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, `${message}`);
80+
}
6781

6882
if (jwtClaims.iss !== TOKEN_ISSUER) {
6983
throw new Parse.Error(
7084
Parse.Error.OBJECT_NOT_FOUND,
7185
`id token not issued by correct OpenID provider - expected: ${TOKEN_ISSUER} | from: ${jwtClaims.iss}`
7286
);
7387
}
88+
7489
if (jwtClaims.sub !== id) {
7590
throw new Parse.Error(
7691
Parse.Error.OBJECT_NOT_FOUND,
7792
`auth data is invalid for this user.`
7893
);
7994
}
80-
if (clientId !== undefined && jwtClaims.aud !== clientId) {
81-
throw new Parse.Error(
82-
Parse.Error.OBJECT_NOT_FOUND,
83-
`jwt aud parameter does not include this client - is: ${jwtClaims.aud} | expected: ${clientId}`
84-
);
85-
}
8695
return jwtClaims;
8796
};
8897

0 commit comments

Comments
 (0)