Skip to content

Commit

Permalink
Update docs and add validation of Openid Connect token
Browse files Browse the repository at this point in the history
  • Loading branch information
Techofficer committed Jun 15, 2019
1 parent c18ecb0 commit 05b7aaf
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 20 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "apple-signin",
"version": "1.0.6",
"version": "1.0.9",
"description": "Node.JS wrapper around Sign In with Apple REST API",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
Expand Down
12 changes: 6 additions & 6 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Start "Sign in with Apple" flow by redirecting user to the authorization URL.
const appleSignin = require("apple-signin");

const options = {
clientId: "com.gotechmakers.auth.client", // identifier of Apple Service ID.
clientID: "com.gotechmakers.auth.client", // identifier of Apple Service ID.
redirectUri: "http://localhost:3000/auth/apple/callback",
state: "123", // optional, An unguessable random string. It is primarily used to protect against CSRF attacks.
scope: "email" // optional, default value is "email".
Expand All @@ -50,14 +50,14 @@ More detail can be found in [Apple docs](https://developer.apple.com/documentati
```javascript

const clientSecret = appleSignin.getClientSecret({
clientId: "com.gotechmakers.auth.client", // identifier of Apple Service ID.
clientID: "com.gotechmakers.auth.client", // identifier of Apple Service ID.
teamId: "teamId", // Apple Developer Team ID.
privateKeyPath: "/var/www/app/AuthKey_XXX.p8", // path to private key associated with your client ID.
keyIdentifier: "XXX" // identifier of the private key.
});

const options = {
clientId: "com.gotechmakers.auth.client", // identifier of Apple Service ID.
clientID: "com.gotechmakers.auth.client", // identifier of Apple Service ID.
redirectUri: "http://localhost:3000/auth/apple/callback", // use the same value which you passed to authorisation URL.
clientSecret: clientSecret
};
Expand All @@ -82,7 +82,7 @@ Result of ```getAuthorizationToken``` command is a JSON object representing Appl

### 3. Verify token signature and get unique user's identifier
```javascript
appleSignin.verifyIdToken(tokenResponse.id_token).then(result => {
appleSignin.verifyIdToken(tokenResponse.id_token, clientID).then(result => {
const userAppleId = result.sub;
}).catch(error => {
// Token is not verified
Expand All @@ -93,14 +93,14 @@ appleSignin.verifyIdToken(tokenResponse.id_token).then(result => {
```javascript

const clientSecret = appleSignin.getClientSecret({
clientId: "com.gotechmakers.auth.client", // identifier of Apple Service ID.
clientID: "com.gotechmakers.auth.client", // identifier of Apple Service ID.
teamId: "teamId", // Apple Developer Team ID.
privateKeyPath: "/var/www/app/AuthKey_XXX.p8", // path to private key associated with your client ID.
keyIdentifier: "XXX" // identifier of the private key.
});

const options = {
clientId: "com.gotechmakers.auth.client", // identifier of Apple Service ID.
clientID: "com.gotechmakers.auth.client", // identifier of Apple Service ID.
clientSecret: clientSecret
};

Expand Down
33 changes: 20 additions & 13 deletions source/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const request = require('request-promise-native');

const ENDPOINT_URL = 'https://appleid.apple.com';
const DEFAULT_SCOPE = 'email';
const TOKEN_ISSUER = 'https://appleid.apple.com';

const getAuthorizationUrl = (options = {}) => {
if (!options.clientID) throw Error('clientID is empty');
Expand All @@ -29,11 +30,11 @@ const getAuthorizationUrl = (options = {}) => {
};

const getClientSecret = options => {
if (!options.clientID) throw Error('clientID is empty');
if (!options.teamId) throw Error('teamId is empty');
if (!options.keyIdentifier) throw Error('keyIdentifier is empty');
if (!options.privateKeyPath) throw Error('privateKeyPath is empty');
if (!fs.existsSync(options.privateKeyPath)) throw Error("Can't find private key");
if (!options.clientID) throw new Error('clientID is empty');
if (!options.teamId) throw new Error('teamId is empty');
if (!options.keyIdentifier) throw new Error('keyIdentifier is empty');
if (!options.privateKeyPath) throw new Error('privateKeyPath is empty');
if (!fs.existsSync(options.privateKeyPath)) throw new Error("Can't find private key");

const timeNow = Math.floor(Date.now() / 1000);

Expand All @@ -52,9 +53,9 @@ const getClientSecret = options => {
};

const getAuthorizationToken = async (code, options) => {
if (!options.clientID) throw Error('clientID is empty');
if (!options.redirectUri) throw Error('redirectUri is empty');
if (!options.clientSecret) throw Error('clientSecret is empty');
if (!options.clientID) throw new Error('clientID is empty');
if (!options.redirectUri) throw new Error('redirectUri is empty');
if (!options.clientSecret) throw new Error('clientSecret is empty');

const url = new URL(ENDPOINT_URL);
url.pathname = '/auth/token';
Expand All @@ -72,8 +73,8 @@ const getAuthorizationToken = async (code, options) => {
};

const refreshAuthorizationToken = async (refreshToken, options) => {
if (!options.clientID) throw Error('clientID is empty');
if (!options.clientSecret) throw Error('clientSecret is empty');
if (!options.clientID) throw new Error('clientID is empty');
if (!options.clientSecret) throw new Error('clientSecret is empty');

const url = new URL(ENDPOINT_URL);
url.pathname = '/auth/token';
Expand Down Expand Up @@ -101,9 +102,15 @@ const getApplePublicKey = async () => {
return pubKey.exportKey(['public']);
};

const verifyIdToken = async idToken => {
const pubKey = await getApplePublicKey();
return jwt.verify(idToken, pubKey, { algorithms: 'RS256' });
const verifyIdToken = async (idToken, clientID) => {
const applePublicKey = await getApplePublicKey();
const jwtClaims = jwt.verify(idToken, applePublicKey, { algorithms: 'RS256' });

if (jwtClaims.iss !== TOKEN_ISSUER) throw new Error('id token not issued by correct OpenID provider - expected: ' + TOKEN_ISSUER + ' | from: ' + jwtClaims.iss);
if (clientID !== undefined && jwtClaims.aud !== clientID) throw new Error('aud parameter does not include this client - is: ' + jwtClaims.aud + '| expected: ' + clientID);
if (jwtClaims.exp < (Date.now() / 1000)) throw new Error('id token has expired');

return jwtClaims;
};


Expand Down

0 comments on commit 05b7aaf

Please sign in to comment.