wagnerdelima / drf-social-oauth2

drf-social-oauth2 makes it easy to integrate Django social authentication with major OAuth2 providers, i.e., Facebook, Twitter, Google, etc.
https://drf-social-oauth2.readthedocs.io/en/latest/
MIT License
274 stars 34 forks source link

Documentation for AppleID and/or authorization code flows #105

Open denizdogan opened 2 years ago

denizdogan commented 2 years ago

I can't figure out how to sign in using AppleID with this library, and I can't understand how the authorization code flow is supposed to work in general.

The README explicitly says to use "Resource owner password-based", but that should obviously be "Authorization code" in this case. But what about the client ID and client secret? Do those work just like with convert_token? Can I use a fake URI for redirect URIs? It seems that no matter which way I twist and turn things, I get invalid_client or invalid_grant back.

Much appreciated.

wagnerdelima commented 2 years ago

@denizdogan yes Apple Sign in is a little bit of a mistery so far. It's in my list of todos to include it here. Did you find anything interesting yourself that can be included to the docs?

denizdogan commented 2 years ago

@wagnerdelima Not yet, was hoping that someone else had made it work. The whole chain of dependencies is so convoluted, it's hard to know what library does what. PyCharm goes a long way, but even then it's hard to keep track. :)

denizdogan commented 2 years ago

Having debugged this one for a little bit, it seems like there's a Grant object missing while validating the authorization code. Line 412 in oauth2_provider.oauth2_validators.OAuth2Validator.validate_code raises Grant.DoesNotExist. It seems to me that this Grant object is meant to be created in oauth2_provider.views.mixins.OAuthLibMixin.create_authorization_response.

From what I've been able to gather, it seems that the idea is that this is created in AuthorizationView with an HTML page and a form. Obviously, this is not suitable for AppleID login, so I'm definitely missing something. (Or some library is missing something.)

Trying a completely different approach, I've tried to POST some authorization code data to /api/auth/complete/apple-id/, but all that does is give me:

django.urls.exceptions.NoReverseMatch: 'social' is not a registered namespace
Internal Server Error: /api/auth/complete/apple-id/

This is the same problem that has been mentioned here two weeks ago: https://github.com/wagnerdelima/drf-social-oauth2/issues/79#issuecomment-1002739804

I'm not sure where to go from here. It seems that something is missing here, but I'm not entirely sure what it is.

wagnerdelima commented 2 years ago

Unfortunately I never tried to use the apple sign on. I can try debugging this a little later once I am done with my current task.

denizdogan commented 2 years ago

