Añade autenticación a tu aplicación iOS (Swift)
Esta guía asume que has creado una Aplicación del tipo "Native app" en la Consola de Administración.
Instalación
La versión mínima de iOS compatible con Logto Swift SDK es iOS 13.
Logto Swift SDK viene en dos versiones principales:
- v2: Abre la experiencia de inicio de sesión en
ASWebAuthenticationSession(el navegador del sistema), lo que habilita el inicio de sesión con passkey y comparte la sesión del navegador. Ten en cuenta que v2 elimina los targets de plugins sociales nativos; los conectores sociales siguen funcionando a través del navegador. Si dependes de la transferencia con el SDK nativo de WeChat o Alipay, permanece en v1. - v1: Abre la experiencia de inicio de sesión en un WebView embebido, lo cual es requerido por los targets de plugins sociales nativos, pero no admite el inicio de sesión con passkey (WebView no soporta WebAuthn, el estándar subyacente de las passkeys).
Esta guía cubre ambas versiones. Elige tu versión en las pestañas de abajo, y la elección se mantendrá sincronizada a lo largo de esta guía.
Utiliza la siguiente URL para añadir Logto SDK como dependencia en Swift Package Manager.
https://github.com/logto-io/swift.git
Desde Xcode 11, puedes importar directamente un paquete Swift sin ninguna herramienta adicional.
Cuando Xcode solicite la versión del paquete, elige la versión que deseas integrar:
- v2
- v1
Utiliza la última versión v2 como versión. La última versión v2 es 2.0.0.
Si usas Package.swift directamente:
// Agrega la dependencia de Logto Swift SDK versión 2.0.0 o superior
.package(url: "https://github.com/logto-io/swift.git", from: "2.0.0")
Utiliza la última versión v1 si necesitas los targets de plugins sociales nativos. La última versión v1 es 1.2.0.
Si usas Package.swift directamente:
// Agrega la dependencia de Logto Swift SDK versión 1.2.0 o superior
.package(url: "https://github.com/logto-io/swift.git", from: "1.2.0")
No ofrecemos soporte para Carthage ni CocoaPods en este momento debido a algunos problemas técnicos.
Carthage
Carthage necesita un archivo xcodeproj para compilar. Intentaremos encontrar una solución alternativa más adelante.
CocoaPods
CocoaPods no admite dependencias locales ni monorepo, por lo tanto es difícil crear un .podspec para este repositorio.
Integración
Inicializar LogtoClient
Inicializa el cliente creando una instancia de LogtoClient con un objeto LogtoConfig.
import Logto
import LogtoClient
let config = try? LogtoConfig(
endpoint: "<your-logto-endpoint>", // Ej. http://localhost:3001
appId: "<your-app-id>"
)
let client = LogtoClient(useConfig: config)
Por defecto, almacenamos credenciales como el Token de ID (ID Token) y el Token de actualización (Refresh Token) en el Keychain. Así, el usuario no necesita iniciar sesión nuevamente cuando regresa.
Para desactivar este comportamiento, establece usingPersistStorage en false:
let config = try? LogtoConfig(
// ...
usingPersistStorage: false
)
Implementar inicio y cierre de sesión
Antes de entrar en los detalles, aquí tienes una visión general rápida de la experiencia del usuario final. El proceso de inicio de sesión se puede simplificar de la siguiente manera:
- Tu aplicación invoca el método de inicio de sesión.
- El usuario es redirigido a la página de inicio de sesión de Logto. Para aplicaciones nativas, se abre el navegador del sistema.
- El usuario inicia sesión y es redirigido de vuelta a tu aplicación (configurada como el URI de redirección).
Sobre el inicio de sesión basado en redirección
- Este proceso de autenticación sigue el protocolo OpenID Connect (OIDC), y Logto aplica medidas de seguridad estrictas para proteger el inicio de sesión del usuario.
- Si tienes múltiples aplicaciones, puedes usar el mismo proveedor de identidad (Logto). Una vez que el usuario inicia sesión en una aplicación, Logto completará automáticamente el proceso de inicio de sesión cuando el usuario acceda a otra aplicación.
Para aprender más sobre la lógica y los beneficios del inicio de sesión basado en redirección, consulta Experiencia de inicio de sesión de Logto explicada.
Configurar URI de redirección
- v2
- v1
Vamos a cambiar a la página de detalles de la aplicación en Logto Console. Añade un URI de redirección io.logto.app://callback y haz clic en "Guardar cambios".

