{"id":15028920,"url":"https://github.com/openid/appauth-ios","last_synced_at":"2025-04-23T20:51:47.879Z","repository":{"id":37458357,"uuid":"51520488","full_name":"openid/AppAuth-iOS","owner":"openid","description":"iOS and macOS SDK for communicating with OAuth 2.0 and OpenID Connect providers.","archived":false,"fork":false,"pushed_at":"2025-04-16T14:08:41.000Z","size":2270,"stargazers_count":1840,"open_issues_count":222,"forks_count":797,"subscribers_count":96,"default_branch":"master","last_synced_at":"2025-04-18T09:54:22.051Z","etag":null,"topics":["ios-sdk","oauth2","openid-connect"],"latest_commit_sha":null,"homepage":"https://openid.github.io/AppAuth-iOS","language":"Objective-C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/openid.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-02-11T14:38:23.000Z","updated_at":"2025-04-18T00:25:27.000Z","dependencies_parsed_at":"2024-11-05T23:03:17.267Z","dependency_job_id":"4c692489-7da0-4c61-afdb-48fd9b79c1b5","html_url":"https://github.com/openid/AppAuth-iOS","commit_stats":{"total_commits":343,"total_committers":59,"mean_commits":5.813559322033898,"dds":0.5626822157434402,"last_synced_commit":"b856e4bdf4d3f5063c933bd103b70541751f8437"},"previous_names":[],"tags_count":45,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openid%2FAppAuth-iOS","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openid%2FAppAuth-iOS/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openid%2FAppAuth-iOS/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openid%2FAppAuth-iOS/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/openid","download_url":"https://codeload.github.com/openid/AppAuth-iOS/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250514756,"owners_count":21443208,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ios-sdk","oauth2","openid-connect"],"created_at":"2024-09-24T20:09:21.071Z","updated_at":"2025-04-23T20:51:47.865Z","avatar_url":"https://github.com/openid.png","language":"Objective-C","funding_links":[],"categories":[],"sub_categories":[],"readme":"![AppAuth for iOS and macOS](https://rawgit.com/openid/AppAuth-iOS/master/appauth_lockup.svg)\n[![tests](https://github.com/openid/AppAuth-iOS/actions/workflows/tests.yml/badge.svg?event=push)](https://github.com/openid/AppAuth-iOS/actions/workflows/tests.yml)\n[![codecov](https://codecov.io/gh/openid/AppAuth-iOS/branch/master/graph/badge.svg)](https://codecov.io/gh/openid/AppAuth-iOS)\n[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-brightgreen.svg?style=flat)](https://github.com/Carthage/Carthage)\n[![SwiftPM compatible](https://img.shields.io/badge/SwiftPM-compatible-brightgreen.svg?style=flat)](https://swift.org/package-manager)\n[![Pod Version](https://img.shields.io/cocoapods/v/AppAuth.svg?style=flat)](https://cocoapods.org/pods/AppAuth)\n[![Pod License](https://img.shields.io/cocoapods/l/AppAuth.svg?style=flat)](https://github.com/openid/AppAuth-iOS/blob/master/LICENSE)\n[![Pod Platform](https://img.shields.io/cocoapods/p/AppAuth.svg?style=flat)](https://cocoapods.org/pods/AppAuth)\n[![Catalyst compatible](https://img.shields.io/badge/Catalyst-compatible-brightgreen.svg?style=flat)](https://developer.apple.com/documentation/xcode/creating_a_mac_version_of_your_ipad_app)\n\nAppAuth for iOS and macOS, and tvOS is a client SDK for communicating with \n[OAuth 2.0](https://tools.ietf.org/html/rfc6749) and \n[OpenID Connect](http://openid.net/specs/openid-connect-core-1_0.html) providers. \nIt strives to\ndirectly map the requests and responses of those specifications, while following\nthe idiomatic style of the implementation language. In addition to mapping the\nraw protocol flows, convenience methods are available to assist with common\ntasks like performing an action with fresh tokens.\n\nIt follows the best practices set out in \n[RFC 8252 - OAuth 2.0 for Native Apps](https://tools.ietf.org/html/rfc8252)\nincluding using `SFAuthenticationSession` and `SFSafariViewController` on iOS\nfor the auth request. `UIWebView` and `WKWebView` are explicitly *not*\nsupported due to the security and usability reasons explained in\n[Section 8.12 of RFC 8252](https://tools.ietf.org/html/rfc8252#section-8.12).\n\nIt also supports the [PKCE](https://tools.ietf.org/html/rfc7636) extension to\nOAuth, which was created to secure authorization codes in public clients when\ncustom URI scheme redirects are used. The library is friendly to other\nextensions (standard or otherwise), with the ability to handle additional params\nin all protocol requests and responses.\n\nFor tvOS, AppAuth implements [OAuth 2.0 Device Authorization Grant\n](https://tools.ietf.org/html/rfc8628) to allow for tvOS sign-ins through a secondary device.\n\n## Specification\n\n### iOS\n\n#### Supported Versions\n\nAppAuth supports iOS 12 and above.\n\niOS 9+ uses the in-app browser tab pattern\n(via `SFSafariViewController`), and falls back to the system browser (mobile\nSafari) on earlier versions.\n\n#### Authorization Server Requirements\n\nBoth Custom URI Schemes (all supported versions of iOS) and Universal Links\n(iOS 9+) can be used with the library.\n\nIn general, AppAuth can work with any authorization server that supports\nnative apps, as documented in [RFC 8252](https://tools.ietf.org/html/rfc8252),\neither through custom URI scheme redirects, or universal links.\nAuthorization servers that assume all clients are web-based, or require clients to maintain\nconfidentiality of the client secrets may not work well.\n\n### macOS\n\n#### Supported Versions\n\nAppAuth supports macOS (OS X) 10.9 and above.\n\n#### Authorization Server Requirements\n\nAppAuth for macOS supports both custom schemes; a loopback HTTP redirects\nvia a small embedded server.\n\nIn general, AppAuth can work with any authorization server that supports\nnative apps, as documented in [RFC 8252](https://tools.ietf.org/html/rfc8252);\neither through custom URI schemes, or loopback HTTP redirects.\nAuthorization servers that assume all clients are web-based, or require clients to maintain\nconfidentiality of the client secrets may not work well.\n\n### tvOS\n\n#### Supported Versions\n\nAppAuth supports tvOS 9.0 and above. Please note that while it is possible to run the standard AppAuth library on tvOS, the documentation below describes implementing [OAuth 2.0 Device Authorization Grant](https://tools.ietf.org/html/rfc8628) (AppAuthTV).\n\n#### Authorization Server Requirements\n\nAppAuthTV is designed for servers that support the device authorization flow as documented in [RFC 8628](https://tools.ietf.org/html/rfc8628).\n\n## Try\n\nWant to try out AppAuth? Just run:\n\n    pod try AppAuth\n\nFollow the instructions in [Examples/README.md](Examples/README.md) to configure\nwith your own OAuth client (you need to update three configuration points with your\nclient info to try the demo).\n\n## Setup\n\nAppAuth supports four options for dependency management.\n\n### CocoaPods\n\nWith [CocoaPods](https://guides.cocoapods.org/using/getting-started.html),\nadd the following line to your `Podfile`:\n\n    pod 'AppAuth'\n\nThen, run `pod install`.\n\n**tvOS:** Use the `TV` subspec:\n\n    pod 'AppAuth/TV'\n\n\n### Swift Package Manager\n\nWith [Swift Package Manager](https://swift.org/package-manager), \nadd the following `dependency` to your `Package.swift`:\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/openid/AppAuth-iOS.git\", .upToNextMajor(from: \"1.3.0\"))\n]\n```\n\n**tvOS:** Use the `AppAuthTV` target.\n\n### Carthage\n\nWith [Carthage](https://github.com/Carthage/Carthage), add the following\nline to your `Cartfile`:\n\n    github \"openid/AppAuth-iOS\" \"master\"\n\nThen, run `carthage bootstrap`.\n\n**tvOS:** Use the `AppAuthTV` framework.\n\n### Static Library\n\nYou can also use AppAuth as a static library. This requires linking the library\nand your project, and including the headers.  Here is a suggested configuration:\n\n1. Create an Xcode Workspace.\n2. Add `AppAuth.xcodeproj` to your Workspace.\n3. Include libAppAuth as a linked library for your target (in the \"General -\u003e\nLinked Framework and Libraries\" section of your target).\n4. Add `AppAuth-iOS/Source` to your search paths of your target (\"Build Settings -\u003e\n\"Header Search Paths\").\n\n*Note: There is no static library for AppAuthTV.*\n\n## Auth Flow\n\nAppAuth supports both manual interaction with the authorization server\nwhere you need to perform your own token exchanges, as well as convenience\nmethods that perform some of this logic for you. This example uses the\nconvenience method, which returns either an `OIDAuthState` object, or an error.\n\n`OIDAuthState` is a class that keeps track of the authorization and token\nrequests and responses, and provides a convenience method to call an API with\nfresh tokens. This is the only object that you need to serialize to retain the\nauthorization state of the session.\n\n### Configuration\n\nYou can configure AppAuth by specifying the endpoints directly:\n\n\u003csub\u003eObjective-C\u003c/sub\u003e\n```objc\nNSURL *authorizationEndpoint =\n    [NSURL URLWithString:@\"https://accounts.google.com/o/oauth2/v2/auth\"];\nNSURL *tokenEndpoint =\n    [NSURL URLWithString:@\"https://www.googleapis.com/oauth2/v4/token\"];\n\nOIDServiceConfiguration *configuration =\n    [[OIDServiceConfiguration alloc]\n        initWithAuthorizationEndpoint:authorizationEndpoint\n                        tokenEndpoint:tokenEndpoint];\n\n// perform the auth request...\n```\n\n\u003csub\u003eSwift\u003c/sub\u003e\n```swift\nlet authorizationEndpoint = URL(string: \"https://accounts.google.com/o/oauth2/v2/auth\")!\nlet tokenEndpoint = URL(string: \"https://www.googleapis.com/oauth2/v4/token\")!\nlet configuration = OIDServiceConfiguration(authorizationEndpoint: authorizationEndpoint,\n                                            tokenEndpoint: tokenEndpoint)\n\n// perform the auth request...\n```\n\n**tvOS**\n\n\u003csub\u003eObjective-C\u003c/sub\u003e\n```objc\nNSURL *deviceAuthorizationEndpoint =\n    [NSURL URLWithString:@\"https://oauth2.googleapis.com/device/code\"];\nNSURL *tokenEndpoint =\n    [NSURL URLWithString:@\"https://www.googleapis.com/oauth2/v4/token\"];\n\nOIDTVServiceConfiguration *configuration =\n    [[OIDTVServiceConfiguration alloc]\n        initWithDeviceAuthorizationEndpoint:deviceAuthorizationEndpoint\n                              tokenEndpoint:tokenEndpoint];\n\n// perform the auth request...\n```\n\n\nOr through discovery:\n\n\u003csub\u003eObjective-C\u003c/sub\u003e\n```objc\nNSURL *issuer = [NSURL URLWithString:@\"https://accounts.google.com\"];\n\n[OIDAuthorizationService discoverServiceConfigurationForIssuer:issuer\n    completion:^(OIDServiceConfiguration *_Nullable configuration,\n                 NSError *_Nullable error) {\n\n  if (!configuration) {\n    NSLog(@\"Error retrieving discovery document: %@\",\n          [error localizedDescription]);\n    return;\n  }\n\n  // perform the auth request...\n}];\n```\n\n\u003csub\u003eSwift\u003c/sub\u003e\n```swift\nlet issuer = URL(string: \"https://accounts.google.com\")!\n\n// discovers endpoints\nOIDAuthorizationService.discoverConfiguration(forIssuer: issuer) { configuration, error in\n  guard let config = configuration else {\n    print(\"Error retrieving discovery document: \\(error?.localizedDescription ?? \"Unknown error\")\")\n    return\n  }\n\n  // perform the auth request...\n}\n```\n\n**tvOS**\n\n\u003csub\u003eObjective-C\u003c/sub\u003e\n```objc\nNSURL *issuer = [NSURL URLWithString:@\"https://accounts.google.com\"];\n\n[OIDTVAuthorizationService discoverServiceConfigurationForIssuer:issuer\n    completion:^(OIDTVServiceConfiguration *_Nullable configuration,\n                 NSError *_Nullable error) {\n\n  if (!configuration) {\n    NSLog(@\"Error retrieving discovery document: %@\",\n          [error localizedDescription]);\n    return;\n  }\n\n  // perform the auth request...\n}];\n```\n\n### Authorizing – iOS\n\nFirst, you need to have a property in your `UIApplicationDelegate`\nimplementation to hold the session, in order to continue the authorization flow\nfrom the redirect. In this example, the implementation of this delegate is\na class named `AppDelegate`, if your app's application delegate has a different\nname, please update the class name in samples below accordingly.\n\n\u003csub\u003eObjective-C\u003c/sub\u003e\n```objc\n@interface AppDelegate : UIResponder \u003cUIApplicationDelegate\u003e\n// property of the app's AppDelegate\n@property(nonatomic, strong, nullable) id\u003cOIDExternalUserAgentSession\u003e currentAuthorizationFlow;\n@end\n```\n\n\u003csub\u003eSwift\u003c/sub\u003e\n```swift\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n  // property of the app's AppDelegate\n  var currentAuthorizationFlow: OIDExternalUserAgentSession?\n}\n```\n\n\nAnd your main class, a property to store the auth state:\n\n\u003csub\u003eObjective-C\u003c/sub\u003e\n```objc\n// property of the containing class\n@property(nonatomic, strong, nullable) OIDAuthState *authState;\n```\n\u003csub\u003eSwift\u003c/sub\u003e\n```swift\n// property of the containing class\nprivate var authState: OIDAuthState?\n```\n\n\nThen, initiate the authorization request. By using the \n`authStateByPresentingAuthorizationRequest` convenience method, the token\nexchange will be performed automatically, and everything will be protected with\nPKCE (if the server supports it). AppAuth also lets you perform these\nrequests manually. See the `authNoCodeExchange` method in the included Example\napp for a demonstration:\n\n\u003csub\u003eObjective-C\u003c/sub\u003e\n```objc\n// builds authentication request\nOIDAuthorizationRequest *request =\n    [[OIDAuthorizationRequest alloc] initWithConfiguration:configuration\n                                                  clientId:kClientID\n                                                    scopes:@[OIDScopeOpenID,\n                                                             OIDScopeProfile]\n                                               redirectURL:kRedirectURI\n                                              responseType:OIDResponseTypeCode\n                                      additionalParameters:nil];\n\n// performs authentication request\nAppDelegate *appDelegate =\n    (AppDelegate *)[UIApplication sharedApplication].delegate;\nappDelegate.currentAuthorizationFlow =\n    [OIDAuthState authStateByPresentingAuthorizationRequest:request\n        presentingViewController:self\n                        callback:^(OIDAuthState *_Nullable authState,\n                                   NSError *_Nullable error) {\n  if (authState) {\n    NSLog(@\"Got authorization tokens. Access token: %@\",\n          authState.lastTokenResponse.accessToken);\n    [self setAuthState:authState];\n  } else {\n    NSLog(@\"Authorization error: %@\", [error localizedDescription]);\n    [self setAuthState:nil];\n  }\n}];\n```\n\n\u003csub\u003eSwift\u003c/sub\u003e\n```swift\n// builds authentication request\nlet request = OIDAuthorizationRequest(configuration: configuration,\n                                      clientId: clientID,\n                                      clientSecret: clientSecret,\n                                      scopes: [OIDScopeOpenID, OIDScopeProfile],\n                                      redirectURL: redirectURI,\n                                      responseType: OIDResponseTypeCode,\n                                      additionalParameters: nil)\n\n// performs authentication request\nprint(\"Initiating authorization request with scope: \\(request.scope ?? \"nil\")\")\n\nlet appDelegate = UIApplication.shared.delegate as! AppDelegate\n\nappDelegate.currentAuthorizationFlow =\n    OIDAuthState.authState(byPresenting: request, presenting: self) { authState, error in\n  if let authState = authState {\n    self.setAuthState(authState)\n    print(\"Got authorization tokens. Access token: \" +\n          \"\\(authState.lastTokenResponse?.accessToken ?? \"nil\")\")\n  } else {\n    print(\"Authorization error: \\(error?.localizedDescription ?? \"Unknown error\")\")\n    self.setAuthState(nil)\n  }\n}\n```\n\n*Handling the Redirect*\n\nThe authorization response URL is returned to the app via the iOS openURL\napp delegate method, so you need to pipe this through to the current\nauthorization session (created in the previous session):\n\n\u003csub\u003eObjective-C\u003c/sub\u003e\n```objc\n- (BOOL)application:(UIApplication *)app\n            openURL:(NSURL *)url\n            options:(NSDictionary\u003cNSString *, id\u003e *)options {\n  // Sends the URL to the current authorization flow (if any) which will\n  // process it if it relates to an authorization response.\n  if ([_currentAuthorizationFlow resumeExternalUserAgentFlowWithURL:url]) {\n    _currentAuthorizationFlow = nil;\n    return YES;\n  }\n\n  // Your additional URL handling (if any) goes here.\n\n  return NO;\n}\n```\n\n\u003csub\u003eSwift\u003c/sub\u003e\n```swift\nfunc application(_ app: UIApplication,\n                 open url: URL,\n                 options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -\u003e Bool {\n  // Sends the URL to the current authorization flow (if any) which will\n  // process it if it relates to an authorization response.\n  if let authorizationFlow = self.currentAuthorizationFlow,\n                             authorizationFlow.resumeExternalUserAgentFlow(with: url) {\n    self.currentAuthorizationFlow = nil\n    return true\n  }\n\n  // Your additional URL handling (if any)\n\n  return false\n}\n```\n\n### Authorizing – MacOS\n\nOn macOS, the most popular way to get the authorization response redirect is to\nstart a local HTTP server on the loopback interface (limited to incoming\nrequests from the user's machine only). When the authorization is complete, the\nuser is redirected to that local server, and the authorization response can be\nprocessed by the app. AppAuth takes care of managing the local HTTP server\nlifecycle for you.\n\n\u003e #### :bulb: Alternative: Custom URI Schemes\n\u003e Custom URI schemes are also supported on macOS, but some browsers display\n\u003e an interstitial, which reduces the usability. For an example on using custom\n\u003e URI schemes with macOS, See `Example-Mac`.\n\nTo receive the authorization response using a local HTTP server, first you need\nto have an instance variable in your main class to retain the HTTP redirect\nhandler:\n\n\u003csub\u003eObjective-C\u003c/sub\u003e\n```objc\nOIDRedirectHTTPHandler *_redirectHTTPHandler;\n```\n\nThen, as the port used by the local HTTP server varies, you need to start it\nbefore building the authorization request, in order to get the exact redirect\nURI to use:\n\n\u003csub\u003eObjective-C\u003c/sub\u003e\n```objc\nstatic NSString *const kSuccessURLString =\n    @\"http://openid.github.io/AppAuth-iOS/redirect/\";\nNSURL *successURL = [NSURL URLWithString:kSuccessURLString];\n\n// Starts a loopback HTTP redirect listener to receive the code.  This needs to be started first,\n// as the exact redirect URI (including port) must be passed in the authorization request.\n_redirectHTTPHandler = [[OIDRedirectHTTPHandler alloc] initWithSuccessURL:successURL];\nNSURL *redirectURI = [_redirectHTTPHandler startHTTPListener:nil];\n```\n\nThen, initiate the authorization request. By using the \n`authStateByPresentingAuthorizationRequest` convenience method, the token\nexchange will be performed automatically, and everything will be protected with\nPKCE (if the server supports it). By assigning the return value to the\n`OIDRedirectHTTPHandler`'s `currentAuthorizationFlow`, the authorization will\ncontinue automatically once the user makes their choice:\n\n```objc\n// builds authentication request\nOIDAuthorizationRequest *request =\n    [[OIDAuthorizationRequest alloc] initWithConfiguration:configuration\n                                                  clientId:kClientID\n                                              clientSecret:kClientSecret\n                                                    scopes:@[ OIDScopeOpenID ]\n                                               redirectURL:redirectURI\n                                              responseType:OIDResponseTypeCode\n                                      additionalParameters:nil];\n// performs authentication request\n__weak __typeof(self) weakSelf = self;\n_redirectHTTPHandler.currentAuthorizationFlow =\n    [OIDAuthState authStateByPresentingAuthorizationRequest:request\n                        callback:^(OIDAuthState *_Nullable authState,\n                                   NSError *_Nullable error) {\n  // Brings this app to the foreground.\n  [[NSRunningApplication currentApplication]\n      activateWithOptions:(NSApplicationActivateAllWindows |\n                           NSApplicationActivateIgnoringOtherApps)];\n\n  // Processes the authorization response.\n  if (authState) {\n    NSLog(@\"Got authorization tokens. Access token: %@\",\n          authState.lastTokenResponse.accessToken);\n  } else {\n    NSLog(@\"Authorization error: %@\", error.localizedDescription);\n  }\n  [weakSelf setAuthState:authState];\n}];\n```\n\n\n### Authorizing – tvOS\n\nEnsure that your main class is a delegate of `OIDAuthStateChangeDelegate`, `OIDAuthStateErrorDelegate`, implement the corresponding methods, and include the following property and instance variable:\n\n\u003csub\u003eObjective-C\u003c/sub\u003e\n```objc\n// property of the containing class\n@property(nonatomic, strong, nullable) OIDAuthState *authState;\n\n// instance variable of the containing class\nOIDTVAuthorizationCancelBlock _cancelBlock;\n```\n\nThen, build and perform the authorization request.\n\n\u003csub\u003eObjective-C\u003c/sub\u003e\n```objc\n// builds authentication request\n__weak __typeof(self) weakSelf = self;\n\nOIDTVAuthorizationRequest *request =\n    [[OIDTVAuthorizationRequest alloc] initWithConfiguration:configuration\n                                                    clientId:kClientID\n                                                clientSecret:kClientSecret\n                                                      scopes:@[ OIDScopeOpenID, OIDScopeProfile ]\n                                        additionalParameters:nil\n                                           additionalHeaders:nil];\n\n// performs authentication request\nOIDTVAuthorizationInitialization initBlock =\n    ^(OIDTVAuthorizationResponse *_Nullable response, NSError *_Nullable error) {\n      if (response) {\n        // process authorization response\n        NSLog(@\"Got authorization response: %@\", response);\n      } else {\n        // handle initialization error\n        NSLog(@\"Error: %@\", error);\n      }\n    };\n\nOIDTVAuthorizationCompletion completionBlock =\n    ^(OIDAuthState *_Nullable authState, NSError *_Nullable error) {\n      weakSelf.signInView.hidden = YES;\n      if (authState) {\n        NSLog(@\"Token response: %@\", authState.lastTokenResponse);\n        [weakSelf setAuthState:authState];\n      } else {\n        NSLog(@\"Error: %@\", error);\n        [weakSelf setAuthState:nil];\n      }\n    };\n\n_cancelBlock = [OIDTVAuthorizationService authorizeTVRequest:request\n                                              initialization:initBlock\n                                                  completion:completionBlock];\n```\n\n### Making API Calls\n\nAppAuth gives you the raw token information, if you need it. However, we\nrecommend that users of the `OIDAuthState` convenience wrapper use the provided\n`performActionWithFreshTokens:` method to perform their API calls to avoid\nneeding to worry about token freshness:\n\n\u003csub\u003eObjective-C\u003c/sub\u003e\n```objc\n[_authState performActionWithFreshTokens:^(NSString *_Nonnull accessToken,\n                                           NSString *_Nonnull idToken,\n                                           NSError *_Nullable error) {\n  if (error) {\n    NSLog(@\"Error fetching fresh tokens: %@\", [error localizedDescription]);\n    return;\n  }\n\n  // perform your API request using the tokens\n}];\n```\n\n\u003csub\u003eSwift\u003c/sub\u003e\n```swift\nlet userinfoEndpoint = URL(string:\"https://openidconnect.googleapis.com/v1/userinfo\")!\nself.authState?.performAction() { (accessToken, idToken, error) in\n\n  if error != nil  {\n    print(\"Error fetching fresh tokens: \\(error?.localizedDescription ?? \"Unknown error\")\")\n    return\n  }\n  guard let accessToken = accessToken else {\n    return\n  }\n\n  // Add Bearer token to request\n  var urlRequest = URLRequest(url: userinfoEndpoint)\n  urlRequest.allHTTPHeaderFields = [\"Authorization\": \"Bearer \\(accessToken)\"]\n\n  // Perform request...\n}\n```\n\n### Custom User-Agents (iOS and macOS)\n\nEach OAuth flow involves presenting an external user-agent to the user, that\nallows them to interact with the OAuth authorization server. Typical examples\nof a user-agent are the user's browser, or an in-app browser tab incarnation\nlike `ASWebAuthenticationSession` on iOS.\n\nAppAuth ships with several implementations of an external user-agent out of the\nbox, including defaults for iOS and macOS suitable for most cases. The default\nuser-agents typically share persistent cookies with the system default browser,\nto improve the chance that the user doesn't need to sign-in all over again.\n\nIt is possible to change the user-agent that AppAuth uses, and even write your\nown - all without needing to fork the library.\n\nAll implementations of the external user-agent, be they included or created by\nyou need to conform to the \n[`OIDExternalUserAgent`](http://openid.github.io/AppAuth-iOS/docs/latest/protocol_o_i_d_external_user_agent-p.html)\nprotocol.\n\nInstances of the `OIDExternalUserAgent`are passed into\n[`OIDAuthState.authStateByPresentingAuthorizationRequest:externalUserAgent:callback`](http://openid.github.io/AppAuth-iOS/docs/latest/interface_o_i_d_auth_state.html#ac762fe2bf95c116f0b437419be211fa1)\nand/or \n[`OIDAuthorizationService.presentAuthorizationRequest:externalUserAgent:callback:`](http://openid.github.io/AppAuth-iOS/docs/latest/interface_o_i_d_authorization_service.html#ae551f8e6887366a46e49b09b37389b8f)\nrather than using the platform-specific convenience methods (which use the \ndefault user-agents for their respective platforms), like \n[`OIDAuthState.authStateByPresentingAuthorizationRequest:presentingViewController:callback:`](http://openid.github.io/AppAuth-iOS/docs/latest/category_o_i_d_auth_state_07_i_o_s_08.html#ae32fd0732cd3192cd5219f2655a4c85c).\n\nPopular use-cases for writing your own user-agent implementation include needing\nto style the user-agent in ways not supported by AppAuth, and implementing a\nfully custom flow with your own business logic. You can take one of the existing\nimplementations as a starting point to copy, rename, and customize to your\nneeds.\n\n#### Custom Browser User-Agent\n\nAppAuth for iOS includes a few extra user-agent implementations which you can\ntry, or use as a reference for your own implementation. One of them,\n[`OIDExternalUserAgentIOSCustomBrowser`](http://openid.github.io/AppAuth-iOS/docs/latest/interface_o_i_d_external_user_agent_i_o_s_custom_browser.html)\nenables you to use a different browser for authentication, like Chrome for iOS\nor Firefox for iOS.\n\nHere's how to configure AppAuth to use a custom browser using the\n`OIDExternalUserAgentIOSCustomBrowser` user agent:\n\nFirst, add the following array to your\n[Info.plist](https://github.com/openid/AppAuth-iOS/blob/135f99d2cb4e9d18d310ac2588b905e612461561/Examples/Example-iOS_ObjC/Source/Info.plist#L34)\n(in XCode, right click -\u003e Open As -\u003e Source Code)\n\n```\n    \u003ckey\u003eLSApplicationQueriesSchemes\u003c/key\u003e\n    \u003carray\u003e\n        \u003cstring\u003egooglechromes\u003c/string\u003e\n        \u003cstring\u003eopera-https\u003c/string\u003e\n        \u003cstring\u003efirefox\u003c/string\u003e\n    \u003c/array\u003e\n```\n\nThis is required so that AppAuth can test for the browser and open the app store\nif it's not installed (the default behavior of this user-agent). You only need\nto include the URL scheme of the actual browser you intend to use.\n\n\u003csub\u003eObjective-C\u003c/sub\u003e\n```objc\n// performs authentication request\nAppDelegate *appDelegate =\n    (AppDelegate *)[UIApplication sharedApplication].delegate;\nid\u003cOIDExternalUserAgent\u003e userAgent =\n    [OIDExternalUserAgentIOSCustomBrowser CustomBrowserChrome];\nappDelegate.currentAuthorizationFlow =\n    [OIDAuthState authStateByPresentingAuthorizationRequest:request\n        externalUserAgent:userAgent\n                 callback:^(OIDAuthState *_Nullable authState,\n                                   NSError *_Nullable error) {\n  if (authState) {\n    NSLog(@\"Got authorization tokens. Access token: %@\",\n          authState.lastTokenResponse.accessToken);\n    [self setAuthState:authState];\n  } else {\n    NSLog(@\"Authorization error: %@\", [error localizedDescription]);\n    [self setAuthState:nil];\n  }\n}];\n```\n\n\u003csub\u003eSwift\u003c/sub\u003e\n```\nguard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {\n            self.logMessage(\"Error accessing AppDelegate\")\n            return\n        }\nlet userAgent = OIDExternalUserAgentIOSCustomBrowser.customBrowserChrome()\t\t\nappDelegate.currentAuthorizationFlow = OIDAuthState.authState(byPresenting: request, externalUserAgent: userAgent) { authState, error in\n    if let authState = authState {\n        self.setAuthState(authState)\n        self.logMessage(\"Got authorization tokens. Access token: \\(authState.lastTokenResponse?.accessToken ?? \"DEFAULT_TOKEN\")\")\n    } else {\n        self.logMessage(\"Authorization error: \\(error?.localizedDescription ?? \"DEFAULT_ERROR\")\")\n        self.setAuthState(nil)\n    }\n}\n```\n\nThat's it! With those two changes (which you can try on the included sample),\nAppAuth will use Chrome iOS for the authorization request (and open Chrome in\nthe App Store if it's not installed).\n\n⚠️**Note: the `OIDExternalUserAgentIOSCustomBrowser` user-agent is not intended for consumer apps**. It is designed for\nadvanced enterprise use-cases where the app developers have greater control over\nthe operating environment and have special requirements that require a custom\nbrowser like Chrome.\n\nYou don't need to stop with the included external user agents either! Since the\n[`OIDExternalUserAgent`](http://openid.github.io/AppAuth-iOS/docs/latest/protocol_o_i_d_external_user_agent-p.html)\nprotocol is part of AppAuth's public API, you can implement your own versions of\nit. In the above example,\n`userAgent = [OIDExternalUserAgentIOSCustomBrowser CustomBrowserChrome]` would\nbe replaced with an instantiation of your user-agent implementation.\n\n## API Documentation\n\nBrowse the [API documentation](http://openid.github.io/AppAuth-iOS/docs/latest/annotated.html).\n\n## Included Samples\n\nSample apps that explore core AppAuth features are available for iOS, macOS and tvOS; follow the instructions in [Examples/README.md](Examples/README.md) to get started.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenid%2Fappauth-ios","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopenid%2Fappauth-ios","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenid%2Fappauth-ios/lists"}