I finally managed to get AppleID sign-in working, but not with the authorization code, rather with the identity token (which I didn't realize we receive from the SDK). Here is how it's done in SwiftUI:

SignInWithAppleButton(.continue) { request in
    request.requestedScopes = [.fullName, .email]
} onCompletion: { result in
    switch result {
    case .success(let authResults):
        switch authResults.credential {
        case let credential as ASAuthorizationAppleIDCredential:
            guard let identityToken = credential.identityToken else {
                print("no identity token received")
                return
            }
            let identityTokenString = String(decoding: identityToken, as: UTF8.self)
            // convert the identity token to an access token:
            // POST /auth/convert-token/
            // {
            //     "grant_type": "convert_token",
            //     "backend": "apple-id",
            //     "client_id": "<application ID>",
            //     "client_secret": "<application secret>",
            //     "token": identityTokenString
            // }
        default:
            // failed to get credentials
        }
    case .failure(let error):
        // sign-in failed
    }
}

Thanks to this comment in the deprecated repo: https://github.com/RealmTeam/django-rest-framework-social-oauth2/issues/241#issuecomment-932751527

Close this issue if you'd like, otherwise let's consider this issue to be about documenting this somewhere.

wagnerdelima commented 2 years ago

Hi @denizdogan I am happy you found a solution. I just saw your comment in the deprecated repo. Let's keep this issue open so I can document it!

SolomonPetrovich commented 1 year ago

Does anyone knows how to get identityToken form apple account for testing, for example google has OAuth2 playground? (https://developers.google.com/oauthplayground/)

wagnerdelima commented 1 year ago

@denizdogan @SolomonPetrovich did you find out how to create an apple app to get client id and client secret?

SolomonPetrovich commented 1 year ago

@denizdogan @SolomonPetrovich did you find out how to create an apple app to get client id and client secret?

Nope

denizdogan commented 1 year ago

@wagnerdelima I did manage to get it working after a lot of trial and error.

I don't have access to any of the actual code anymore, but this is pretty much how it works. Hopefully someone else can try this and get back to me and tell me if it works or not.

If this works, someone should document this properly, this comment is not good enough :)

# settings.py

# not sure if all three are needed here tbh
INSTALLED_APPS = [
  # ...
  "oauth2_provider",
  "social_django",
  "drf_social_oauth2",
  # ...
]

# add the apple id backend
AUTHENTICATION_BACKENDS = (
    "social_core.backends.apple.AppleIdAuth",
    "drf_social_oauth2.backends.DjangoOAuth2",
    "django.contrib.auth.backends.ModelBackend",
)

# configure apple id backend settings, i think all of these are mandatory?
SOCIAL_AUTH_APPLE_ID_CLIENT = # ...apple bundle id...
SOCIAL_AUTH_APPLE_ID_TEAM = # ...apple team id...
SOCIAL_AUTH_APPLE_ID_KEY = # ...apple key id...
SOCIAL_AUTH_APPLE_ID_SECRET = # ...apple key secret...
SOCIAL_AUTH_APPLE_ID_SCOPE = ["email", "name"]
// MyLoginButton.swift
struct MyLoginButton: View {
  func onRequest(_ request: ASAuthorizationAppleIDRequest) {
    request.requestedScopes = [.fullName, .email]
  }

  func onCompletion(_ result: Result<ASAuthorization, any Error>) {
    Task { @MainActor in
      do {
        guard
          case let .success(auth) = result,
          case let cred = auth.credential as! ASAuthorizationAppleIDCredential,
          let identity = cred.identityToken?.utf8 else {
            throw MyError.authFailed
          }
        // send this to the django backend:
        // POST /auth/convert-token/
        // {"token": <identity>, "backend": "apple-id"}
        // (the response will contain the token we want)
      } catch {
        // ...
      }
    }
  }

  var body: some View {
    SignInWithAppleButton(
      .continue,
      onRequest: self.onRequest,
      onCompletion: self.onCompletion
    )
  }
}
denizdogan commented 1 year ago

Sorry, maybe I misunderstood your question, was my response what you were looking for? I don't really remember.

wagnerdelima commented 1 year ago

The question was not how to set up the configuration. It's just that I have not found a way to create an apple application to get the apple key, apple secret etc. Do you know where to get those variables from?

denizdogan commented 1 year ago

@wagnerdelima Here's some example values, with some explanation below.

SOCIAL_AUTH_APPLE_ID_CLIENT = "com.foobar.MyApp"
SOCIAL_AUTH_APPLE_ID_TEAM = "FDHPXE33MD"
SOCIAL_AUTH_APPLE_ID_KEY = "3AB82BA21G"
SOCIAL_AUTH_APPLE_ID_SECRET = "-----BEGIN PRIVATE KEY-----\nVdH8so0J1DSjnWydQYEXIgBXJznkeOxL9UwKDuipH4KSDzbBF4ehTlbkui4eo3fB\nDk2qNRWtomLL1Rh0lqtmvQ7BdqqLXA8aYba7p12DWSIqP0ZOZsHPGTOmdSDXfkak\nfW9cT2tS7XxGtqtnm8mpHP9c8WzufCN7Cri6Co27ULUTz8MUPQebws7ugYiFT0Xf\n52F6BIw8\n-----END PRIVATE KEY-----"
SOCIAL_AUTH_APPLE_ID_SCOPE = ["email", "name"]

Obviously all values above are fake.

Additionally, you need to add the "Sign in with Apple" entitlement to your app. It's simple to do via "Signing & Capabilities" in your app project, and when done correctly you will have a .entitlements file in your app project root, and it will look like this:

Screenshot 2023-04-28 at 15 41 22

Hopefully this helps. I'm not 100% sure what is being asked exactly.

resuls commented 8 months ago

https://prog.world/django-drf-sign-in-with-apple/ This explains how to get the necessary stuff for Apple.

wagnerdelima commented 8 months ago

@resuls thank you for sharing! :)