{
	"id": "1cce570a-c742-49af-94f7-ab94dfcb49f6",
	"created_at": "2026-04-29T02:22:10.192013Z",
	"updated_at": "2026-04-29T08:21:41.377529Z",
	"deleted_at": null,
	"sha1_hash": "e8c43595fb7b595d744cfff1b1f0217a5754092c",
	"title": "Build an iOS App Using OAuth 2.0 and PKCE | SecureAuth Connect Product Docs",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 357746,
	"plain_text": "Build an iOS App Using OAuth 2.0 and PKCE | SecureAuth\r\nConnect Product Docs\r\nArchived: 2026-04-29 02:13:24 UTC\r\nLearn how to create an iOS application to authenticate user via OIDC protocol using the OAuth Proof Key for\r\nCode Exchange (PKCE) flow.\r\nOverview\r\nIn this tutorial, we will explore a simple iOS application to authenticate user utilizing OIDC with authorization\r\ncode grant type with PKCE. Additionally, Authentication Services provided by the iOS SDK are used as they\r\nprovide an external user-agent that the developer cannot access and mitigates and prevents the risk of rogue\r\napplications from receiving the authorization server callback. This application follows best practices as described\r\nin the OAuth for Native Apps specification.\r\nMobile applications should be generally treated as untrusted clients and must be assumed that they cannot store\r\nany system credentials securely. An application developer should not store any long lived system credentials\r\nsecrets in these applications since they can be decompiled and the secrets extracted.With mobile and native\r\napplications it is also possible for multiple applications to register the same custom URL scheme. The behavior is\r\nthen undefined for which application receives the callback from the authorization server.\r\nBoth of these concerns can be mitigated by using OAuth Proof Key for Code Exchange (PKCE) flow and, in the\r\ncase of an iOS application, taking advantage of the iOS SDK frameworks that ensure the correct application is\r\ngiven the authorization code.\r\nReference repository\r\nPrerequisites\r\nSecureAuth tenant\r\nWorkspace and Client application prepared for PKCE\r\nXcode 13+\r\niOS 15+\r\nPrepare SecureAuth Workspace\r\n1. In your workspace, create a new client application.\r\n2. For the client application you created, set the token endpoint authentication method to None.\r\nhttps://docs.secureauth.com/ciam/en/build-an-ios-app-using-oauth-2-0-and-pkce.html\r\nPage 1 of 11\n\n3. Optionally, in Auth Settings under the General tab turn on Enforce PKCE for all clients.\r\nSetting up enforcement of PKCE for all client application causes that all applications registered within this\r\nworkspace must use the Proof Key for Code Exchange.\r\n4. In your application settings, copy the client identifier, token endpoint, and authorization endpoints from the\r\nOAuth tab.\r\n5. Set the redirect URI.\r\nThe redirect URI should include your custom URL scheme and the reverse DNS string for your domain\r\nand application name to ensure uniqueness.\r\nhttps://docs.secureauth.com/ciam/en/build-an-ios-app-using-oauth-2-0-and-pkce.html\r\nPage 2 of 11\n\nIn the sample iOS application, the identifier is set to com.example.simple-pkce and the scheme is set to\r\noauth in the Info.plist as shown in the next section. Therefore, in your client application set the\r\nredirect URI to oauth://com.example.simple-pkce as shown above. In a production-ready application,\r\nchoose an appropriate scheme and a reverse DNS string.\r\nConfigure the Sample iOS Application\r\nFirst clone the provided github repo and let's configure the application. In this tutorial, we will configure and run\r\nthe app first and then explore the code for understanding.\r\nThe iOS Application can be configured in two ways:\r\n1. Using custom iOS target properties in Xcode\r\n2. Directly in the Info.plist File\r\nUsing custom iOS target properties in Xcode\r\n1. In the custom iOS target properties menu in Xcode, set the values of the client identifier, token endpoint\r\nURL, and the authorize endpoint URL.\r\nhttps://docs.secureauth.com/ciam/en/build-an-ios-app-using-oauth-2-0-and-pkce.html\r\nPage 3 of 11\n\nYou can find all needed credentials in the SecureAuth platform in your client application settings.\r\n2. In the URL Types, set the identifier to the reverse DNS string that incorporates your domain and\r\napplication name.\r\n3. Set URL Schemes to your chosen scheme ensuring that the values match the redirect URI that was set in\r\nthe previous section.\r\nIf the values set in the previous section are left as the defaults in the sample application, no change is\r\nrequired for this step.\r\nDirectly in the Info.plist File\r\nConfigure the sample iOS application as in the example below:\r\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\r\n\u003c!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"\u003e\r\n\u003cplist version=\"1.0\"\u003e\r\n\u003cdict\u003e\r\n \u003ckey\u003eAuthorizeEndpoint\u003c/key\u003e\r\n \u003cstring\u003e--enter authorization URL--\u003c/string\u003e\r\n \u003ckey\u003eCFBundleURLTypes\u003c/key\u003e\r\nhttps://docs.secureauth.com/ciam/en/build-an-ios-app-using-oauth-2-0-and-pkce.html\r\nPage 4 of 11\n\n\u003carray\u003e\r\n \u003cdict\u003e\r\n \u003ckey\u003eCFBundleTypeRole\u003c/key\u003e\r\n \u003cstring\u003eViewer\u003c/string\u003e\r\n \u003ckey\u003eCFBundleURLName\u003c/key\u003e\r\n \u003cstring\u003e--enter reverse DNS string here--\u003c/string\u003e\r\n \u003ckey\u003eCFBundleURLSchemes\u003c/key\u003e\r\n \u003carray\u003e\r\n \u003cstring\u003e--enter scheme here--\u003c/string\u003e\r\n \u003c/array\u003e\r\n \u003c/dict\u003e\r\n \u003c/array\u003e\r\n \u003ckey\u003eClientID\u003c/key\u003e\r\n \u003cstring\u003e--enter client ID here--\u003c/string\u003e\r\n \u003ckey\u003eTokenEndpoint\u003c/key\u003e\r\n \u003cstring\u003e--enter token endpoint URL here--\u003c/string\u003e\r\n\u003c/dict\u003e\r\n\u003c/plist\u003e\r\nNote that a custom URL scheme is used. Since we are using the iOS SDK, Authentication Services provided by\r\nthe iOS SDK help to protect the application from rogue applications getting the callback from the authorization\r\nserver. However, when not using Authentication Services, it is possible for multiple applications to register the\r\nsame callback.\r\nThis is where PKCE is helpful because any application that receives the callback with the authorization code also\r\nneeds the corresponding code verifier for the code challenge presented to the authorization server. This will be\r\nexplored more in the following sections.\r\nRun the application\r\n1. Run the application and verify there are no errors. You should see the sign-in screen as shown.\r\nhttps://docs.secureauth.com/ciam/en/build-an-ios-app-using-oauth-2-0-and-pkce.html\r\nPage 5 of 11\n\n2. Log in to the application by tapping Sign In.\r\nYou should see no errors and be presented with the SecureAuth OAuth sign-in modal.\r\nYou can view the token header and the payload by selecting the corresponding tabs from the home screen\r\nupon successful login.\r\nAdditionally, there is a tab for Resources. The Resources tab is explored further in the next section.\r\nExplore the Code\r\nThe relevant portion of the code for handling the authentication flow can be seen in the Helpers folder in\r\nAuthenticator.swift . The Authenticator class uses AuthenticationServices to simplify the authentication flow.\r\nIt also restricts access to the browser presented to the user because the application developer cannot access what\r\nthe user enters since it is an external user-agent. Developers should not use an embedded webview since the users'\r\nentries could be visible to the developer. Furthermore, an embedded view would not share session data with the\r\nmobile applications primary browser.\r\nThe authenticate() method starts the authentication flow by first generating a code verifier as explained in\r\nRFC 7636 . The authenticate() method then gets the authentication endpoint URL and required parameters. In\r\nthe next section, the authentication URL and its parameters are explored in more detail. In the event, if the\r\nauthentication URL is not set, an error is returned.\r\nNotice that since PKCE is being used, a code challenge, generated from the code verifier, is included as required\r\nby RFC 7636\r\nfunc authenticate() {\r\n codeGenerator.generateVerifier()\r\n guard let authURL = URL(string: AuthConfig.authEndpoint)?.getAuthURL(clientID: AuthConfig.clientID, chal\r\n self.completion(nil, .failedToSetAuthURL)\r\nhttps://docs.secureauth.com/ciam/en/build-an-ios-app-using-oauth-2-0-and-pkce.html\r\nPage 6 of 11\n\nreturn\r\n}\r\nAn ASWebAuthenticationSession is obtained by providing the authentication URL with required parameters and\r\nthe callback URL scheme. In the callback, a check is performed for an error. If there is no error, the callback URL\r\nis verified to be present and it is verified that no error is returned from the OAuth server. Finally, the authorization\r\ncode is extracted from the query parameters and passed to fetchToken(code: String) .\r\nlet session = ASWebAuthenticationSession(url: authURL, callbackURLScheme: \"oauth\")\r\n { [self] callbackURL, error in\r\n guard error == nil else {\r\n self.completion(nil, .cancelled)\r\n return\r\n }\r\n guard let callbackURL = callbackURL else {\r\n self.completion(nil, .callbackMissingCallbackURL)\r\n return\r\n }\r\n guard callbackURL.getQueryParam(value: \"error\") == nil else {\r\n self.completion(nil, .errorReturnedFromAuthorize(callbackURL.getQueryParam(value: \"error\")!))\r\n return\r\n }\r\n guard let code = callbackURL.getQueryParam(value: \"code\") else {\r\n self.completion(nil, .callbackMissingCode)\r\n return\r\n }\r\n self.fetchToken(code: code)\r\n }\r\n session.presentationContextProvider = self\r\n session.prefersEphemeralWebBrowserSession = true\r\n session.start()\r\nThe fetchToken(code: String) method retrieves the code verifier and creates a URLRequest using the code\r\nverifier and the authorization code returned from the SecureAuth OAuth server. A request for the token to the\r\ntoken endpoint is made. If there is an error, the UI is updated with the error. Otherwise, the token is saved and the\r\nuser is presented with the application home screen.\r\nprivate func fetchToken(code: String) {\r\n guard let url = URL(string: AuthConfig.tokenEndpoint) else {\r\n self.completion(nil, .failedToGetTokenEndpoint)\r\nhttps://docs.secureauth.com/ciam/en/build-an-ios-app-using-oauth-2-0-and-pkce.html\r\nPage 7 of 11\n\nreturn\r\n }\r\n let verifier = self.codeGenerator.getVerifier()\r\n let request = url.getTokenRequest(clientID: AuthConfig.clientID, verifier: verifier, code: code, urlSche\r\n URLSession.shared.dataTask(with: request) {\r\n data,_,err in\r\n if err != nil {\r\n self.completion(nil, .tokenRequestFailed(err!))\r\n return\r\n }\r\n DispatchQueue.main.async {\r\n guard let data = data else {\r\n self.completion(nil, .unableToParseTokenResponse)\r\n return\r\n }\r\n do {\r\n let v = try JSONDecoder().decode(TokenResponse.self, from: data)\r\n self.completion(v, nil)\r\n } catch {\r\n self.completion(nil, .unableToParseTokenResponse)\r\n }\r\n }\r\n }.resume()\r\n}\r\nWhen making an authorization request, scopes are requested. In addition to the code challenge, the request also\r\nrequires the code challenge method, the redirect URI, the client ID, and, in this case, a response type set to code .\r\nThe authorization URL is constructed in the URLExtensions.swift in the getAuthURL method. In addition to\r\nthe usual parameters, the code_challenge and code_challenge_method are sent in the request. This is also\r\nwhere the requested scopes are added to the request.\r\nfunc getAuthURL(clientID: String, challenge: String, urlScheme: String) -\u003e URL? {\r\n guard var components = URLComponents(string: self.absoluteString) else {\r\n return nil\r\n }\r\n components.queryItems = [\r\n URLQueryItem(name:\"client_id\", value: clientID),\r\n URLQueryItem(name:\"redirect_uri\", value: urlScheme),\r\n URLQueryItem(name:\"response_type\", value: \"code\"),\r\n URLQueryItem(name:\"scope\", value: \"email openid profile\"),\r\n URLQueryItem(name:\"code_challenge\", value: challenge),\r\nhttps://docs.secureauth.com/ciam/en/build-an-ios-app-using-oauth-2-0-and-pkce.html\r\nPage 8 of 11\n\nURLQueryItem(name:\"code_challenge_method\", value: \"S256\"),\r\n ]\r\n return components.url\r\n}\r\nThe URLExtensions.swift file also contains the getTokenRequest method which is used to create a request and\r\nset the necessary query parameters for getting the access token using the authorization code. The code_verifier\r\nis included in the request so the authorization server can verify that this is the application for which the\r\nauthorization code was intended.\r\nfunc getTokenRequest(clientID: String, verifier: String, code: String, urlScheme: String) -\u003e URLRequest {\r\n var components = URLComponents()\r\n components.queryItems = [\r\n URLQueryItem(name:\"client_id\", value: clientID),\r\n URLQueryItem(name:\"redirect_uri\", value: urlScheme),\r\n URLQueryItem(name:\"grant_type\", value: \"authorization_code\"),\r\n URLQueryItem(name:\"code_verifier\", value: verifier),\r\n URLQueryItem(name:\"code\", value: code),\r\n ]\r\n return buildRequest(components: components)\r\n}\r\nRecall the Resources tab in the sample application. The scopes can be used to control which buttons are present,\r\nthe titles the buttons have, and the resource that is accessed when a button is tapped. In the sample application the\r\nscopes are set to email openid profile . Open the scopeData.json file under Resources in the project.\r\n[\r\n {\r\n \"scope\":\"openid\",\r\n \"title\": \"Transfer\",\r\n \"url\": \"http://localhost:8080/banking/transfer\"\r\n },\r\n {\r\n \"scope\":\"email\",\r\n \"title\": \"Balance\",\r\n \"url\": \"http://localhost:8080/banking/balance\"\r\n },\r\n {\r\n \"scope\":\"profile\",\r\n \"title\": \"Some name\",\r\n \"url\": \"http://localhost:8080/pets/pet/2\"\r\n },\r\n {\r\nhttps://docs.secureauth.com/ciam/en/build-an-ios-app-using-oauth-2-0-and-pkce.html\r\nPage 9 of 11\n\n\"scope\":\"phone\",\r\n \"title\": \"Phone\",\r\n \"url\": \"http://localhost:8080/pets/pet/1\"\r\n }\r\n]\r\nThis file contains a list of possible buttons as shown.\r\nNotice the sample application requested three scopes: email openid profile , but scopeData.json shows four\r\nentries. Upon receiving authorization, the application iterates over the scopes in scopeData.json and for each\r\nscope granted to the application, if there is a corresponding scope in this file, a button is displayed. Each entry in\r\nscopeData.json represents a JSON object with three fields. scope is a scope that the application could request.\r\nThe url is for a protected resource that the application would like to access. The title key sets the title that is\r\ndisplayed on the button. Try changing the title value for a few buttons and run the application to see the\r\nupdated title. Change scopes requested by removing one of the scopes and verify that the application only displays\r\ntwo buttons after logging in to the application.\r\nConclusion\r\nA simple iOS application was created which obtains an access token using SecureAuth authorization platform.\r\nPKCE was used with the authorization code flow ensuring that only this application can obtain an access token\r\nusing the authorization code returned from the authorization server. If another application used the same custom\r\nURL scheme and obtained the authorization code it would not be able to obtain an access token because it would\r\nnot have the correct code verifier. SecureAuth Authorization Platform conforms to the current OAuth 2.0\r\nstandards and facilitates creating secure mobile applications, protects user data, and enables developers to build\r\napplications quickly and easily with security in mind.\r\nhttps://docs.secureauth.com/ciam/en/build-an-ios-app-using-oauth-2-0-and-pkce.html\r\nPage 10 of 11\n\nSource: https://docs.secureauth.com/ciam/en/build-an-ios-app-using-oauth-2-0-and-pkce.html\r\nhttps://docs.secureauth.com/ciam/en/build-an-ios-app-using-oauth-2-0-and-pkce.html\r\nPage 11 of 11",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MITRE"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://docs.secureauth.com/ciam/en/build-an-ios-app-using-oauth-2-0-and-pkce.html"
	],
	"report_names": [
		"build-an-ios-app-using-oauth-2-0-and-pkce.html"
	],
	"threat_actors": [],
	"ts_created_at": 1777429330,
	"ts_updated_at": 1777450901,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/e8c43595fb7b595d744cfff1b1f0217a5754092c.pdf",
		"text": "https://archive.orkl.eu/e8c43595fb7b595d744cfff1b1f0217a5754092c.txt",
		"img": "https://archive.orkl.eu/e8c43595fb7b595d744cfff1b1f0217a5754092c.jpg"
	}
}