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

feat: support native social sign using apple sdk #3476

Merged
merged 10 commits into from
Sep 12, 2023

Conversation

jonas-jonas
Copy link
Member

@jonas-jonas jonas-jonas commented Sep 4, 2023

This PR adds support for social sign in via Apple using an ID token instead of the browser based OIDC flows. This allows integration of the SDK for Apple sign in iOS.

How this works:

  1. Use the Apple SDK on the device to request authentication, which returns an IDToken
  2. Submit that token to Kratos using updateRegistrationFlow, alongside any traits you want the identity to have
  3. Kratos verifies the token using Apple's public JWKS (make this configurable for the generic provider?)
  4. Kratos extracts the data from the IDToken
  5. Kratos processes the login/registration as if it came from an OIDC callback

Expo example (PR in repo following):

import * as AppleAuthentication from "expo-apple-authentication"
import * as Crypto from "expo-crypto"
import * as Random from "expo-random"

async function signInWithApple() {
  const nonce = Random.getRandomBytes(16).toString()

  const digest = await Crypto.digestStringAsync(
    Crypto.CryptoDigestAlgorithm.SHA256,
    nonce,
  )
  const credential = await AppleAuthentication.signInAsync({
    requestedScopes: [
      AppleAuthentication.AppleAuthenticationScope.EMAIL,
      AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
    ],
    nonce: digest,
  })

  return orySdk.updateRegistrationFlow({
    flow: flow.id,
    updateRegistrationFlowBody: {
      provider: "apple",
      id_token: credential.identityToken,
      raw_id_token_nonce: nonce,
      traits: {
        name: {
          first: credential.fullName?.givenName || "given name", // When developing, these values might be empty
          last: credential.fullName?.familyName || "last name", // When developing, these values might be empty
        },
      },
    },
  })
}

Related issue(s)

Docs PR: ory/docs#1528

Checklist

  • I have read the contributing guidelines.
  • I have referenced an issue containing the design document if my change
    introduces a new feature.
  • I am following the
    contributing code guidelines.
  • I have read the security policy.
  • I confirm that this pull request does not address a security
    vulnerability. If this pull request addresses a security vulnerability, I
    confirm that I got the approval (please contact
    [email protected]) from the maintainers to push
    the changes.
  • I have added tests that prove my fix is effective or that my feature
    works.
  • I have added or changed the documentation.

Further Comments

@jonas-jonas jonas-jonas force-pushed the jonas-jonas/supportSignInWithNativeSDK branch from 6ec19d3 to 6b580e5 Compare September 4, 2023 16:21
@codecov
Copy link

codecov bot commented Sep 4, 2023

Codecov Report

Merging #3476 (fc30304) into master (fc30304) will not change coverage.
The diff coverage is n/a.

❗ Current head fc30304 differs from pull request most recent head b8de37b. Consider uploading reports for the commit b8de37b to get more accurate results

@@           Coverage Diff           @@
##           master    #3476   +/-   ##
=======================================
  Coverage   78.76%   78.76%           
=======================================
  Files         341      341           
  Lines       23707    23707           
=======================================
  Hits        18673    18673           
  Misses       3667     3667           
  Partials     1367     1367           

@jonas-jonas jonas-jonas self-assigned this Sep 5, 2023
@jonas-jonas jonas-jonas marked this pull request as ready for review September 5, 2023 17:20
Copy link
Member Author

@jonas-jonas jonas-jonas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure, we can really e2e test this, as there is no other provider that supports verifying an ID Token from the payload, for now.

I guess, we could make the generic provider support it and add a JWKS URL to the config? Then we could obtain an ID token from a Hydra instance and submit that.

selfservice/strategy/oidc/provider_apple.go Show resolved Hide resolved
selfservice/strategy/oidc/provider_apple.go Show resolved Hide resolved
selfservice/strategy/oidc/provider_config.go Show resolved Hide resolved
selfservice/strategy/oidc/provider_apple.go Show resolved Hide resolved
@jonas-jonas jonas-jonas changed the title feat: support native social sign using apple/google sdk feat: support native social sign using apple sdk Sep 5, 2023
Copy link
Member

@aeneasr aeneasr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks very good, please add three tests to strategy_test:

  • Test login with an ID token, ensure claims end up properly
  • Test registration with an ID token, ensure claims end up properly
  • Test login/registration with an ID token where the Client ID is not matching (should fail)
  • Test login/registration with an ID token where the nonce is not matching (should fail)

Please also make it possible to submit the nonce and validate the nonce as well. Fail the flow if the nonce is not set.

@aeneasr aeneasr force-pushed the jonas-jonas/supportSignInWithNativeSDK branch from ec1ee7d to 3f3b428 Compare September 7, 2023 14:33
@aeneasr aeneasr self-requested a review September 8, 2023 08:39
Copy link
Member

@aeneasr aeneasr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The nonce implementation does not look correct to me. Typically, a nonce is a plain string (like the state parameter) and you do a string equality match to verify if it is valid or not. The nonce_supported flag defaults to false, which may be OK for apple, but is definitely not OK for any other provider, as this claim is not a standard claim (it is never mentioned here: https://openid.net/specs/openid-connect-core-1_0.html).

Additionally, the Apple documentation states:

A Boolean value that indicates whether the transaction is on a nonce-supported platform. If you send a nonce in the authorization request, but don’t see the nonce claim in the identity token, check this claim to determine how to proceed. If this claim returns true, treat nonce as mandatory and fail the transaction; otherwise, you can proceed treating the nonce as optional.

However, as far as I can see, we use this claim first to check whether we should validate. But the documentation states:

  1. If a nonce was sent (aka if we receive the nonce as part of the registration / login payload
  2. And the nonce is not available in the id_token
  3. Then (and only then) we check this claim

The current implementation however:

  1. Checks if the claim is true
  2. Proceeds with validation

My suggestion is to move this custom validation logic into the apple ID token verification:

  1. The apple provider validates the nonce claim:
  2. If a nonce was sent as part of the payload
  3. And the id_token has a nonce -> we validate
  4. And the id_token has no nonce
    * We check the nonce_supported claim
    * If true: fail
    * If false: proceed
  5. The Google provider also validates the nonce (but always, because Google returns this always)
  6. The generic provider does not validate the nonce at all, it delegates the ID token validation to the specific provider (we can fix this later if desired).

Please don't merge this without another review from myself!

selfservice/strategy/oidc/provider.go Show resolved Hide resolved
selfservice/strategy/oidc/strategy.go Outdated Show resolved Hide resolved
selfservice/strategy/oidc/strategy_login.go Outdated Show resolved Hide resolved
selfservice/strategy/oidc/strategy_test.go Show resolved Hide resolved
selfservice/strategy/oidc/provider_apple_test.go Outdated Show resolved Hide resolved
Copy link
Member

@aeneasr aeneasr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much better! Almost there

selfservice/strategy/oidc/strategy.go Outdated Show resolved Hide resolved
Copy link
Member

@aeneasr aeneasr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome!

@jonas-jonas jonas-jonas force-pushed the jonas-jonas/supportSignInWithNativeSDK branch from 9b97cc0 to b8de37b Compare September 12, 2023 08:06
@jonas-jonas jonas-jonas merged commit f561013 into master Sep 12, 2023
26 checks passed
@jonas-jonas jonas-jonas deleted the jonas-jonas/supportSignInWithNativeSDK branch September 12, 2023 12:47
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

Successfully merging this pull request may close these issues.

3 participants