Introdução ao OAuth 2.0 e JWT em Swift
Aplicativos modernos para dispositivos móveis e desktop em Swift (iOS/macOS) usam cada vez mais o protocolo OAuth 2.0 e o formato JWT (JSON Web Token) para autorização segura. O OAuth 2.0 fornece acesso delegado a recursos, enquanto o JWT permite a transmissão compacta e segura de dados do usuário. Neste artigo, vamos detalhar como implementar uma cadeia de autorização completa em Swift: desde a obtenção de um token até sua verificação e renovação.
Abordaremos:
- Fundamentos do OAuth 2.0: fluxos e papéis
- Estrutura do JWT e sua decodificação em Swift
- Implementação prática de autorização usando
URLSession - Armazenamento de tokens no Keychain e renovação dos mesmos
Fundamentos do OAuth 2.0 para um Desenvolvedor Swift
OAuth 2.0 é um protocolo de autorização que permite que um aplicativo obtenha acesso limitado aos recursos de um usuário sem compartilhar suas credenciais. No contexto de aplicativos Swift, o Fluxo de Código de Autorização com PKCE (Proof Key for Code Exchange) é o mais comumente usado para aplicativos móveis.
Componentes Chave do OAuth 2.0
- Proprietário do Recurso — o usuário, proprietário dos dados
- Cliente — seu aplicativo Swift
- Servidor de Autorização — o servidor que emite tokens (ex.: Google, Facebook, seu backend)
- Servidor de Recursos — a API que fornece dados protegidos
Um fluxo típico em Swift se parece com isto:
- O aplicativo abre uma visualização web (SFSafariViewController ou ASWebAuthenticationSession) para autenticação do usuário.
- Após o login bem-sucedido, o servidor redireciona para uma URL de callback com um código temporário.
- O aplicativo troca o código por um token de acesso e um token de atualização.
- O token de acesso é usado para requisições à API, e o token de atualização é usado para obter um novo token de acesso quando ele expirar.
Estrutura do JWT e Sua Decodificação em Swift
O JWT consiste em três partes separadas por pontos: header.payload.signature. Exemplo de JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikl2YW4gUGV0cm92IiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5cDecodificando o payload em Swift (sem verificação de assinatura):
import Foundation
struct JWT { static func decodePayload(_ token: String) -> [String: Any]? { let segments = token.components(separatedBy: ".") guard segments.count == 3 else { return nil } var base64 = segments[1] .replacingOccurrences(of: "-", with: "+") .replacingOccurrences(of: "_", with: "/") let length = Double(base64.lengthOfBytes(using: .utf8)) let requiredLength = 4 * ceil(length / 4.0) let padding = Int(requiredLength - length) if padding > 0 { base64 += String(repeating: "=", count: padding) } guard let data = Data(base64Encoded: base64) else { return nil } return try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] }}
// Usageif let payload = JWT.decodePayload("your.jwt.token") { print(payload["sub"] ?? "") print(payload["exp"] ?? "")}Para verificação completa da assinatura do JWT no lado do cliente, use a biblioteca SwiftJWT ou JWTDecode, disponível via Swift Package Manager.
Implementando OAuth 2.0 e JWT em Swift
Passo 1: Configurando URLSession e Modelos de Token
struct AuthToken: Codable { let accessToken: String let refreshToken: String? let expiresIn: Int let tokenType: String}
class AuthService { private let session = URLSession.shared