Utilisation d'AuthenticationServices en SwiftUI

Bonjour,

Je suis actuellement sur un projet d’app sur WatchOS utilisant un web service. Il s’agit d’une app indépendante.

L’idée est de pouvoir utiliser cette API pour récupérer un certain nombre d’informations. La documentation de l’API demande une identification par protocole OAuth 2.

J’ai donc pu trouver dans la documentation d’xCode des informations à ce sujet mais j’avoue ne pas tout bien saisir.

J’ai réussi à créer un lien vers la page internet d’identification grâce à ASWebAuthenticationService. Lorsque je clique dessus, un fenêtre apparait alors et affiche la page d’identification du web service. Je peux y saisir mes identifiants (et même utiliser le trousseau iCloud) et lorsque je valide je reçois bien un mail pour me dire que je suis connecté depuis la montre.

Seulement sur mon app, la fenêtre se rafraichit et les champs apparaissent de nouveau vide. Je ne parviens pas à attraper les informations renvoyées pour obtenir le token.

Est-ce que certains d’entre vous ont déjà utilisé authentication services ? Auriez vous des pistes et encore mieux, des liens explicatifs pour utiliser Authentication services avec OAuth ?

Bonjour Christophe,

malheureusement je n’ai jamais utilisé ce type d’authentification web mais je pense que tu dois trouver un moyen de récupérer ce token car sans lui le serveur ne te reconnaîtra pas.
Si tu reçois l’email confirmant ta connexion c’est que le token a bien été généré donc il faut juste trouver le moyen de le récupérer pour tes prochaines requêtes

Bonjour Maxime,

C’est bien là mon problème, je n’arrive pas à le récupérer. J’espérai trouver quelqu’un ayant déjà utilisé ce type d’authentification.

Je vais creuser encore. Mais j’avoue coincer sur ce point.

Selon la doc officielle et notamment ce guide : Authenticating a User Through a Web Service | Apple Developer Documentation

Tu as une closure à fournir à ton objet ASWebAuthenticationService et cette closure te sert de callback lorsque le site OAuth cherche à te donner ton token.
Généralement le token est un paramètre contenu dans l’URL de redirection.
Et d’ailleurs, dans la doc ils te donnent un exemple de code pour ce callback :

guard error == nil, let callbackURL = callbackURL else { return }

// The callback URL format depends on the provider. For this example:
//   exampleauth://auth?token=1234
let queryItems = URLComponents(string: callbackURL.absoluteString)?.queryItems
let token = queryItems?.filter({ $0.name == "token" }).first?.value

Dans cet exemple ils imaginent que le token est un paramètre d’URL (queryItem) qui s’appellerai token, quelque chose comme ça : https://www.url-de-redirection.com/authenticated?token=ABC-123-DEF et ton token extrait serait ABC-123-DEF

Ce que tu dois faire avec ce token, est de l’enregistrer en local et de considérer ton utilisateur comme connecté.
Puis pour chaque requete au webservice en question, tu vas réutiliser ce token. Ca dépend du webservice mais généralement c’est sous la forme d’un entête http :

Authorization: Bearer ABC-123-DEF

Merci Maxime d’avoir étudier la doc. Je vais regarder ça de plus près.

Je croise les doigts pour m’en sortir. :crossed_fingers:

1 « J'aime »

Et bien me revoilà. Je vais profiter des nouveaux cours sur iOS 17 pour me remettre un peu dans le bain. J’avoue que ce n’est pas toujours très simple après une longue interruption. mais je suis confiant.

Pour ce qui est de l’utilisation d’AuthenticationServices, je ne progresse pas du tout.

J’ai d’ailleurs voulu créer une app gérant juste cet accès afin de m’exercer et c’est encore pire que sur WatchOS. Je n’arrive même pas à afficher la page internet de connexion au web service. N’y connaissant absolument rien à UIKit, je pense que le problème se situe là. L’intégration d’AuthenticationServices ne semble pas être faite dans SwiftUI.

Bref je patauge complètement dans cette histoire. Il va falloir que je revois mes objectifs à la baisse :joy:.

Tu aurais un bout de code à montrer ?

Désolé pour cette longue absence. Mon activité principale a été très chronophage (plus que ce que je pensais :face_exhaling:)

