Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make documentation more beginner-friendly #48

Open
merganon opened this issue Aug 17, 2021 · 5 comments
Open

Make documentation more beginner-friendly #48

merganon opened this issue Aug 17, 2021 · 5 comments

Comments

@merganon
Copy link

merganon commented Aug 17, 2021

I feel like this repo is missing a lot of documentation.

No explanation for clientId, redirectURI, scopes, state and nonce params.

Also it's not clear that you have to create a new App ID on https://developer.apple.com/ with "Sign in with Apple" capability enabled etc.

@TheNemus
Copy link

Yes please, give more info about the options.

@timeisgolden
Copy link

yeah, @mlynch Hello,
Can you remind the explanation for clientId, redirectURI, scopes, state, and nonce params in detail?
Thanks support.

@DanielClyde
Copy link

Also I had a question related to this. I'd like to know if there is any additional verification that I need to do with the returned "authorizationCode". Or if I get an "authorizationCode" and an "identityToken" back then can I assume that it is a verified and valid login?

@serebrov
Copy link

serebrov commented Jan 29, 2022

Below is the information I gathered while working on the Apple Sign In integration.
This is compiled from Apple docs and external sources and might not be 100% correct, use with care.

Authentication Request Options

Options look like this:

const options: SignInWithAppleOptions = {
  clientId: 'com.myapp.app',
  redirectURI: 'https://www.myapp.com/login',
  scopes: 'email name',
  state: '12345',
  nonce: 'nonce',
}

clientId: For native app: the application ID, same as “appId” in capacitor config.

For web app: a client ID assigned to it after creating a new identity record for the website in Certificates, Identifiers & Profiles, see also About Sign in with Apple.

redirectUri: As I understand, redirectUri is only relevant for the web app, the URL to redirect to from the Apple Sign In dialog.

state: used as CSRF token:

  • App backend generates “state” value when we display the login form
  • Frontend adds “state” to the auth request
  • Apple sends back the response with “state” in it
  • Response is forwarded to the backend
  • Backend compares initial “state” with the one in the response

Note: probably this is more relevant for the sign in process in the web app, not sure if there is a way to hack into the sign in when it is performed in the native app (as request/response here happen on the level of the Apple platform code).

Note: plugin actually does not return state, so at the moment it is not possible to verify it, see #66.

nonce: it is encoded into the “identityToken” that can be decoded (JWT token) and compared on the server:

  • App backend (or frontend?) generates unique “nonce” value when we display the login form
  • Frontend adds “nonce” to the auth request
  • Apple sends back the response with “identityToken” with “nonce” encoded in it
  • Frontend resends apple response to the backend
  • Backend decodes “identityToken” and makes sure that “nonce” value is the same as was initially sent.

This is to prevent replay attacks: a network sniffer records Apple response and then a recorded response is sent to the app to get the account access.

References:

Authentication Response Data

We have following fields returned:

  • familyName, givenName, email - user name and email
  • user - unique Apple user ID
  • authorizationCode
  • identityToken

familyName, givenName, email user name and email, returned only on first sign in request ("null"s here after that)

user: The unique Apple’s user ID (also it is unique for your development team, so other developers/app would have a different ID for the same user).
The user identifier should be used instead of an email address to identify the user. The app backend should save this user ID and use it to find the account on future sign ups.

See: Authenticating Users with Sign in with Apple

Note: for the user identification we are actually forced to use user ID as familyName, givenName and email are only returned on first sign in. Following sign ins have “null”s here.

Update: it looks like email is also present inside the identityToken, see Retrieve the User’s Information from Apple ID Servers:

email
A String value representing the user’s email address. The email address is either the user’s real email address or the proxy address, depending on their status private email relay service.

identityToken: should be verified by the app backend, see: Verifying a User. Can be used to request user information from the Apple server.

authorizationCode: can be used by the app backend for additional validation or to get new access tokens (to talk to Apple servers from the backend).

See Verifying a User and Generate and Validate Tokens: Use this endpoint to either authorize a user by validating the authorization code received by your app, or by validating an existing refresh token to verify a user session or obtain access tokens.

@piotr-cz
Copy link
Contributor

piotr-cz commented Feb 8, 2024

This is actually pretty simple, but it takes few hours to pick up pieces.

Frontend integration

iOS platform

import { SignInWithAppleOptions } from '@capacitor-community/apple-sign-in'

const options: SignInWithAppleOptions = {
  // The appId defined in capacitor.config.ts
  clientId: 'com.your.webservice',
  // Ignored for iOS Platform
  redirectURI: '',
  scopes: 'email name',
};

Web platform

import { SignInWithAppleOptions } from '@capacitor-community/apple-sign-in'

const options: SignInWithAppleOptions = {
  // Service ID in your Apple Developer Account
  clientId: 'com.your.webservice',
  // This should be window.location origin because this plugin uses usePopup: true and data are sent back to opener
  redirectURI: 'https://www.yourfrontend.com/login',
  scopes: 'email name',
};

Android platform

Not implemented, see #13

Backend integration

  1. Submit the await SignInWithApple.authorize(options) result reponse to your backend.
  2. Verify identityToken as in example here: https://www.npmjs.com/package/react-apple-signin-auth#server-side-authentication-nodejs-backend but note, that payload format is slightly different:
    export interface SignInWithAppleResponse {
    response: {
    user: string | null;
    email: string | null;
    givenName: string | null;
    familyName: string | null;
    identityToken: string;
    authorizationCode: string;
    };
    }
  3. Extract payload.sub and payload.email from identityToken
  4. Extract givenName and familyName (you'll receive these only once).
    Probably it's good idea to use state or nonce to make sure that data has not been tampered

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants