Instagram login using ASWebAuthenticationSession

I am currently using the ability to log in with my Instagram account using ASWebAuthenticationSession and it is not working!

I filled in the URL directly and there was no problem on the web, but when I run it in SwiftUI in Xcode, it doesn't work and Error: The operation couldn’t be completed. (com.apple.AuthenticationServices.WebAuthenticationSession error 2.) I get this error.

I was told that I need a custom scheme to return to mobile, but the Instagram redirect URL says no custom scheme.

What should I do?

IDs and URLs are placed under assumption.

I have no idea since this is my first implementation. Should I send the scheme URL from the website to mobile once using Django or something else?

import SwiftUI
import AuthenticationServices

struct InstagramLoginView: View {
   @State private var authSession: ASWebAuthenticationSession?
   @State private var token: String = ""
   @State private var showAlert: Bool = false
   @State private var alertMessage: String = ""
   
   var body: some View {
       VStack {
           Text("Instagram Login")
               .font(.largeTitle)
               .padding()
           
           Button(action: {
               startInstagramLogin()
           }) {
               Text("Login with Instagram")
                   .padding()
                   .background(Color.blue)
                   .foregroundColor(.white)
                   .cornerRadius(10)
           }
           
           if !token.isEmpty {
               Text("Token: \(token)")
                   .padding()
           }
       }
       .alert(isPresented: $showAlert) {
           Alert(title: Text("Error"), message: Text(alertMessage), dismissButton: .default(Text("OK")))
       }
   }
   
   func startInstagramLogin() {
       let clientID = "XXXXXXXXXX" // Instagram client ID
       let redirectURI = "https://example.com" // Instagram Redirect URI
       
       guard let authURL = URL(string: "https://api.instagram.com/oauth/authorize?client_id=\(clientID)&redirect_uri=\(redirectURI)&scope=user_profile,user_media&response_type=code") else {
           print("Invalid URL")
           return
       }
       
       authSession = ASWebAuthenticationSession(url: authURL, callbackURLScheme: "customscheme") { callbackURL, error in
           if let error = error {
               print("Error: \(error.localizedDescription)")
               return
           }
           
           guard let callbackURL = callbackURL else {
               print("Invalid callback URL")
               return
           }
           
           if let code = URLComponents(string: callbackURL.absoluteString)?.queryItems?.first(where: { $0.name == "code" })?.value {
               print("Authorization code: \(code)")
     
               getInstagramAccessToken(authCode: code)
           }
       }
       authSession?.start()
   }
   func getInstagramAccessToken(authCode: String) {
       let tokenURL = "https://api.instagram.com/oauth/access_token"
       var request = URLRequest(url: URL(string: tokenURL)!)
       request.httpMethod = "POST"
       let clientID = "XXXXXXXXXXXX"
       let clientSecret = "XXXXXXXXXXXXXX" // Instagram clientSecret
       let redirectURI = "https://example.com/"
       
       let params = "client_id=\(clientID)&client_secret=\(clientSecret)&grant_type=authorization_code&redirect_uri=\(redirectURI)&code=\(authCode)"
       request.httpBody = params.data(using: .utf8)
       request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
       
       URLSession.shared.dataTask(with: request) { data, response, error in
           if let error = error {
               print("Error: \(error.localizedDescription)")
               return
           }
           
           guard let data = data else {
               print("No data")
               return
           }
           
           if let jsonResponse = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
              let accessToken = jsonResponse["access_token"] as? String {
               print("Access Token: \(accessToken)")
               // ここでアクセストークンを使用してInstagram APIにアクセスする
           } else {
               print("Failed to get access token")
           }
       }.resume()
   }

}

#Preview {
   InstagramLoginView()
}
Answered by Engineer in 808222022

Instagram would be the best people to ask for a supported mechanism on mobile apps.

Accepted Answer

Instagram would be the best people to ask for a supported mechanism on mobile apps.

Error code 2 here is ASWebAuthenticationSessionErrorCode.PresentationContextNotProvided, because you're not setting the presentationContextProvider on your ASWebAuthenticationSession instance. This method tells the system which window of your app to lay out relative to. Since you're in SwiftUI, there's a separate SwiftUI version of this API which handles the presentation context for you.

Also, starting in iOS 17.4, ASWebAuthenticationSession now supports callbacks using https URLs, in addition to custom schemes. Using https callbacks requires you to set up Associated Domains with your callback URL.

Putting those two things together would look something like

@Environment(\.webAuthenticationSession) private var webAuthenticationSession

func startInstagramLogin() {
    ...
    let callbackURL = try await webAuthenticationSession.authenticate(using: authURL, callback: .https(host: "mysite.com", path: "/myAuthEndpoint"))
    ...
}

Instagram login using ASWebAuthenticationSession
 
 
Q