En la versión v2, la experiencia de inicio de sesión se abre en ASWebAuthenticationSession (el navegador del sistema), y la redirección se enruta de vuelta a tu app mediante la coincidencia de callback a nivel del sistema operativo. Para un URI de redirección con esquema personalizado como io.logto.app://callback, registra solo la parte del esquema (io.logto.app) en el Info.plist de tu app y luego añade el URI de redirección completo en los Redirect URIs de tu aplicación Logto.
En Xcode, abre el target de tu app, selecciona Info, expande URL Types y añade una entrada con io.logto.app en URL Schemes. Si editas Info.plist directamente, añade:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>io.logto.app</string>
<key>CFBundleURLSchemes</key>
<array>
<string>io.logto.app</string>
</array>
</dict>
</array>
Para el flujo en navegador en v2, no necesitas llamar a LogtoClient.handle(url:); esa API de handoff de plugin fue eliminada junto con el flujo de WebView embebido.
¿Usar Universal Links en lugar de un esquema personalizado?
También puedes usar un URI de redirección HTTPS como https://example.com/callback:
- Añade la capacidad Associated Domains a tu app.
- Configura
webcredentials:example.compara queASWebAuthenticationSessionpueda hacer coincidir callbacks HTTPS en iOS 17.4 y versiones posteriores. - Si la misma URL también debe abrir tu app como Universal Link fuera de la sesión de autenticación, configura
applinks:example.comy hospeda un archivo válidoapple-app-site-associationpara el dominio y la ruta. - Añade el URI HTTPS a los Redirect URIs de tu aplicación Logto.
- Pasa el mismo URI a
signInWithBrowser.
En iOS 17.4 y versiones posteriores, el SDK utiliza la API de coincidencia de callback HTTPS de ASWebAuthenticationSession para que las redirecciones HTTPS puedan completarse automáticamente y cerrar la sesión. En versiones anteriores de iOS, la solicitud de autorización aún puede usar el URI de redirección HTTPS, pero la sesión puede no cerrarse automáticamente a menos que tu app maneje el callback Universal Link por sí misma. Mantén un esquema personalizado como opción de compatibilidad si necesitas finalización automática en versiones antiguas de iOS.
Vamos a cambiar a la página de detalles de la aplicación en Logto Console. Añade un URI de redirección io.logto://callback y haz clic en "Guardar cambios".

