OAuth 2.0 e autorização JWT em Swift: guia prático

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: por que OAuth 2.0 e JWT são o padrão para aplicativos iOS

\n

Os aplicativos móveis modernos raramente funcionam isoladamente. A maioria deles interage com APIs remotas, exigindo autenticação e autorização seguras do usuário. No ecossistema Apple (iOS, macOS, watchOS), a combinação de OAuth 2.0 (protocolo de delegação de acesso) e JWT (JSON Web Token — formato compacto de token) tornou-se o padrão de fato. Essa combinação oferece flexibilidade, segurança e facilidade de integração.

\n

Neste artigo, não vamos nos aprofundar em teoria seca. Em vez disso, vamos abordar a implementação prática em Swift. Você aprenderá como obter um token de acesso via OAuth 2.0, como armazená-lo com segurança no Keychain, como decodificar JWT no cliente e como renovar tokens sem a intervenção do usuário. Todos os exemplos de código estão prontos para uso em um projeto real.

\n\n

1. Arquitetura OAuth 2.0 em Swift: da solicitação ao token

\n

Primeiro, vamos definir o fluxo (flow). Em aplicativos móveis, o mais utilizado é o Authorization Code Flow with PKCE (Proof Key for Code Exchange). Esta é a opção mais segura para clientes públicos (aplicativos móveis não podem armazenar segredos).

\n

Vamos criar uma estrutura para a configuração OAuth:

\n
struct OAuthConfig {\n    let clientID: String\n    let redirectURI: String\n    let authorizationEndpoint: String\n    let tokenEndpoint: String\n    let scope: String\n}
\n

O primeiro passo é formar a URL para autorização. Para PKCE, precisamos gerar um codeVerifier e seu hash SHA256 — codeChallenge:

\n
import Foundation\nimport CommonCrypto\n\nclass PKCEGenerator {\n    static func generateCodeVerifier() -> String {\n        var buffer = [UInt8](repeating: 0, count: 32)\n        _ = SecRandomCopyBytes(kSecRandomDefault, buffer.count, &buffer)\n        return Data(buffer).base64URLEncodedString()\n    }\n    \n    static func generateCodeChallenge(from verifier: String) -> String {\n        guard let data = verifier.data(using: .utf8) else { return "" }\n        var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))\n        data.withUnsafeBytes { \n            _ = CC_SHA256($0.baseAddress, CC_LONG(data.count), &hash)\n        }\n        return Data(hash).base64URLEncodedString()\n    }\n}\n\nextension Data {\n    func base64URLEncodedString() -> String {\n        return self.base64EncodedString()\n            .replacingOccurrences(of: "+", with: "-")\n            .replacingOccurrences(of: "/", with: "_")\n            .replacingOccurrences(of: "=", with: "")\n    }\n}
\n

Agora, formamos a URL para abrir no navegador (via ASWebAuthenticationSession):

\n
func buildAuthorizationURL(config: OAuthConfig, codeChallenge: String) -> URL? {\n    var components = URLComponents(string: config.authorizationEndpoint)\n    components?.queryItems = [\n        URLQueryItem(name: "response_type", value: "code"),\n        URLQueryItem(name: "client_id", value: config.clientID),\n        URLQueryItem(name: "redirect_uri", value: config.redirectURI),\n        URLQueryItem(name: "scope", value: config.scope),\n        URLQueryItem(name: "code_challenge", value: codeChallenge),\n        URLQueryItem(name: "code_challenge_method", value: "S256")\n    ]\n    return components?.url\n}
\n

Após a autorização bem-sucedida, o usuário será redirecionado para a redirectURI com o parâmetro code. Esse código é trocado por tokens:

\n
func exchangeCodeForToken(config: OAuthConfig, code: String, codeVerifier: String) async throws -> TokenResponse {\n    let url = URL(string: config.tokenEndpoint)!\n    var request = URLRequest(url: url)\n    request.httpMethod = "POST"\n    request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")\n    \n    let body = "grant_type=authorization_code" +\n               "&co                

Blogs

Book Recommendations