Neato Polyester Material

    apple-sign-in-rest
    TypeScript icon, indicating that this package has built-in type declarations

    1.0.3 • Public • Published

    apple-sign-in-rest

    NPM

    renarsvilnis

    Hopefully your go-to library for implementing Sign In With Apple Rest API in Node.js.

    See comparison table why you should choose apple-sign-in-rest over other apple-xxx package.

    Supports Node.js >= 10.x.x

    Installation

    Install the module using npm:

    npm install --save apple-sign-in-rest
    yarn add apple-sign-in-rest

    Documentation

    Library is built on typescript and has well documented source code. This will provide a zero-effort developer expierence within your existing code editors. But the library also provides autogenered documentation using typedoc.

    Documentation

    Usage

    0. Prerequisites

    Here are some usefull links to get started with Sign In with Apple:

    1. Create a AppleSignIn instance

    Compared to other libraries apple-sign-in-rest chooses to create an instance with credentials instead of passing same credentials to functions on each call. This allows the library to validate them once and create apple public key cache per instance.

    // Using modules
    import {AppleSignIn} from 'apple-sign-in-rest';
    // or if using common.js
    const {AppleSignIn} = require("apple-sign-in-rest");
    
    /**
     * See docs for full list of options and descriptions:
     * https://renarsvilnis.github.io/apple-sign-in-rest/classes/_applesignin_.applesignin.html#constructor
     */
    const appleSignIn = new AppleSignIn({
      /**
       * The clientId depends on that login "flow" you trying to create:
       *   - "web login" - this is the "serviceId"
       *   - "ios login" - this is the app "bundleId", choose only this if you trying to
       *                   verify user that has signed into using the native iOS way
       *
       */
      clientId: "com.my-company.my-app",
      teamId: "5B645323E8",
      keyIdentifier: "U3B842SVGC",
      privateKey: "-----BEGIN PRIVATE KEY-----\nMIGTAgEHIHMJKJyqGSM32AgEGC...",
      // or instead of privateKey use privateKeyPath to read key from file
      privateKeyPath: '/Users/arnold/my-project/credentials/AuthKey.p8'
    })

    2. (Optional) Get authorization URL

    Start "Sign in with Apple" flow by redirecting user to the authorization URL.

    Alternatively, you can use Sign In with Apple browser javascript library to handle this.

    If you implement in Sign In With Apple trough iOS native login, you won't need to do this.

    /**
     * See docs for full list of options and descriptions:
     * https://renarsvilnis.github.io/apple-sign-in-rest/classes/_applesignin_.applesignin.html#getauthorizationurl
     */
    const authorizationUrl = appleSignIn.getAuthorizationUrl({
      scope: ["name", "email"],
      redirectUri: "http://localhost:3000/auth/apple/callback",
      // (Optional) Value of the anti-forgery unique session token, as well as any other information needed to recover the context when the user returns to your application, e.g., the starting URL.
      state: "123",
      // (Optional) A random value generated by your app that enables replay protection when present.
      nonce: "insert-generated-uuid",
    });

    2. Get access token

    2.1. Get credentials return after successful sign in with Apple

    Retrieve the "code" query parameter from the URL string when the user user redirect to your sites previously provided redirectUrl after a successfull Sign In With Apple.

    Make sure to verify that the state matches what was set when creating the authorization url!

    // Example: http://localhost:3000/auth/apple/callback?code=somecode&state=123
    app.get("/auth/apple/callback", (req, res) => {
      const code = req.query.code;
      const state = req.query.state;
    
      // This depends how you implemented the storing "state"
      if (req.session.state && req.session.state !== state) {
        throw new Error("Missing or invalid state");
      }
    
      // Continues in next examples...
    });

    In the case of iOS the native-app sends the code to a custom endpoint on your app. Make sure that iOS app also securily passes along the fullName and idToken . From the backend you won't have access to the fullName and idToken can be used to verify the user without making appleSignIn.getAuthorization() call.

    2.2. Create a userSecret

    /**
     * See docs for full list of options and descriptions:
     * https://renarsvilnis.github.io/apple-sign-in-rest/classes/_applesignin_.applesignin.html#createclientsecret
     */
    const clientSecret = appleSignIn.createClientSecret({
      /**
       * Optionaly you can set the validity duration of the secret in seconds. Apple allows the secret to up to 6 months,
       * but if you are creating a clientSecret per request basis you can set your own expiration duration.
       * Defaults to 6 months.
       */
      expirationDuration: 5 * 60, // 5 minutes
    });

    2.2. Exchange retrieved "code" to user's access token.

    /**
     * See docs for full list of options and descriptions:
     * https://renarsvilnis.github.io/apple-sign-in-rest/classes/_applesignin_.applesignin.html#getauthorizationtoken
     */
    const tokenResponse = await appleSignIn.getAuthorizationToken(clientSecret, code, {
      // Optional, use the same value which you passed to authorisation URL. In case of iOS you skip the value
      redirectUri: "http://localhost:3000/auth/apple/callback",
    });

    Result of appleSignIn.getAuthorizationToken command is a JSON object representing Apple's TokenResponse:

    {
       // A token used to access allowed data. Currently has no use
        access_token: "ACCESS_TOKEN",
        // It will always be Bearer.
        token_type: 'Bearer',
        // The amount of time, in seconds, before the access token expires.
        expires_in: 3600,
        // used to regenerate new access tokens. Store this token securely on your server.
        refresh_token: "REFRESH_TOKEN",
        // A JSON Web Token that contains the user’s identity information.
        id_token: "ID_TOKEN"
    }

    2.4. Verify token signature and get unique user's identifier

    /**
     * See docs for full list of options and descriptions:
     * https://renarsvilnis.github.io/apple-sign-in-rest/classes/_applesignin_.applesignin.html#verifyidtoken
     */
    const claim = await appleSignIn.verifyIdToken(tokenResponse.id_token, {
      // (Optional) verifies the nonce
      nonce: "nonce",
      // (Optional) If you want to check subject(sub field) of the jwt a.k.a "user_identifier|provider_id". Might be usefull in the case where iOS app also sends you it, so you can verify if it is correct
      subject: "000852.5g3d8d4b3db045b48b7a58fb07728e1e.1303",
      // (Optional) If you want to handle expiration on your own, useful in case of iOS as identityId can't be "refreshed"
      ignoreExpiration: true, // default is false
    });

    3. Refresh access token after expiration

    Should call it no more once a day, else apple amy throttle your request.

    /**
     * See docs for full list of options and descriptions:
     * https://renarsvilnis.github.io/apple-sign-in-rest/classes/_applesignin_.applesignin.html#refreshauthorizationtoken
     */
    const refreshTokenResponse = await appleSignIn.refreshAuthorizationToken(clientSecret, refreshToken);
    const { access_token } = refreshTokenResponse.access_token;

    Comparison to other "apple sign in" libraries

    There are many already packages on npm with very similar names. Most of them are missing features and/or abandoned. This package takes inspiration from apple-signin and implements features/fixes while comparing to other libraries.

    The only other library I'd consider feature-full and ready to use besides this one is apple-signin-auth by A-Tokyo, seem to have missing key features.

    apple-sign-in-rest apple-signin-auth apple-auth apple-signin
    Feature Full (missing some minor options)
    Apple Public Key Caching (cache per class instance) (global cache)
    Passport.js library (comming-soon)
    Typed Support (typescript based) (flow based)
    API Documentation (auto generated docs using typedoc)
    Usage Examples
    Tools for easier contributors (typescript, eslint, prettier, jest) (flow, eslint, prettier, jest)
    Stats NPM NPM NPM NPM

    Contributing

    Pull requests are always welcomed. 🙇🏻‍♂️ Please open an issue first to discuss what you would like to change.

    Package has a pre-commit git hook that does typechecking, linting, unit testing and doc building (if see source code changes).

    Helper scripts

    # Build library, will create a library in /lib folder
    npm run build
    
    # Run unit tests
    npm run test
    npm run test:watch # watch mode
    
    # Run typecheck and linter
    npm run lint
    
    # Attempts to fix all formatting and linting issues
    npm run format
    
    # Build docs
    npm run docs
    
    # Inspect documentation localy visit http://127.0.0.1:8080
    npm run docs:serve
    
    # By default docs are automatically built and added on pre-commit hook,
    # if it sees staged changes to any /src files,
    # you can override the logic by forcing to build docs by passing environmental
    DOCS_FORCE=true git commit -m 'My awesome change'
    
    # You also skip automatically adding docs to commit
    DOCS_COMMIT=false git commit -m 'My awesome change'
    
    # Commit but ignore ship the git hooks
    git commit -m 'My awesome change' --no-verify

    License

    The MIT License

    Copyright (c) 2020 Renārs Vilnis

    Support

    If you have any questions or need help with integration, then you can contact me by email renars.vilnis@gmail.com.

    Install

    npm i apple-sign-in-rest

    DownloadsWeekly Downloads

    1,922

    Version

    1.0.3

    License

    MIT

    Unpacked Size

    38.7 kB

    Total Files

    5

    Last publish

    Collaborators

    • renarsvilnis