El Redirect URI en el SDK de iOS es solo para uso interno. NO HAY NECESIDAD de añadir un Custom URL Scheme hasta que un conector lo solicite.
Inicio y cierre de sesión
Antes de llamar a .signInWithBrowser(redirectUri:), asegúrate de haber configurado correctamente el URI de redirección en la Consola de Administración.
- v2
- v1
En la versión v2, client.signOut(postLogoutRedirectUri:) realiza un cierre de sesión completo: borra las credenciales locales, revoca el token de actualización y finaliza la sesión de Logto abriendo el endpoint de cierre de sesión en el navegador del sistema. El navegador luego navega de vuelta a tu app mediante el URI de redirección posterior al cierre de sesión. Antes de usarlo, ve a la página de detalles de la aplicación en Logto Console, añade el URI de redirección posterior al cierre de sesión io.logto.app://signed-out y haz clic en "Guardar cambios". El URI de redirección posterior al cierre de sesión puede usar el mismo esquema personalizado que registraste para el inicio de sesión.
Por ejemplo, en una app SwiftUI:
// Ejemplo de uso de inicio y cierre de sesión en SwiftUI
struct ContentView: View {
@State var isAuthenticated: Bool
private let redirectUri = "io.logto.app://callback"
private let postLogoutRedirectUri = "io.logto.app://signed-out"
init() {
isAuthenticated = client.isAuthenticated
}
var body: some View {
VStack {
if isAuthenticated {
Button("Sign Out") {
Task { [self] in
let error = await client.signOut(postLogoutRedirectUri: postLogoutRedirectUri)
if let error = error {
print(error)
return
}
isAuthenticated = false
}
}
} else {
Button("Sign In") {
Task { [self] in
do {
try await client.signInWithBrowser(redirectUri: redirectUri)
isAuthenticated = true
} catch let error as LogtoClientErrors.SignIn {
// error ocurrido durante el inicio de sesión
} catch {
// otros errores
}
}
}
}
}
}
}
- También puedes llamar a
client.signOut()sin un URI de redirección posterior al cierre de sesión. No se necesita configuración en Console en este caso: el navegador muestra la página de cierre de sesión de Logto y el usuario regresa a la app cerrándola manualmente. - Si no hay contexto de UI disponible, puedes llamar a
client.clearCredentials()para borrar las credenciales locales y revocar el token de actualización. Ten en cuenta que esto mantiene la sesión de Logto en el navegador, por lo que el siguientesignInWithBrowserpuede iniciar sesión al usuario silenciosamente a través de esa sesión.
Puedes usar client.signInWithBrowser(redirectUri:) para iniciar sesión del usuario y client.signOut() para cerrar la sesión del usuario.
Por ejemplo, en una app SwiftUI:
// Ejemplo de uso de inicio y cierre de sesión en SwiftUI
struct ContentView: View {
@State var isAuthenticated: Bool
init() {
isAuthenticated = client.isAuthenticated
}
var body: some View {
VStack {
if isAuthenticated {
Button("Sign Out") {
Task { [self] in
await client.signOut()
isAuthenticated = false
}
}
} else {
Button("Sign In") {
Task { [self] in
do {
try await client.signInWithBrowser(redirectUri: "io.logto://callback")
isAuthenticated = true
} catch let error as LogtoClientErrors.SignIn {
// error ocurrido durante el inicio de sesión
} catch {
// otros errores
}
}
}
}
}
}
}
Punto de control: Prueba tu aplicación
Ahora, puedes probar tu aplicación:
- Ejecuta tu aplicación, verás el botón de inicio de sesión.
- Haz clic en el botón de inicio de sesión, el SDK iniciará el proceso de inicio de sesión y te redirigirá a la página de inicio de sesión de Logto.
- Después de iniciar sesión, serás redirigido de vuelta a tu aplicación y verás el botón de cierre de sesión.
- Haz clic en el botón de cierre de sesión para limpiar el almacenamiento de tokens y cerrar sesión.
Obtener información del usuario
Mostrar información del usuario
Para mostrar la información del usuario, puedes usar el método client.getIdTokenClaims(). Por ejemplo, en una aplicación SwiftUI:
struct ContentView: View {
@State var isAuthenticated: Bool
@State var name: String?
init() {
isAuthenticated = client.isAuthenticated
name = try? client.getIdTokenClaims().name
}
var body: some View {
VStack {
if isAuthenticated {
Text("Bienvenido, \(name)")
} else {
Text("Por favor, inicia sesión")
}
}
}
}
Solicitar reclamos adicionales
Es posible que encuentres que falta alguna información del usuario en el objeto devuelto desde client.getIdTokenClaims(). Esto se debe a que OAuth 2.0 y OpenID Connect (OIDC) están diseñados para seguir el principio de privilegio mínimo (PoLP), y Logto está construido sobre estos estándares.
De forma predeterminada, se devuelven reclamos limitados. Si necesitas más información, puedes solicitar alcances adicionales para acceder a más reclamos.
Un "reclamo (Claim)" es una afirmación hecha sobre un sujeto; un "alcance (Scope)" es un grupo de reclamos. En el caso actual, un reclamo es una pieza de información sobre el usuario.
Aquí tienes un ejemplo no normativo de la relación alcance - reclamo:
El reclamo "sub" significa "sujeto", que es el identificador único del usuario (es decir, el ID del usuario).
El SDK de Logto siempre solicitará tres alcances: openid, profile y offline_access.
Para solicitar alcances adicionales, puedes pasarlos al objeto LogtoConfig. Por ejemplo:
let config = try? LogtoConfig(
endpoint: "<your-logto-endpoint>", // Ej. http://localhost:3001
appId: "<your-app-id>",
scopes: [
UserScope.Email.rawValue,
UserScope.Phone.rawValue,
]
)
Luego puedes acceder a los reclamos adicionales en el valor de retorno de client.getIdTokenClaims():
let claims = try? client.getIdTokenClaims()
// Ahora puedes acceder a los reclamos adicionales `claims.email`, `claims.phone`, etc.
Reclamos que necesitan solicitudes de red
Para evitar sobrecargar el Token de ID, algunos reclamos requieren solicitudes de red para ser obtenidos. Por ejemplo, el reclamo custom_data no se incluye en el objeto de usuario incluso si se solicita en los alcances. Para acceder a estos reclamos, puedes usar el método client.fetchUserInfo():
let userInfo = try? client.fetchUserInfo()
// Ahora puedes acceder al reclamo `userInfo.custom_data`
Alcances y reclamos
Logto utiliza las convenciones de OIDC alcances y reclamos (scopes and claims) para definir los alcances y reclamos para obtener información del usuario desde el token de ID y el endpoint OIDC userinfo. Tanto "alcance (scope)" como "reclamo (claim)" son términos de las especificaciones OAuth 2.0 y OpenID Connect (OIDC).
Para los reclamos estándar de OIDC, la inclusión en el token de ID está estrictamente determinada por los alcances solicitados. Los reclamos extendidos (como custom_data y organizations) pueden configurarse adicionalmente para aparecer en el token de ID a través de la configuración de Token de ID personalizado.
Aquí tienes la lista de alcances (Alcances) soportados y los reclamos (Reclamos) correspondientes:
Alcances OIDC estándar
openid (predeterminado)
| Claim name | Type | Description |
|---|---|---|
| sub | string | El identificador único del usuario |
profile (predeterminado)
| Claim name | Type | Description |
|---|---|---|
| name | string | El nombre completo del usuario |
| username | string | El nombre de usuario del usuario |
| picture | string | URL de la foto de perfil del usuario final. Esta URL DEBE referirse a un archivo de imagen (por ejemplo, un archivo de imagen PNG, JPEG o GIF), en lugar de a una página web que contenga una imagen. Ten en cuenta que esta URL DEBERÍA referenciar específicamente una foto de perfil del usuario final adecuada para mostrar al describir al usuario final, en lugar de una foto arbitraria tomada por el usuario final. |
| created_at | number | Momento en que se creó el usuario final. El tiempo se representa como el número de milisegundos desde la época Unix (1970-01-01T00:00:00Z). |
| updated_at | number | Momento en que se actualizó por última vez la información del usuario final. El tiempo se representa como el número de milisegundos desde la época Unix (1970-01-01T00:00:00Z). |
Otros reclamos estándar incluyen family_name, given_name, middle_name, nickname, preferred_username, profile, website, gender, birthdate, zoneinfo y locale, que también se incluirán en el alcance profile sin necesidad de solicitar el endpoint userinfo. Una diferencia en comparación con los reclamos anteriores es que estos reclamos solo se devolverán cuando sus valores no estén vacíos, mientras que los reclamos anteriores devolverán null si los valores están vacíos.
A diferencia de los reclamos estándar, los reclamos created_at y updated_at utilizan milisegundos en lugar de segundos.
email
| Claim name | Type | Description |
|---|---|---|
string | La dirección de correo electrónico del usuario | |
| email_verified | boolean | Si la dirección de correo electrónico ha sido verificada |
phone
| Claim name | Type | Description |
|---|---|---|
| phone_number | string | El número de teléfono del usuario |
| phone_number_verified | boolean | Si el número de teléfono ha sido verificado |
address
Por favor, consulta OpenID Connect Core 1.0 para los detalles del reclamo de dirección.
Los alcances marcados como (predeterminado) siempre son solicitados por el SDK de Logto. Los reclamos bajo los alcances OIDC estándar siempre se incluyen en el token de ID cuando se solicita el alcance correspondiente; no se pueden desactivar.
Alcances extendidos
Los siguientes alcances son extendidos por Logto y devolverán reclamos a través del endpoint userinfo. Estos reclamos también pueden configurarse para incluirse directamente en el token de ID a través de Consola > JWT personalizado. Consulta Token de ID personalizado para más detalles.
custom_data
| Claim name | Type | Description | Included in ID token by default |
|---|---|---|---|
| custom_data | object | Los datos personalizados del usuario |
identities
| Claim name | Type | Description | Included in ID token by default |
|---|---|---|---|
| identities | object | Las identidades vinculadas del usuario | |
| sso_identities | array | Las identidades SSO vinculadas del usuario |
roles
| Claim name | Type | Description | Included in ID token by default |
|---|---|---|---|
| roles | string[] | Los roles del usuario | ✅ |
urn:logto:scope:organizations
| Claim name | Type | Description | Included in ID token by default |
|---|---|---|---|
| organizations | string[] | Los IDs de las organizaciones a las que pertenece el usuario | ✅ |
| organization_data | object[] | Los datos de las organizaciones a las que pertenece el usuario |
Estos reclamos de organización también pueden recuperarse a través del endpoint userinfo cuando se utiliza un token opaco. Sin embargo, los tokens opacos no pueden usarse como tokens de organización para acceder a recursos específicos de la organización. Consulta Token opaco y organizaciones para más detalles.
urn:logto:scope:organization_roles
| Claim name | Type | Description | Included in ID token by default |
|---|---|---|---|
| organization_roles | string[] | Los roles de organización a los que pertenece el usuario con el formato <organization_id>:<role_name> | ✅ |
Recursos de API
Recomendamos leer primero 🔐 Control de acceso basado en roles (RBAC) para entender los conceptos básicos de Logto RBAC y cómo configurar correctamente los recursos de API.
Configurar el cliente de Logto
Una vez que hayas configurado los recursos de API, puedes agregarlos al configurar Logto en tu aplicación:
let config = try? LogtoConfig(
endpoint: "<your-logto-endpoint>", // E.g. http://localhost:3001
appId: "<your-app-id>",
resources: ["https://shopping.your-app.com/api", "https://store.your-app.com/api"], // Añadir recursos de API
)
let client = LogtoClient(useConfig: config)
Cada recurso de API tiene sus propios permisos (alcances).
Por ejemplo, el recurso https://shopping.your-app.com/api tiene los permisos shopping:read y shopping:write, y el recurso https://store.your-app.com/api tiene los permisos store:read y store:write.
Para solicitar estos permisos, puedes agregarlos al configurar Logto en tu aplicación:
let config = try? LogtoConfig(
endpoint: "<your-logto-endpoint>",
appId: "<your-app-id>",
scopes: ["shopping:read", "shopping:write", "store:read", "store:write"],
resources: ["https://shopping.your-app.com/api", "https://store.your-app.com/api"],
)
let client = LogtoClient(useConfig: config)
Puedes notar que los alcances se definen por separado de los recursos de API. Esto se debe a que Resource Indicators for OAuth 2.0 especifica que los alcances finales para la solicitud serán el producto cartesiano de todos los alcances en todos los servicios objetivo.
Así, en el caso anterior, los alcances se pueden simplificar desde la definición en Logto, ambos recursos de API pueden tener alcances read y write sin el prefijo. Luego, en la configuración de Logto:
let config = try? LogtoConfig(
endpoint: "<your-logto-endpoint>",
appId: "<your-app-id>",
scopes: ["read", "write"],
resources: ["https://shopping.your-app.com/api", "https://store.your-app.com/api"],
)
let client = LogtoClient(useConfig: config)
Para cada recurso de API, se solicitarán tanto los alcances read como write.
Está bien solicitar alcances que no están definidos en los recursos de API. Por ejemplo, puedes solicitar el alcance email incluso si los recursos de API no tienen el alcance email disponible. Los alcances no disponibles serán ignorados de manera segura.
Después de un inicio de sesión exitoso, Logto emitirá los alcances apropiados a los recursos de API de acuerdo con los roles del usuario.
Obtener token de acceso para el recurso de API
Para obtener el token de acceso para un recurso de API específico, puedes usar el método getAccessToken:
let accessToken = try await client.getAccessToken(for: "https://shopping.your-app.com/api")
Este método devolverá un token de acceso JWT que se puede usar para acceder al recurso de API cuando el usuario tiene permisos relacionados. Si el token de acceso en caché actual ha expirado, este método intentará automáticamente usar un token de actualización para obtener un nuevo token de acceso.
Adjuntar token de acceso a los encabezados de solicitud
Coloca el token en el campo Authorization de los encabezados HTTP con el formato Bearer (Bearer YOUR_TOKEN), y listo.
El flujo de integración del Token Bearer puede variar según el framework o solicitante que estés utilizando. Elige tu propia forma de aplicar el encabezado de solicitud Authorization.
await LogtoRequest.get(
useSession: session,
endpoint: userInfoEndpoint,
headers: ["Authorization": "Bearer \(accessToken)"]
)