Spotify token swap : unsupported URL error - ios

I'm trying to implement the token swap and refresh for the Spotify sdk. I'm using the Heroku app as a server. Here is my code.
In my Sign-in view controller:
var auth = SPTAuth.defaultInstance()!
var session: SPTSession!
var player: SPTAudioStreamingController?
SPTAuth.defaultInstance().clientID = "********************************"
SPTAuth.defaultInstance().redirectURL = URL(string: "viraj-project2://callback" )
SPTAuth.defaultInstance().tokenSwapURL = URL(string: "https://viraj-project2.herokuapp.com/v1/swap")
SPTAuth.defaultInstance().tokenRefreshURL = URL(string: "https://viraj-project2.herokuapp.com/v1/refresh")
SPTAuth.defaultInstance().requestedScopes = [SPTAuthStreamingScope, SPTAuthPlaylistReadPrivateScope, SPTAuthPlaylistModifyPublicScope, SPTAuthPlaylistModifyPrivateScope, SPTAuthUserLibraryReadScope, SPTAuthUserLibraryModifyScope]
loginUrl = SPTAuth.defaultInstance().spotifyWebAuthenticationURL()
#IBAction func signIn(_ sender: Any) {
self.performSegue(withIdentifier: "toNewsFeed", sender: self)
if SPTAuth.supportsApplicationAuthentication() {
UIApplication.shared.open(loginUrl!, options: [:], completionHandler: nil)
} else {
if UIApplication.shared.openURL(loginUrl!) {
if auth.canHandle(auth.redirectURL) {
// To do - build in error handling
}
}
}
}
and in my AppDelegate
class AppDelegate: UIResponder, UIApplicationDelegate{
var window: UIWindow?
var auth = SPTAuth()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
auth.redirectURL = URL(string: "viraj-project2")
auth.sessionUserDefaultsKey = "current session"
// Override point for customization after application launch.
return true
}
func application(_ application: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
// 2- check if app can handle redirect URL
if auth.canHandle(auth.redirectURL) {
// 3 - handle callback in closure
print (url)
auth.handleAuthCallback(withTriggeredAuthURL: url, callback: { (error, session) in
// 4- handle error
if error != nil {
print(error)
print("error!")
}
NotificationCenter.default.post(name: Notification.Name(rawValue: "loggedinperformsegue"), object: nil)
// 5- Add session to User Defaults
let userDefaults = UserDefaults.standard
let sessionData = NSKeyedArchiver.archivedData(withRootObject: session!)
userDefaults.set(sessionData, forKey: "SpotifySession")
userDefaults.synchronize()
// 6 - Tell notification center login is successful
NotificationCenter.default.post(name: Notification.Name(rawValue: "loginSuccessfull"), object: nil)
})
return true
}
return false
}
The authentication works fine without adding the swap and refresh URLs. But whenever I run it with the two URLS added to the SPTAuth.defaultInstance() I get a unsupported URL error like so:
viraj-project2://callback/?code=AQDhKLE9s5GQGITEn**********5_y9aKZM6_nSlzA
2018-09-14 16:55:08.258063-0400 Project2[17606:3197471] NSURLConnection finished with error - code -1002
Optional(Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL" UserInfo={NSLocalizedDescription=unsupported URL, NSUnderlyingError=0x109385130 {Error Domain=kCFErrorDomainCFNetwork Code=-1002 "unsupported URL" UserInfo={NSLocalizedDescription=unsupported URL}}})
error!
Can someone help?
Update on further digging:
When I include add the tokenSwapURL and tokenRefreshURL to my default instance the loginUrl formed looks like so
"https://accounts.spotify.com/authorize?nolinks=true&nosignup=true&response_type=code&scope=streaming%20playlist-read-private%20playlist-modify-public%20playlist-modify-private%20user-library-read%20user-library-modify&utm_source=spotify-sdk&utm_medium=ios-sdk&utm_campaign=ios-sdk&redirect_uri=viraj-project2%3A%2F%2Fcallback&show_dialog=true&client_id=****************"
The response type is "code" which as per the documentation is the right one according to Authorization Flow. But this is what returns the unsupported URL error.
Without the swap and refresh URLs the loginURL looks the same except that the response_type says "token". And this works fine. Is that right though? Doesn't response_type = token mean implicit grant flow?
https://developer.spotify.com/documentation/general/guides/authorization-guide/#client-credentials-flow

Related

TikTok LoginKit iOS Integration Issue

I am implementing social login with TikTok in my app, From official documentation I implemented Basic setup and connected with my AppDelegate https://developers.tiktok.com/doc/getting-started-ios-quickstart-swift. Implemented loginkit with there sample code but request.send completionBlock is not getting any response or do not enter into completion block after we authorised from TikTok app. Please help if any one has implemented tiktok login kit in iOS.
/* STEP 1 */
let scopes = "user.info.basic,video.list" // list your scopes
let scopesSet = NSOrderedSet(array:scopes)
let request = TikTokOpenSDKAuthRequest()
request.permissions = scopesSet
/* STEP 2 */
request.send(self, completion: { resp -> Void in
/* STEP 3 */
if resp.errCode == 0 {
/* STEP 3.a */
let clientKey = ... // you will receive this once you register in the Developer Portal
let responseCode = resp.code
// replace this baseURLstring with your own wrapper API
let baseURlString = "https://open-api.tiktok.com/demoapp/callback/?code=\(responseCode)&client_key=\(clientKey)"
let url = NSURL(string: baseURlstring)
/* STEP 3.b */
let session = URLSession(configuration: .default)
let urlRequest = NSMutableURLRequest(url: url! as URL)
let task = session.dataTask(with: urlRequest as URLRequest) { (data, response, error) -> Void in
/* STEP 3.c */
}
task.resume()
} else {
// handle error
}
}
Thanks to author's comment I figured that out too. In my case, there was no SceneDelegate in the project, so I had 3 url-related methods implemented in AppDelegate as per TikTok's documentation:
1:
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool
2:
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any)
3:
func application(_ application: UIApplication, handleOpen url: URL) -> Bool
The docs also suggested that 1st method should use a default value of [:] for options, which is plainly wrong so I removed it.
I also had Firebase dynamic links implemented in the 1st method:
if let dynamicLink = DynamicLinks.dynamicLinks().dynamicLink(fromCustomSchemeURL: url) {
self.handleDynamicLink(dynamicLink)
return true
}
Turns out, if you remove the 1st method completely and move Firebase DL handling to method #2 everything starts working! Dynamic links are handled and TT's completion block finally gets called

iOS 12 - AppAuth redirect URL not trigger AppDelegate

I am using AppAuth on my code.
I manage to authenticate successful , but when the SFSafariViewController gets dismiss from my Controller , the redirect url does not trigger the AppDelegate func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool
The redirect URL is my Bundle Identifier name : BundleIdentifier://authenticate
I have setup in info.plist url Schemes and url identifier which they have the same name.
When I run my code setting a break point on this func I can see my redirect url correct for standarizedURL and standarizedRedirectURL
- (BOOL)shouldHandleURL:(NSURL *)URL {
NSURL *standardizedURL = [URL standardizedURL];
NSURL *standardizedRedirectURL = [_request.redirectURL standardizedURL];
return OIDIsEqualIncludingNil(standardizedURL.scheme, standardizedRedirectURL.scheme) &&
OIDIsEqualIncludingNil(standardizedURL.user, standardizedRedirectURL.user) &&
OIDIsEqualIncludingNil(standardizedURL.password, standardizedRedirectURL.password) &&
OIDIsEqualIncludingNil(standardizedURL.host, standardizedRedirectURL.host) &&
OIDIsEqualIncludingNil(standardizedURL.port, standardizedRedirectURL.port) &&
OIDIsEqualIncludingNil(standardizedURL.path, standardizedRedirectURL.path);
But when AppAuth finishes the authentication and I have an access token , func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool doesn't get triggered.
Any idea why?
Here is my code
class func signInAuth(discoveryURLstr: String,presenter : UIViewController,completionHandler: #escaping ( (OIDAuthState?,Error?) -> () )){
guard let discoveruURL = URL(string: discoveryURLstr) else{
completionHandler(nil,AuthErrors.InvalidDiscoveryURL)
return
}
appAuthDiscoverConfiguration(discoveryURL: discoveruURL) { (configurationFile, error) in
guard let configurationFile = configurationFile else {
completionHandler(nil,AuthErrors.InvalidConfigurationFile)
return
}
let authRequest = appAuthRequest(configurationFile: configurationFile)
self.appAuthenticationSession = OIDAuthState.authState(byPresenting: authRequest, presenting: presenter, callback: { (state, error) in
if let error = error {
//self.authState = nil
completionHandler(nil,error)
return
}
if let state = state {
self.authState = state
completionHandler(state,nil)
}else{
completionHandler(nil,AuthErrors.InvalideState)
}
})
}
}
class func appAuthDiscoverConfiguration(discoveryURL : URL, completionHandler: #escaping ((OIDServiceConfiguration?,Error?) -> ())) {
OIDAuthorizationService.discoverConfiguration(forDiscoveryURL: discoveryURL) { (configuration, error) in
if let error = error {
completionHandler(nil,error)
return
}else{
guard let configurationFile = configuration else {
completionHandler(nil,AuthErrors.InvalidConfigurationFile)
return
}
completionHandler(configurationFile,nil)
}
}
}
class func appAuthRequest(configurationFile : OIDServiceConfiguration) -> OIDAuthorizationRequest{
return OIDAuthorizationRequest(configuration: configurationFile, clientId: AppAuthConstants.clientId, clientSecret: nil, scope: AppAuthConstants.scope, redirectURL: AppAuthConstants.redirectURL, responseType: AppAuthConstants.responseType, state: nil, nonce: nil, codeVerifier: nil, codeChallenge: nil, codeChallengeMethod: nil, additionalParameters: AppAuthConstants.additionalParameters)
}
On iOS 12, App-Auth uses ASWebAuthenticationSession, and on iOS 11, it uses the now-deprecated SFAuthenticationSession instead of requiring the app to support handling the redirect manually. To support earlier versions of iOS, you still need your code in the func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool method.
For reference, you can see what AppAuth is doing under the covers here. Also, this is a great answer that explains how to generically get an OAuth token on iOS without using AppAuth.

Got an "configurationError" when sending a transaction in Xcode

When I try to send a transaction on the Aion network, I keep getting the "configurationError". I am using Xcode to create my IOS dApp.
The code i have to send a transaction is:
#IBAction func sendTxButton(_ sender: Any) {
//deleted my address and pk
let address = "0x0"
let privateKey = "0x0"
let nonce = BigInt.init(3)
let to = "0xa0d969df9232b45239b577c3790887081b5a22ffd5a46a8d82584ee560485624"
let value = BigInt.init(10000000)
let nrgPrice = BigInt.init(10000000000)
let nrg = BigInt.init(21000)
var txParams = [AnyHashable: Any]()
txParams["nonce"] = HexStringUtil.prependZeroX(hex: nonce.toString(radix: 16))
txParams["to"] = to
txParams["data"] = ""
txParams["value"] = HexStringUtil.prependZeroX(hex: value.toString(radix: 16))
txParams["nrgPrice"] = HexStringUtil.prependZeroX(hex: nrgPrice.toString(radix: 16))
txParams["nrg"] = HexStringUtil.prependZeroX(hex: nrg.toString(radix: 16))
do {
let importWallet = try PocketAion.importWallet(privateKey: privateKey, subnetwork: "32", address: address, data: nil)
try PocketAion.eth.sendTransaction(wallet: importWallet, nonce: nonce, to: to, data: "", value: value, nrgPrice: nrgPrice, nrg: nrg, handler: { (result, error) in
if error != nil {
print(error!)
return
} else {
print("the hash:", result!)
}
})
} catch{
print(error)
}
}
I have met all of the requirements on sending a transaction, but cant figure out what is wrong.(this is for sending test tokens on the Aion test net "32").
check your AppDelegates class. make sure you have added "configuration" and point it to the right URL and under the application function you make sure you have the configuration is set to "self".
class AppDelegate: UIResponder, UIApplicationDelegate, Configuration {
public var nodeURL: URL{
get {
return URL.init(string: "https://aion.pokt.network")!
}
}
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
PocketAion.shared.setConfiguration(config: self)
return true
}

Show Facebook Events in Swift 3

How can I store Facebook events in an array using Swift 3? I have the following code which I pretty much copied from The Swift Guy but it doesn't work for this code. The following is in my viewDidLoad() function:
let url = URL(string: "https://www.facebook.com/events/upcoming")
let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil {
print("ERROR")
} else {
if let content = data {
do {
let myJson = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
print(myJson)
} catch {
print("error")
}
}
}
}
task.resume()
How can I get the information from the Facebook Events page? I should mention that I'm good at coding, but I'm a beginner when it comes to Swift so some explanation as to what each line does would be very helpful. Thanks!
The URL you're requesting returns an HTML page that you're trying to parse as if it was a JSON resource. You'll have to use the Facebook Graph API and/or the Facebook Swift SDK to get the information as JSON.
Try reading the Facebook developer documentation for more information:
https://developers.facebook.com/docs/swift
https://developers.facebook.com/docs/graph-api
Also, Swift Error objects contain information that can help you understand what went wrong. You can print them to the console. Try this:
if error != nil {
print(error)
} else {
// ...
The catch statement also sets its own error variable inside its block, so you can use:
} catch {
print(error)
}
Make sure you understand the steps involved in creating a Facebook app: registering the app with Facebook, downloading the SDK, adding the SDK to your project, configuring the SDK for your app, logging in to Facebook in your app and then calling the Facebook Graph API to get the information. These steps are all described in the Facebook documentation mentioned above. I'd start with the iOS SDK (Objective-C) instructions to setup your project and then change your app delegate and view controller to the following:
AppDelegate.swift:
import UIKit
import FacebookCore
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
SDKApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
return true
}
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
return SDKApplicationDelegate.shared.application(app, open: url, options: options)
}
}
ViewController.swift:
import UIKit
import FacebookCore
import FacebookLogin
class ViewController: UIViewController, LoginButtonDelegate {
override func viewDidLoad() {
super.viewDidLoad()
if let _ = AccessToken.current {
loadEvents()
}
let loginButton = LoginButton(readPermissions: [ .publicProfile, .userEvents ])
loginButton.center = view.center
loginButton.delegate = self
view.addSubview(loginButton)
}
func loginButtonDidCompleteLogin(_ loginButton: LoginButton, result: LoginResult) {
if let _ = AccessToken.current {
loadEvents()
}
}
func loginButtonDidLogOut(_ loginButton: LoginButton) {
// Logout handling code here
}
func loadEvents() {
let connection = GraphRequestConnection()
connection.add(GraphRequest(graphPath: "/me/events")) { httpResponse, result in
switch result {
case .success(let response):
print("Graph Request Succeeded: \(response)")
case .failed(let error):
print("Graph Request Failed: \(error)")
}
}
connection.start()
}
}
The response object will contain the Facebook Events information, already parsed.