Je souhaite vraiment me remettre à fond dans le code ce coup-ci. J’ai hâte de pouvoir reprendre les cours de Maxime.

Voici ce que j’ai fait comme code :

import SwiftUI
import AuthenticationServices

struct ContentView: View {
    
    var body: some View {
        VStack {
            Button("Authentification") {
                guard let url = URL(string: "https://api.netatmo.com/oauth2/authorize?client_id=6232270c8ed760672f7ac299&redirect_uri=://auth&scope=read_station&state=fzezef5zegfr5grv5vr5ezrz6rz9trgzg4rgre") else { return }
                
                let callback = "auth"
                
                let session = ASWebAuthenticationSession(url: url,callbackURLScheme: callback) { callbackURL, error in
                    print(callbackURL ?? "pas de callback")
                    print(error ?? "pas d'erreur")
                    guard error == nil, let callbackURL = callbackURL else { return }
                    
                    // The callback URL format depends on the provider. For this example:
                    //   exampleauth://auth?token=1234
                    let queryItems = URLComponents(string: callbackURL.absoluteString)?.queryItems
                    print(queryItems!)
                    let token = queryItems?.filter({ $0.name == "state" }).first?.value
                    print(token as Any)
                    
                }
                session.prefersEphemeralWebBrowserSession = true
                session.start()
                
            }
        }
        .padding()
    }
}

Et voici l’erreur affichée dans la console lorsque je clique sur le bouton d’authentification :

Error Domain=com.apple.AuthenticationServices.WebAuthenticationSession Code=2 « Cannot start ASWebAuthenticationSession without providing presentation context. Set presentationContextProvider before calling -start. » UserInfo={NSDebugDescription=Cannot start ASWebAuthenticationSession without providing presentation context. Set presentationContextProvider before calling -start.}

Je pense que je me lance dans quelque chose de trop complexe pour mon petit niveau. C’est dommage car l’app qui utilise ce web service fonctionne plutôt bien. J’était assez content du résultat. Le web service a entre 2 changé ses règles d’identification et impose de passer par Oauth 2.

Autre chose que j’ai oublié de mentionné : ce lien fonctionne sur WatchOS. Lorsque je clique dessus depuis mon app dédiée à WatchOS, j’ai bien la page internet de connexion du fournisseur de l’API. Je peux saisir mon identifiant et mot de passe. Lorsque je valide, la page se rafraichit et réapparaît.Je reçois dans le même temps un mail du fournisseur pour m’indiquer que je viens d’accepter la connexion depuis une Apple Watch.

Cela veut dire qu’il y a quand même un certains nombre d’éléments qui se déroulent correctement. Je ne parviens pas à récupérer le retour fait par Netatmo et donc je ne peux pas récupérer le token.

Par contre sur iOS, je n’arrive même pas à afficher la page de connexion Netatmo.

Bon, me voilà de nouveau sur Purple Girrafe.
Je vais pouvoir profiter de mon temps libre et de visionner de nouveau certains cours pour essayer de me sortir de cette situation.

Si vous avez des pistes de réflexion, je suis preneur.

Je continu mes recherches concernant mon problème d’authentification sur mon app.

J’ai voulu suivre le cours sur l’intégration de Passkeys à une app en espérant pouvoir trouver une piste pour ma situation.

Dès les 1ères vidéos, il est expliqué qu’il faut ajouter la Capabilities « Associated Domain » pour pouvoir utiliser ce genre de fonction. J’ai pu lire la même information concernant mon problème.

Seulement il m’est impossible d’ajouter ceci à mon app. D’ailleurs, cela est impossible également pour suivre l’exemple du cours sur Passkeys.

J’ai donc essayé de désactiver « Automatically manage signing » et là je peux ajouter « Associated domain ».
Par contre, dès que je souhaite activer « Automatically manage signing » j’obtiens une erreur m’indiquant que je ne possède pas les autorisations pour utiliser cette Capabilitie.

J’en déduis que mon compte développeur gratuit ne me permet pas de me lancer dans ce genre de service. Est ce que l’un d’entre vous peux me le confirmer ?

Je suis un peu déçu, mon app est devenue complètement inutilisable, l’API interdisant le passage du nom d’utilisateur et du mot de passe dans une requête URL.

Dommage, j’avais bien avancé et j’étais plutôt content de ce que j’avais réussi à faire…