# Technical Documentation: openid/AppAuth-iOS

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/openid/AppAuth-iOS)

### Overview (`README.md`)

[](https://github.com/openid/AppAuth-iOS/actions/workflows/tests.yml)
[](https://codecov.io/gh/openid/AppAuth-iOS)
[](https://github.com/Carthage/Carthage)
[](https://swift.org/package-manager)
[](https://cocoapods.org/pods/AppAuth)
[](https://github.com/openid/AppAuth-iOS/blob/master/LICENSE)
[](https://cocoapods.org/pods/AppAuth)
[](https://developer.apple.com/documentation/xcode/creating_a_mac_version_of_your_ipad_app)

AppAuth for iOS and macOS, and tvOS is a client SDK for communicating with 
[OAuth 2.0](https://tools.ietf.org/html/rfc6749) and 
[OpenID Connect](http://openid.net/specs/openid-connect-core-1_0.html) providers. 
It strives to
directly map the requests and responses of those specifications, while following
the idiomatic style of the implementation language. In addition to mapping the
raw protocol flows, convenience methods are available to assist with common
tasks like performing an action with fresh tokens.

It follows the best practices set out in 
[RFC 8252 - OAuth 2.0 for Native Apps](https://tools.ietf.org/html/rfc8252)
including using `SFAuthenticationSession` and `SFSafariViewController` on iOS
for the auth request. `UIWebView` and `WKWebView` are explicitly *not*
supported due to the security and usability reasons explained in
[Section 8.12 of RFC 8252](https://tools.ietf.org/html/rfc8252#section-8.12).

It also supports the [PKCE](https://tools.ietf.org/html/rfc7636) extension to
OAuth, which was created to secure authorization codes in public clients when
custom URI scheme redirects are used. The library is friendly to other
extensions (standard or otherwise), with the ability to handle additional params
in all protocol requests and responses.

For tvOS, AppAuth implements [OAuth 2.0 Device Authorization Grant
](https://tools.ietf.org/html/rfc8628) to allow for tvOS sign-ins through a secondary device.

## Specification

### iOS

#### Supported Versions

AppAuth supports iOS 15 and above.

Authentication is performed using `ASWebAuthenticationSession`.

#### Authorization Server Requirements

Both custom URI scheme redirects and HTTPS redirects (RFC 8252 "claimed https" redirect URIs) can
be used with the library. HTTPS redirects require iOS 17.4+, an Associated Domains entitlement
for the redirect host using the `webcredentials` service, and an AASA file on that host listing
the app under `webcredentials`. An `applinks` (Universal Links) association alone is not enough.

In general, AppAuth can work with any authorization server that supports
native apps, as documented in [RFC 8252](https://tools.ietf.org/html/rfc8252),
either through custom URI scheme redirects, or HTTPS redirects.
Authorization servers that assume all clients are web-based, or require clients to maintain
confidentiality of the client secrets may not work well.

### macOS

#### Supported Versions

AppAuth supports macOS 12 and above.

#### Authorization Server Requirements

AppAuth for macOS supports both custom schemes; a loopback HTTP redirects
via a small embedded server.

In general, AppAuth can work with any authorization server that supports
native apps, as documented in [RFC 8252](https://tools.ietf.org/html/rfc8252);
either through custom URI schemes, or loopback HTTP redirects.
Authorization servers that assume all clients are web-based, or require clients to maintain
confidentiality of the client secrets may not work well.

### tvOS

#### Supported Versions

AppAuth supports tvOS 15.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).

#### Authorization Server Requirements

AppAuthTV is designed for servers that support the device authorization flow as documented in [RFC 8628](https://tools.ietf.org/html/rfc8628).

## Try

Want to try out AppAuth? Just run:

    pod try AppAuth

Follow the instructions in [Examples/README.md](Examples/README.md) to configure
with your own OAuth client (you need to update three configuration points with your
client info to try the demo).

## Setup

AppAuth supports four options for dependency management.

### CocoaPods

With [CocoaPods](https://guides.cocoapods.org/using/getting-started.html),
add the following line to your `Podfile`:

    pod 'AppAuth'

Then, run `pod install`.

**tvOS:** Use the `TV` subspec:

    pod 'AppAuth/TV'


### Swift Package Manager

With [Swift Package Manager](https://swift.org/package-manager), 
add the following `dependency` to your `Package.swift`:

```swift
dependencies: [
    .package(url: "https://github.com/openid/AppAuth-iOS.git", .upToNextMajor(from: "3.0.0"))
]
```

**tvOS:** Use the `AppAuthTV` target.

### Carthage

With [Carthage](https://github.com/Carthage/Carthage), add the following
line to your `Cartfile`:

    github "openid/AppAuth-iOS" "master"

Then, run `carthage bootstrap`.

**tvOS:** Use the `AppAuthTV` framework.

### Static Library

You can also use AppAuth as a static library. This requires linking the library
and your project, and including the headers.  Here is a suggested configuration:

1. Create an Xcode Workspace.
2. Add `AppAuth.xcodeproj` to your Workspace.
3. Include libAppAuth as a linked library for your target (in the "General ->
Linked Framework and Libraries" section of your target).
4. Add `AppAuth-iOS/Source` to your search paths of your target ("Build Settings ->
"Header Search Paths").

*Note: There is no static library for AppAuthTV.*

## Auth Flow

AppAuth supports both manual interaction with the authorization server
where you need to perform your own token exchanges, as well as convenience
methods that perform some of this logic for you. This example uses the
convenience method, which returns either an `OIDAuthState` object, or an error.

`OIDAuthState` is a class that keeps track of the authorization and token
requests and responses, and provides a convenience method to call an API with
fresh tokens. This is the only object that you need to serialize to retain the
authorization state of the session.

### Configuration

You can configure AppAuth by specifying the endpoints directly:

<sub>Objective-C</sub>
```objc
NSURL *authorizationEndpoint =
    [NSURL URLWithString:@"https://accounts.google.com/o/oauth2/v2/auth"];
NSURL *tokenEndpoint =
    [NSURL URLWithString:@"https://www.googleapis.com/oauth2/v4/token"];

OIDServiceConfiguration *configuration =
    [[OIDServiceConfiguration alloc]
        initWithAuthorizationEndpoint:authorizationEndpoint
                        tokenEndpoint:tokenEndpoint];

// perform the auth request...
```

<sub>Swift</sub>
```swift
let authorizationEndpoint = URL(string: "https://accounts.google.com/o/oauth2/v2/auth")!
let tokenEndpoint = URL(string: "https://www.googleapis.com/oauth2/v4/token")!
let configuration = OIDServiceConfiguration(authorizationEndpoint: authorizationEndpoint,
                                            tokenEndpoint: tokenEndpoint)

// perform the auth request...
```

**tvOS**

<sub>Objective-C</sub>
```objc
NSURL *deviceAuthorizationEndpoint =
    [NSURL URLWithString:@"https://oauth2.googleapis.com/device/code"];
NSURL *tokenEndpoint =
    [NSURL URLWithString:@"https://www.googleapis.com/oauth2/v4/token"];

OIDTVServiceConfiguration *configuration =
    [[OIDTVServiceConfiguration alloc]
        initWithDeviceAuthorizationEndpoint:deviceAuthorizationEndpoint
                              tokenEndpoint:tokenEndpoint];

// perform the auth request...
```


Or through discovery:

<sub>Objective-C</sub>
```objc
NSURL *issuer = [NSURL URLWithString:@"https://accounts.google.com"];

[OIDAuthorizationService discoverServiceConfigurationForIssuer:issuer
    completion:^(OIDServiceConfiguration *_Nullable configuration,
                 NSError *_Nullable error) {

  if (!configuration) {
    NSLog(@"Error retrieving discovery document: %@",
          [error localizedDescription]);
    return;
  }

  // perform the auth request...
}];
```

<sub>Swift</sub>
```swift
let issuer = URL(string: "https://accounts.google.com")!

// discovers endpoints
OIDAuthorizationService.discoverConfiguration(forIssuer: issuer) { configuration, error in
  guard let config = configuration else {
    print("Error retrieving discovery document: \(error?.localizedDescription ?? "Unknown error")")
    return
  }

  // perform the auth request...
}
```

**tvOS**

<sub>Objective-C</sub>
```objc
NSURL *issuer = [NSURL URLWithString:@"https://accounts.google.com"];

[OIDTVAuthorizationService discoverServiceConfigurationForIssuer:issuer
    completion:^(OIDTVServiceConfiguration *_Nullable configuration,
                 NSError *_Nullable error) {

  if (!configuration) {
    NSLog(@"Error retrieving discovery document: %@",
          [error localizedDescription]);
    return;
  }

  // perform the auth request...
}];
```

### Authorizing – iOS

First, you need to have a property in your `UIApplicationDelegate`
implementation to hold the session, in order to continue the authorization flow
from the redirect. In this example, the implementation of this delegate is
a class named `AppDelegate`, if your app's application delegate has a different
name, please update the class name in samples below accordingly.

<sub>Objective-C</sub>
```objc
@interface AppDelegate : UIResponder <UIApplicationDelegate>
// property of the app's AppDelegate
@property(nonatomic, strong, nullable) id<OIDExternalUserAgentSession> currentAuthorizationFlow;
@end
```

<sub>Swift</sub>
```swift
class AppDelegate: UIResponder, UIApplicationDelegate {
  // property of the app's AppDelegate
  var currentAuthorizationFlow: OIDExternalUserAgentSession?
}
```


And your main class, a property to store the auth state:

<sub>Objective-C</sub>
```objc
// property of the containing class
@property(nonatomic, strong, nullable) OIDAuthState *authState;
```
<sub>Swift</sub>
```swift
// property of the containing class
private var authState: OIDAuthState?
```


Then, initiate the authorization request. By using the 
`authStateByPresentingAuthorizationRequest` convenience method, the token
exchange will be performed automatically, and everything will be protected with
PKCE (if the server supports it). AppAuth also lets you perform these
requests manually. See the `authNoCodeExchange` method in the included Example
app for a demonstration:

<sub>Objective-C</sub>
```objc
// builds authentication request
OIDAuthorizationRequest *request =
    [[OIDAuthorizationRequest alloc] initWithConfiguration:configuration
                                                  clientId:kClientID
                                                    scopes:@[OIDScopeOpenID,
                                                             OIDScopeProfile]
                                               redirectURL:kRedirectURI
                                              responseType:OIDResponseTypeCode
                                      additionalParameters:nil];

// performs authentication request
AppDelegate *appDelegate =
    (AppDelegate *)[UIApplication sharedApplication].delegate;
appDelegate.currentAuthorizationFlow =
    [OIDAuthState authStateByPresentingAuthorizationRequest:request
        presentingViewController:self
                        callback:^(OIDAuthState *_Nullable authState,
                                   NSError *_Nullable error) {
  if (authState) {
    NSLog(@"Got authorization tokens. Access token: %@",
          authState.lastTokenResponse.accessToken);
    [self setAuthState:authState];
  } else {
    NSLog(@"Authorization error: %@", [error localizedDescription]);
    [self setAuthState:nil];
  }
}];
```

<sub>Swift</sub>
```swift
// builds authentication request
let request = OIDAuthorizationRequest(configuration: configuration,
                                      clientId: clientID,
                                      clientSecret: clientSecret,
                                      scopes: [OIDScopeOpenID, OIDScopeProfile],
                                      redirectURL: redirectURI,
                                      responseType: OIDResponseTypeCode,
                                      additionalParameters: nil)

// performs authentication request
print("Initiating authorization request with scope: \(request.scope ?? "nil")")

let appDelegate = UIApplication.shared.delegate as! AppDelegate

appDelegate.currentAuthorizationFlow =
    OIDAuthState.authState(byPresenting: request, presenting: self) { authState, error in
  if let authState = authState {
    self.setAuthState(authState)
    print("Got authorization tokens. Access token: " +
          "\(authState.lastTokenResponse?.accessToken ?? "nil")")
  } else {
    print("Authorization error: \(error?.localizedDescription ?? "Unknown error")")
    self.setAuthState(nil)
  }
}
```

*Handling the Redirect*

The authorization response URL is returned to the app via the iOS openURL
app delegate method, so you need to pipe this through to the current
authorization session (created in the previous session):

<sub>Objective-C</sub>
```objc
- (BOOL)application:(UIApplication *)app
            openURL:(NSURL *)url
            options:(NSDictionary<NSString *, id> *)options {
  // Sends the URL to the current authorization flow (if any) which will
  // process it if it relates to an authorization response.
  // Handling the error lets you filter for conditions that require
  // logging, such as an unexpected state
  // (OIDErrorCodeInvalidAuthorizationFlow). Benign mismatches
  // (OIDErrorCodeURLMismatch) are kept silent.
  NSError *error = nil;
  if ([_currentAuthorizationFlow resumeExternalUserAgentFlowWithURL:url error:&error]) {
    _currentAuthorizationFlow = nil;
    return YES;
  } else if (error.code == OIDErrorCodeInvalidAuthorizationFlow) {
    NSLog(@"Authorization flow could not handle URL: %@", error.localizedDescription);
  }

  // Your additional URL handling (if any) goes here.

  return NO;
}
```

<sub>Swift</sub>
```swift
func application(_ app: UIApplication,
                 open url: URL,
                 options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
  // Sends the URL to the current authorization flow (if any) which will
  // process it if it relates to an authorization response. Handling the
  // error lets you filter for conditions that require logging, such as
  // an unexpected state (OIDErrorCodeInvalidAuthorizationFlow). Benign
  // mismatches (OIDErrorCodeURLMismatch) are kept silent.
  if let authorizationFlow = self.currentAuthorizationFlow {
    do {
      try authorizationFlow.resumeExternalUserAgentFlow(url)
      self.currentAuthorizationFlow = nil
      return true
    } catch let error as NSError where error.code == OIDErrorCodeInvalidAuthorizationFlow.rawValue {
      print("Authorization flow could not handle URL: \(error.localizedDescription)")
    } catch {
      // Benign mismatch (e.g. OIDErrorCodeURLMismatch): fall through.
    }
  }

  // Your additional URL handling (if any)

  return false
}
```

### Authorizing – MacOS

On macOS, the most popular way to get the authorization response redirect is to
start a local HTTP server on the loopback interface (limited to incoming
requests from the user's machine only). When the authorization is complete, the
user is redirected to that local server, and the authorization response can be
processed by the app. AppAuth takes care of managing the local HTTP server
lifecycle for you.

> #### :bulb: Alternative: Custom URI Schemes
> Custom URI schemes are also supported on macOS, but some browsers display
> an interstitial, which reduces the usability. For an example on using custom
> URI schemes with macOS, See `Example-Mac`.

To receive the authorization response using a local HTTP server, first you need
to have an instance variable in your main class to retain the HTTP redirect
handler:

<sub>Objective-C</sub>
```objc
OIDRedirectHTTPHandler *_redirectHTTPHandler;
```

Then, as the port used by the local HTTP server varies, you need to start it
before building the authorization request, in order to get the exact redirect
URI to use:

<sub>Objective-C</sub>
```objc
static NSString *const kSuccessURLString =
    @"http://openid.github.io/AppAuth-iOS/redirect/";
NSURL *successURL = [NSURL URLWithString:kSuccessURLString];

// Starts a loopback HTTP redirect listener to receive the code.  This needs to be started first,
// as the exact redirect URI (including port) must be passed in the authorization request.
_redirectHTTPHandler = [[OIDRedirectHTTPHandler alloc] initWithSuccessURL:successURL];
NSURL *redirectURI = [_redirectHTTPHandler startHTTPListener:nil];
```

Then, initiate the authorization request. By using the 
`authStateByPresentingAuthorizationRequest` convenience method, the token
exchange will be performed automatically, and everything will be protected with
PKCE (if the server supports it). By assigning the return value to the
`OIDRedirectHTTPHandler`'s `currentAuthorizationFlow`, the authorization will
continue automatically once the user makes their choice:

```objc
// builds authentication request
OIDAuthorizationRequest *request =
    [[OIDAuthorizationRequest alloc] initWithConfiguration:configuration
                                                  clientId:kClientID
                                              clientSecret:kClientSecret
                                                    scopes:@[ OIDScopeOpenID ]
                                               redirectURL:redirectURI
                                              responseType:OIDResponseTypeCode
                                      additionalParameters:nil];
// performs authentication request
__weak __typeof(self) weakSelf = self;
_redirectHTTPHandler.currentAuthorizationFlow =
    [OIDAuthState authStateByPresentingAuthorizationRequest:request
                        callback:^(OIDAuthState *_Nullable authState,
                                   NSError *_Nullable error) {
  // Brings this app to the foreground.
  [[NSRunningApplication currentApplication]
      activateWithOptions:(NSApplicationActivateAllWindows |
                           NSApplicationActivateIgnoringOtherApps)];

  // Processes the authorization response.
  if (authState) {
    NSLog(@"Got authorization tokens. Access token: %@",
          authState.lastTokenResponse.accessToken);
  } else {
    NSLog(@"Authorization error: %@", error.localizedDescription);
  }
  [weakSelf setAuthState:authState];
}];
```


### Authorizing – tvOS

Ensure that your main class is a delegate of `OIDAuthStateChangeDelegate`, `OIDAuthStateErrorDelegate`, implement the corresponding methods, and include the following property and instance variable:

<sub>Objective-C</sub>
```objc
// property of the containing class
@property(nonatomic, strong, nullable) OIDAuthState *authState;

// instance variable of the containing class
OIDTVAuthorizationCancelBlock _cancelBlock;
```

Then, build and perform the authorization request.

<sub>Objective-C</sub>
```
/* Detailed source-code truncated for AI context efficiency. */
```

### Making API Calls

AppAuth gives you the raw token information, if you need it. However, we
recommend that users of the `OIDAuthState` convenience wrapper use the provided
`performActionWithFreshTokens:` method to perform their API calls to avoid
needing to worry about token freshness:

<sub>Objective-C</sub>
```objc
[_authState performActionWithFreshTokens:^(NSString *_Nonnull accessToken,
                                           NSString *_Nonnull idToken,
                                           NSError *_Nullable error) {
  if (error) {
    NSLog(@"Error fetching fresh tokens: %@", [error localizedDescription]);
    return;
  }

  // perform your API request using the tokens
}];
```

<sub>Swift</sub>
```swift
let userinfoEndpoint = URL(string:"https://openidconnect.googleapis.com/v1/userinfo")!
self.authState?.performAction() { (accessToken, idToken, error) in

  if error != nil  {
    print("Error fetching fresh tokens: \(error?.localizedDescription ?? "Unknown error")")
    return
  }
  guard let accessToken = accessToken else {
    return
  }

  // Add Bearer token to request
  var urlRequest = URLRequest(url: userinfoEndpoint)
  urlRequest.allHTTPHeaderFields = ["Authorization": "Bearer \(accessToken)"]

  // Perform request...
}
```

### Custom User-Agents (iOS and macOS)

Each OAuth flow involves presenting an external user-agent to the user, that
allows them to interact with the OAuth authorization server. Typical examples
of a user-agent are the user's browser, or an in-app browser tab incarnation
like `ASWebAuthenticationSession` on iOS.

AppAuth ships with several implementations of an external user-agent out of the
box, including defaults for iOS and macOS suitable for most cases. The default
user-agents typically share persistent cookies with the system default browser,
to improve the chance that the user doesn't need to sign-in all over again.

It is possible to change the user-agent that AppAuth uses, and even write your
own - all without needing to fork the library.

All implementations of the external user-agent, be they included or created by
you need to conform to the 
[`OIDExternalUserAgent`](http://openid.github.io/AppAuth-iOS/docs/latest/protocol_o_i_d_external_user_agent-p.html)
protocol.

Instances of the `OIDExternalUserAgent`are passed into
[`OIDAuthState.authStateByPresentingAuthorizationRequest:externalUserAgent:callback`](http://openid.github.io/AppAuth-iOS/docs/latest/interface_o_i_d_auth_state.html#ac762fe2bf95c116f0b437419be211fa1)
and/or 
[`OIDAuthorizationService.presentAuthorizationRequest:externalUserAgent:callback:`](http://openid.github.io/AppAuth-iOS/docs/latest/interface_o_i_d_authorization_service.html#ae551f8e6887366a46e49b09b37389b8f)
rather than using the platform-specific convenience methods (which use the 
default user-agents for their respective platforms), like 
[`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).

Popular use-cases for writing your own user-agent implementation include needing
to style the user-agent in ways not supported by AppAuth, and implementing a
fully custom flow with your own business logic. You can take one of the existing
implementations as a starting point to copy, rename, and customize to your
needs.

#### Custom Browser User-Agent

AppAuth for iOS includes a few extra user-agent implementations which you can
try, or use as a reference for your own implementation. One of them,
[`OIDExternalUserAgentIOSCustomBrowser`](http://openid.github.io/AppAuth-iOS/docs/latest/interface_o_i_d_external_user_agent_i_o_s_custom_browser.html)
enables you to use a different browser for authentication, like Chrome for iOS
or Firefox for iOS.

Here's how to configure AppAuth to use a custom browser using the
`OIDExternalUserAgentIOSCustomBrowser` user agent:

First, add the following array to your
[Info.plist](https://github.com/openid/AppAuth-iOS/blob/135f99d2cb4e9d18d310ac2588b905e612461561/Examples/Example-iOS_ObjC/Source/Info.plist#L34)
(in XCode, right click -> Open As -> Source Code)

```
    <key>LSApplicationQueriesSchemes</key>
    <array>
        <string>googlechromes</string>
        <string>opera-https</string>
        <string>firefox</string>
    </array>
```

This is required so that AppAuth can test for the browser and open the app store
if it's not installed (the default behavior of this user-agent). You only need
to include the URL scheme of the actual browser you intend to use.

<sub>Objective-C</sub>
```objc
// performs authentication request
AppDelegate *appDelegate =
    (AppDelegate *)[UIApplication sharedApplication].delegate;
id<OIDExternalUserAgent> userAgent =
    [OIDExternalUserAgentIOSCustomBrowser CustomBrowserChrome];
appDelegate.currentAuthorizationFlow =
    [OIDAuthState authStateByPresentingAuthorizationRequest:request
        externalUserAgent:userAgent
                 callback:^(OIDAuthState *_Nullable authState,
                                   NSError *_Nullable error) {
  if (authState) {
    NSLog(@"Got authorization tokens. Access token: %@",
          authState.lastTokenResponse.accessToken);
    [self setAuthState:authState];
  } else {
    NSLog(@"Authorization error: %@", [error localizedDescription]);
    [self setAuthState:nil];
  }
}];
```

<sub>Swift</sub>
```
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
            self.logMessage("Error accessing AppDelegate")
            return
        }
let userAgent = OIDExternalUserAgentIOSCustomBrowser.customBrowserChrome()		
appDelegate.currentAuthorizationFlow = OIDAuthState.authState(byPresenting: request, externalUserAgent: userAgent) { authState, error in
    if let authState = authState {
        self.setAuthState(authState)
        self.logMessage("Got authorization tokens. Access token: \(authState.lastTokenResponse?.accessToken ?? "DEFAULT_TOKEN")")
    } else {
        self.logMessage("Authorization error: \(error?.localizedDescription ?? "DEFAULT_ERROR")")
        self.setAuthState(nil)
    }
}
```

That's it! With those two changes (which you can try on the included sample),
AppAuth will use Chrome iOS for the authorization request (and open Chrome in
the App Store if it's not installed).

⚠️**Note: the `OIDExternalUserAgentIOSCustomBrowser` user-agent is not intended for consumer apps**. It is designed for
advanced enterprise use-cases where the app developers have greater control over
the operating environment and have special requirements that require a custom
browser like Chrome.

You don't need to stop with the included external user agents either! Since the
[`OIDExternalUserAgent`](http://openid.github.io/AppAuth-iOS/docs/latest/protocol_o_i_d_external_user_agent-p.html)
protocol is part of AppAuth's public API, you can implement your own versions of
it. In the above example,
`userAgent = [OIDExternalUserAgentIOSCustomBrowser CustomBrowserChrome]` would
be replaced with an instantiation of your user-agent implementation.

## API Documentation

Browse the [API documentation](http://openid.github.io/AppAuth-iOS/docs/latest/annotated.html).

## Included Samples

Sample 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.

---

### Overview (`Examples/README.md`)

# AppAuth for iOS and macOS Examples

The examples need to be configured with an OpenID Connect issuer (or
Authorization and Token endpoints manually), and the OAuth client information
like the Client ID and Redirect URI.

## Examples

Each example has docs on how to configure:

* [Example for iOS (Objective-C)](Example-iOS_ObjC/README.md)
* [Example for iOS w/ Carthage (Objective-C)](Example-iOS_ObjC-Carthage/README.md)
* [Example for iOS w/ Carthage (Swift)](Example-iOS_Swift-Carthage/README.md)
* [Example for iOS w/ SPM (SwiftUI)](Example-iOS_Swift-SPM/README.md)
* [Example for macOS](Example-macOS/README.md)
* [Example for tvOS](Example-tvOS/README.md)

To get the Issuer, Client ID, and Redirect URI, for your particular IdP, you
may view the IdP-specific information in the next section.

## OpenID Certified Providers

All [Certified OpenID providers](http://openid.net/certification/) that support
[RFC 8252](https://tools.ietf.org/html/rfc8252#appendix-A)
are welcome to submit a README with IdP information.

Those with instructions on file:

* [Google](README-Google.md)
* [IdentityServer](README-IdentityServer.md)
* [Okta](README-Okta.md)
* [PingFederate](README-PingFederate.md)

---

### Overview (`Examples/Example-iOS_ObjC-Carthage/README.md`)

# Example Project

## Setup & Open the Project

You'll need to have [Carthage](https://github.com/Carthage/Carthage) installed
in order to pull the AppAuth dependency.

So first run `carthage bootstrap` to build AppAuth framework then open the
`Example.xcodeproj` file.

## Configuration

The example doesn't work out of the box, you need to configure it with your own
client ID.

### Information You'll Need

* Issuer
* Client ID
* Redirect URI

How to get this information varies by IdP, but we have
[instructions](../README.md#openid-certified-providers) for some OpenID
Certified providers.

### Configure the Example

#### In the file `AppAuthExampleViewController.m` 

1. Update `kIssuer` with the IdP's issuer.
2. Update `kClientID` with your new client id.
3. Update `kRedirectURI` redirect URI

#### In the file `Info.plist`

Fully expand "URL types" (a.k.a. `CFBundleURLTypes`) and replace
`com.example.app` with the *scheme* of your redirect URI. 
The scheme is everything before the colon (`:`).  For example, if the redirect
URI is `com.example.app:/oauth2redirect/example-provider`, then the scheme
would be `com.example.app`.

### Running the Example

Now your example should be ready to run.

---

### Overview (`Examples/Example-iOS_ObjC/README.md`)

# Example Project

## Setup & Open the Project

1. In the `Example-iOS_ObjC` folder, run the following command to install the
AppAuth pod.

```
pod install
```

2. Open the `Example-iOS_ObjC.xcworkspace` workspace.

```
open Example-iOS_ObjC.xcworkspace
```

This workspace is configured to include AppAuth via CocoaPods. You can also
directly include AppAuth as a static library using the build targets in the
`AppAuth.xcodeproj` project.

## Configuration

The example doesn't work out of the box, you need to configure it with your own
client ID.

### Information You'll Need

* Issuer
* Client ID
* Redirect URI

How to get this information varies by IdP, but we have
[instructions](../README.md#openid-certified-providers) for some OpenID
Certified providers.

### Configure the Example

#### In the file `AppAuthExampleViewController.m` 

1. Update `kIssuer` with the IdP's issuer.
2. Update `kClientID` with your new client id.
3. Update `kRedirectURI` redirect URI

#### In the file `Info.plist`

Fully expand "URL types" (a.k.a. `CFBundleURLTypes`) and replace
`com.example.app` with the *scheme* of your redirect URI. 
The scheme is everything before the colon (`:`).  For example, if the redirect
URI is `com.example.app:/oauth2redirect/example-provider`, then the scheme
would be `com.example.app`.

### Running the Example

Now your example should be ready to run.

---

### Overview (`Examples/Example-iOS_Swift-Carthage/README.md`)

# Example Project

## Setup & Open the Project

You'll need to have [Carthage](https://github.com/Carthage/Carthage) installed
in order to pull the AppAuth dependency.

So first run `carthage bootstrap` to build AppAuth framework then open the
`Example.xcodeproj` file.

## Configuration

The example doesn't work out of the box, you need to configure it with your own
client ID.

### Information You'll Need

* Issuer
* Client ID
* Redirect URI

How to get this information varies by IdP, but we have
[instructions](../README.md#openid-certified-providers) for some OpenID
Certified providers.

### Configure the Example

#### In the file `AppAuthExampleViewController.swift` 

1. Update `kIssuer` with the IdP's issuer.
2. Update `kClientID` with your new client id.
3. Update `kRedirectURI` redirect URI

#### In the file `Info.plist`

Fully expand "URL types" (a.k.a. `CFBundleURLTypes`) and replace
`com.example.app` with the *scheme* of your redirect URI. 
The scheme is everything before the colon (`:`).  For example, if the redirect
URI is `com.example.app:/oauth2redirect/example-provider`, then the scheme
would be `com.example.app`.

### Running the Example

Now your example should be ready to run.

---

### Overview (`Examples/Example-iOS_Swift-SPM/README.md`)

# Example Project (SwiftUI + Swift Package Manager)

## Setup & Open the Project

This sample uses the local AppAuth Swift Package via a relative path (`../..`), so Xcode resolves it automatically.

Just open `Example.xcodeproj` to get started, and complete the configuration.

## Configuration

The example doesn't work out of the box — you need to configure it with your own OpenID Connect client.

### Information You'll Need

* Issuer
* Client ID
* Redirect URI

How to get this information varies by IdP, but we have [instructions](../README.md#openid-certified-providers) for some OpenID Certified providers.

### Configure the Example

The sample reads these values (Issuer, Client ID, Redirect URI) from an xcconfig file. Create your local override file by copying the committed defaults:

    cp Config/Example.xcconfig Config/Example.local.xcconfig

Then edit `Config/Example.local.xcconfig` and set:

    OIDC_ISSUER = <your IdP's issuer URL>
    OIDC_CLIENT_ID = <your client ID>
    OIDC_REDIRECT_URI = <your redirect URI>
    OIDC_REDIRECT_URI_SCHEME = <scheme portion of redirect URI>

The scheme is everything before the colon (:) of your redirect URI. For example, if the redirect URI is `com.example.app:/oauth2redirect/example-provider`, the scheme is `com.example.app`.

Note that the local version you create, `Config/Example.local.xcconfig`, is gitignored.

The same file can also override code-signing. By default the committed xcconfig sets CODE_SIGN_STYLE = Automatic, which causes Xcode to prompt for your team on first build — the same experience as the sibling samples. To use Manual signing with a specific provisioning profile, add these lines to Config/Example.local.xcconfig:

    CODE_SIGN_STYLE = Manual
    DEVELOPMENT_TEAM = <your team ID>
    PROVISIONING_PROFILE_SPECIFIER = <your profile name>

Note: Xcode may cache Info.plist substitutions — after editing the xcconfig, run **Product > Clean Build Folder**.

### Running the Example

Now your example should be ready to run.

---

### Overview (`Examples/Example-macOS/README.md`)

# Example Project

## Setup & Open the Project

1. In the `Example-macOS` folder, run the following command to install the
AppAuth pod.

```
pod install
```

2. Open the `Example-macOS.xcworkspace` workspace

```
open Example-macOS.xcworkspace
```

This workspace is configured to include AppAuth via CocoaPods. You can also
directly include AppAuth as a static library using the build targets in the
`AppAuth.xcodeproj` project.

## Configuration

The example doesn't work out of the box, you need to configure it with your own
client ID.

### Information You'll Need

* Issuer
* Client ID
* Client Secret
* Redirect URI (optional: if not using loopback).

How to get this information varies by IdP, but we have
[instructions](../README.md#openid-certified-providers) for some OpenID
Certified providers.

### Configure the Example

#### In the file `AppAuthExampleViewController.m` 

1. Update `kIssuer` with the IdP's issuer.
2. Update `kClientID` with your new client id.
3. Update `kClientSecret` with your client id's secret.
4. Update `kRedirectURI` redirect URI (optional: if not using loopback)

#### In the file `Info.plist`

Fully expand "URL types" (a.k.a. `CFBundleURLTypes`) and replace
`com.example.app` with the *scheme* of your redirect URI. 
The scheme is everything before the colon (`:`).  For example, if the redirect
URI is `com.example.app:/oauth2redirect/example-provider`, then the scheme
would be `com.example.app`.

### Running the Example

Now your example should be ready to run.

---

### Overview (`Examples/Example-tvOS/README.md`)

# Example Project

## Setup & Open the Project

1. In the `Example-tvOS` folder, run the following command to install the AppAuth pod with the TV
subspec.

```
pod install
```

2. Open the `Example-tvOS.xcworkspace` workspace.

```
open Example-tvOS.xcworkspace
```

This workspace is configured to include AppAuth via CocoaPods. You can also include AppAuthTV using 
Carthage or Swift Package Manager, please see the main [README](../../README.md) for instructions. 

## Configuration

The example doesn't work out of the box; you need to configure it with your own client and IdP details.

### Information You'll Need

* Client ID
* Client Secret (optional)

If you are choosing to automatically discover endpoints:

* Issuer URL

If you are choosing to manually specify endpoints:

* Device Authorization Endpoint
* Token Endpoint
* User Info Endpoint

How to get this information varies by IdP, but we have 
[instructions](../README.md#openid-certified-providers) for some OpenID Certified providers.

### Configure the Example

#### In the file `AppAuthTVExampleViewController.m` 

1. Update `kClientID` with your new client ID.
2. Update `kClientSecret` with your client ID's secret, or set to `""` if not using.

If you are choosing to automatically discover endpoints, also:

1. Update `kIssuer` with the issuer URL.
2. Set `shouldDiscoverEndpoints` to `YES`

If you are choosing to manually specify endpoints, also:

1. Set `shouldDiscoverEndpoints` to `NO`
2. Update `kDeviceAuthorizationEndpoint` with the device authorization endpoint.
3. Update `kTokenEndpoint` with the token endpoint.
4. Update `kUserInfoEndpoint` with the token endpoint.

### Running the Example

Now your example should be ready to run.

---

--- METRICS ---
- Files Extracted: 8
- Estimated Token Budget: ~9326 tokens
- Canonical Reference: https://codewiki.google/github.com/openid/AppAuth-iOS