Square API + OAuth2: How do I set my redirect URL to my iOS app?

I am trying to implement OAuth2 in my iOS app through Square but it's saying there is an error with my redirect_uri when I sign in successfully through the browser that pops up.
I'm using the OAuthSwift pod. This is what I have so far to set up the URL scheme so that the redirect should open my iOS app:
Square dashboard config:
AppDelegate:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
print("hollaaaaaaaaaaaaaaaaa") // i never see this printed
OAuthSwift.handle(url: url)
return true
}
}
Target:
Controller that opens the browser:
class OAuthViewController: UIViewController {
#IBAction func signInButtonTapped(_ sender: AnyObject) {
print("tapped");
let oauthswift = OAuth2Swift(
consumerKey: "my token",
consumerSecret: "my secret",
authorizeUrl: "https://connect.squareup.com/oauth2/authorize?client_id=my_id",
responseType: "token"
)
oauthswift.authorize(
withCallbackURL: URL(string: "com.edmund.ios/oauth-callback")!, // doesn't seem to do anything honestly... I think the Square dashboard setting has precedence over this.
scope: "MERCHANT_PROFILE_READ%20PAYMENTS_READ%20ITEMS_READ%20ORDERS_READ",
state: "",
success: { (credential, response, parameters) -> Void in
print(credential)
},
failure: { error in
print(error.localizedDescription)
}
)
}
}
Redirect to ios app is possible? Completly possible
Here I will guide you simple approach to achieve this.
The square oAuth implementation can achieve by 2 simple easy steps without using any third-party libraries.
Benefits of this approach
You always stay within the application (because we use the in-app browser)
No need to add URI schema in the application (because we never leave the app)
Step 1: Add a view controller and attach a WKWebview;
Step 2: Load auth request URL and listen for redirect URI;
You can dismiss the controller and proceed with the access token once the redirection happens.
Redirect URI
You have to set a redirect URI in the square dashboard;
(Example: "http://localhost/square-oauth-callback")
but you are free to set any valid URL.
We monitor this url within our app.
Implement the following code in your application
import Foundation
import UIKit
import WebKit
class SquareAuthenticationViewController: UIViewController {
// MARK: Connection Objects
#IBOutlet weak var webView: WKWebView!
// MARK: Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
configureView()
initiateAuthentication()
}
func configureView() {
webView.navigationDelegate = self
}
func initiateAuthentication() {
// Validation
guard let url = getPath() else {
return
}
// Prepare request
let request = URLRequest(url: url)
webView.load(request)
}
func getPath() -> URL? {
let clientId = "Your Suare Application Id"
let scope = ["MERCHANT_PROFILE_READ",
"CUSTOMERS_READ",
"CUSTOMERS_WRITE",
"EMPLOYEES_READ",
"EMPLOYEES_WRITE",
"ITEMS_READ",
"PAYMENTS_READ"].joined(separator: " ")
let queryClientId = URLQueryItem(name: "client_id" , value: clientId.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed))
let queryScope = URLQueryItem(name: "scope" , value: scope.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed))
var components = URLComponents()
components.scheme = "https"
components.host = "connect.squareup.com"
components.path = "/oauth2/authorize"
components.percentEncodedQueryItems = [queryClientId, queryScope]
return components.url
}
}
extension SquareAuthenticationViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
// here we handle internally the callback url and call method that call handleOpenURL (not app scheme used)
if let url = navigationAction.request.url, url.host == "localhost" , url.path == "/square-oauth-callback" {
print(url)
print(url.valueOf("code"))
//decisionHandler(.cancel)
/* Dismiss your view controller as normal
And proceed with OAuth authorization code
The code you receive here is not the auth token; For auth token you have to make another api call with the code that you received here and you can procced further
*/
/*
Auth Process Flow: https://developer.squareup.com/docs/oauth-api/how-it-works#oauth-access-token-management
Obtain Auth Token: https://developer.squareup.com/reference/square/oauth-api/obtain-token
*/
}
decisionHandler(.allow)
}
}
extension URL {
func valueOf(_ queryParamaterName: String) -> String? {
guard let url = URLComponents(string: self.absoluteString) else { return nil }
return url.queryItems?.first(where: { $0.name == queryParamaterName })?.value
}
}
When you guide a user through the oauth flow for your app, you must specify a redirect_uri parameter that matches that value you have specified in the Square developer portal. Note that this redirect_uri must start with http or https and correspond to a webpage on your server.
If you redirect the square endpoint to your server, if your sure they are running on iOS you can use your URL Scheme to reopen your app and pass any parameters that you wish

Resources