Guida pratica: Autorizzazione (applicazione)

Introduzione

In questa guida imparerai ad autenticare e autorizzare un’applicazione C2C in un progetto Frame.io.

Cosa serve?

Se non hai letto la guida Implementazione C2C: configurazione, dalle un’occhiata veloce prima di continuare!Inoltre, dovresti aver ricevuto dal nostro team un client_id che sarà utilizzato per identificare la tua integrazione.Se non hai ricevuto un client_id, leggi questa introduzione all’ecosistema C2C e contatta il nostro team.Se hai ricevuto un client_secret invece di un client_id, ti abbiamo configurato come dispositivo hardware anziché come applicazione C2C. Dovrai seguire la guida all’autorizzazione per dispositivi hardware oppure contattare il nostro team per ricevere un client_id.

Guida al flusso di autorizzazione dell’applicazione

Assicuriamoci di avere una comprensione generale dell’esperienza utente prevista per il flusso di autorizzazione che vogliamo implementare.Consulta le seguenti risorse per vedere questo flusso dal punto di vista dell’utente. Prova a scaricare Zoelog e ad accedere a Frame.io per capire come funziona il processo di autorizzazione per le applicazioni C2C.

Panoramica di OAuth

Le applicazioni C2C usano un flusso OAuth 2.0 per l’autenticazione e l’autorizzazione. Si tratta di un insieme standardizzato di chiamate che può essere utilizzato per autenticare e autorizzare un’applicazione o un utente di terze parti per un servizio. Puoi trovare altre informazioni sul flusso OAuth qui.

URI di callback/reindirizzamento

Come parte del flusso OAuth, i nostri server dovranno effettuare una chiamata HTTP a un URI/URL che sei tu a controllare. Dopo che un utente accede a Frame.io nel browser, reindirizziamo il browser a questo URI per fornire alcune informazioni alla tua applicazione. L’URI di reindirizzamento deve essere:

  • Di tua proprietà
  • Statico

Puoi avere più di un reindirizzamento valido registrato per il tuo dispositivo, purché soddisfino questi due criteri.

Durante il flusso OAuth, verifichiamo che l’URI di callback richiesto dall’applicazione sia uno degli URI che abbiamo in archivio. Se non lo è, il flusso di autorizzazione non riesce. Se non effettuassimo questo controllo, un malintenzionato potrebbe fornire un reindirizzamento a un indirizzo che controlla.

Per scopi di sviluppo, supportiamo i callback non HTTPS su http://localhost.

Identificazione del dispositivo

Al momento di connettersi a Camera to Cloud, ogni singola installazione di app deve identificarsi in modo univoco affinché sia possibile elencare le connessioni dei dispositivi nel progetto di un utente.

Per le applicazioni C2C, questo sarà il device_id del dispositivo. Quando configuri l’implementazione, devi pensare a come farlo. Alcune piattaforme offrono un’API per generare un identificatore specifico per dispositivo e app per questo caso d’uso esatto:

PIATTAFORMARIFERIMENTO
iOSidentifierForVendor
AndroidFID o GUID
Fai attenzione a non divulgare informazioni di identificazione personale

L’e-mail dell’utente, ad esempio, non è un valore valido da utilizzare come device_id. Allo stesso modo, assicurati di possedere l’identificatore univoco. Non utilizzare l’indirizzo MAC del dispositivo, ad esempio. L’indirizzo MAC non è di proprietà del tuo software e potrebbe anche essere considerato un’informazione di identificazione personale.

Se non sei sicuro del valore che vorresti utilizzare, possiamo discutere insieme questa scelta e assicurarci che venga scelto un valore adatto, in grado di semplificare il più possibile l’integrazione.

Passaggio 1: autenticazione dell’utente

Al momento di connettersi a Frame.io in LaTuaApp™, occorre andare alla sezione di configurazione Frame.io e selezionare “Connetti al progetto” (o qualcosa di simile). Quando si fa clic sul pulsante, l’utente viene reindirizzato a Frame.io per accedere e autorizzare l’app.

Per farlo, viene creato un URL che viene aperto in un browser web. Diamo un’occhiata allo pseudocodice simile a Python:

Python
1def redirect_to_auth(config):
2 credentials = {
3 "response_type": "code",
4 "redirect_uri": "http://MyApp.io/frameio-callback",
5 "client_id": f"{MYAPP.client_id}",
6 "scope": "offline device.connect asset.create",
7 "state": str(uuid.uuid4()),
8 "device_id": f"{HARDWARE.get_vendor_id('com.mycompany.myapp')}",
9 }
10
11 encoded = parse.urlencode(credentials)
12 url = "https://applications.frame.io/oauth2/auth?" + encoded
13
14 webbrowser.open(url)

Il nostro “payload” è codificato nell’URL stesso e, se è codificato completamente, l’URL avrà un aspetto simile a questo:

https://applications.frame.io/oauth2/auth?response_type=code&redirect_uri=http%3A%2F%2FMyApp.io%2Fframeio-callback&client_id=[client_id]&scope=offline+device.connect+asset.create&state=[state]&device_id=62f88d2a-1ae1-45e7-a6a0-81954e0cf2ff

Analizziamo queste opzioni:

response_type: il tipo di risposta del flusso Oauth. Questo valore deve essere sempre “code”. Indica al server Oauth di inviare un codice all’URI di reindirizzamento, che verrà quindi usato per recuperare i token di autorizzazione effettivi. redirect_uri: URL/URI in cui il server Oauth deve eseguire una richiesta GET quando risponde a una richiesta di autenticazione. client_id: identifica la tua applicazione. Per le integrazioni delle applicazioni, questo valore verrà fornito da Frame.io. scope: elenco di autorizzazioni delimitate da spazi che l’applicazione sta richiedendo. Per le applicazioni C2C sono disponibili le seguenti autorizzazioni

  • offline: l’app può aggiornare la propria autorizzazione quando il token iniziale scade.
  • device.connect: il dispositivo può ottenere un elenco di account e progetti disponibili per le connessioni C2C dall’utente.
  • asset.create: l’app può caricare risorse nei progetti a cui è connessa.

Anche se è possibile richiedere e ottenere un sottoinsieme di questi ambiti, conviene sempre richiederli tutti e tre.

state: valore casuale associato a questa richiesta. state viene utilizzato per verificare che le chiamate all’URI di reindirizzamento siano per richieste valide. Quando ricevi una callback sull’URI registrato, devi verificare che lo stato (state) sia quello previsto.

Il valore di “state” deve essere casuale. Se il parametro “state” non è casuale, ti esponi agli attacchi CRSF, in cui un malintenzionato falsifica il parametro “state” e invia una richiesta dannosa al callback. Puoi leggere di più sul parametro state in questo blog di Auth0

device_id: identificatore univoco per il dispositivo o l’installazione. L’ID dispositivo deve essere un valore di tua proprietà (quindi non un indirizzo MAC o un numero di serie di CPU ecc.) e non deve contenere informazioni personalmente identificabili (quindi nessun indirizzo e-mail, codice fiscale, hash di impronte digitali ecc.). Consulta la sezione precedente sul device_id per maggiori informazioni.

Passaggio 2: ricezione della risposta OAuth

Dopo che l’utente ha effettuato l’accesso a Frame.io e ha accettato gli ambiti richiesti nel browser, viene inviata una richiesta GET al tuo URI di callback. La richiesta contiene un payload codificato con URL che ha i seguenti parametri di richiesta. code: un codice che verrà usato per recuperare i token di autorizzazione effettivi dal backend di Frame.io. state: il valore dello stato incluso nella richiesta di autenticazione originale nel passaggio 1. scope: le autorizzazioni e gli ambiti concessi.

L’URI completo avrà un aspetto simile a questo:

https://MyApp.io/frameio-callback?code=[authorization_code]&scope=offline+device.connect+asset.create&state=[state]

L’analisi degli URI può essere complessa e la libreria HTTP/server probabilmente dispone di buone risorse per farlo, quindi dai un’occhiata prima di decidere di provare ad analizzare questo valore in modo indipendente!

Per il test, possiamo configurare rapidamente un server per osservare la richiesta GET usando Python. L’URI di callback deve essere configurato come http://localhost:8888/callback

$$ python -m http.server 8888

Ora possiamo utilizzare il seguente modello per richiedere l’accesso a Frame.io. Inserisci il tuo [client_id] e un valore per [state]. Puoi generare un UUID casuale qui per state.

https://applications.frame.io/oauth2/auth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A8888%2Fcallback&client_id=[client_id]&scope=offline+device.connect+asset.create&state=[state]&device_id=62f88d2a-1ae1-45e7-a6a0-81954e0cf2ff

Quando passiamo attraverso il flusso di autenticazione, otteniamo un errore 404. Questo accade perché Python non riconosce la risorsa richiesta e non sa come rispondere. Ma non preoccuparti, la richiesta di autenticazione è comunque riuscita! Dovremmo vedere che il server stampa qualcosa del genere nel terminale:

Serving HTTP on :: port 8888 (http://[::]:8888/) ...
::1 - - [08/Mar/2022 14:04:34] code 404, message File not found
::1 - - [08/Mar/2022 14:04:34] "GET /callback?code=[authentication_code]&scope=offline+device.connect+asset.create&state=[state] HTTP/1.1" 404 -

Dobbiamo verificare che lo stato sia lo stesso che abbiamo inviato. Il valore di . authentication_code sarà importante nel passaggio successivo per recuperare i token di accesso.

In un’app reale, un gestore di callback potrebbe apparire così:

Python
1@handler("/frameio-callback")
2def do_get(request):
3 params = url.parse_query(request.url.parts.query)
4 if "error" in params:
5 raise AuthError(params["error"])
6
7 # Handles sending the authentication code and state to the proper user
8 MyApp.frameio_oauth_success(state=params["state"], code=params["code"])
9
10 # Render some sort of confirmation page for the user.
11 request.send_response(
12 code=200,
13 headers={"Content-type": "text/html"},
14 data=OauthSuccessPage()
15 )

Passaggio 3: recupero dei token di accesso

Ora che abbiamo l’authorization_code, possiamo recuperare il token di accesso! A questo punto, il token di accesso è già stato concesso, dobbiamo solo richiederlo al backend.

Facciamo la seguente richiesta:

$curl -X POST https://applications.frame.io/oauth2/token \
> --form 'client_id=[client_id]' \
> --form 'state=[state]' \
> --form 'code=[authorization_code]' \
> --form 'redirect_uri=http://localhost:8888/callback' \
> --form 'grant_type=authorization_code' \
> --form 'scope=offline device.connect asset.create' \
> | python -m json.tool
Endpoint OAuth

L’host per questa richiesta è applications.frame.io, anziché api.frame.io, che usiamo per la maggior parte delle richieste. Tieni presente che stiamo utilizzando dati del modulo, invece di dati JSON. Gli endpoint di OAuth C2C accettano solo dati di modulo.

Una volta autenticato, altri endpoint accettano il payload application/json, ma gli endpoint di autenticazione restituiscono un errore se invii JSON anziché dati application/x-www-form-urlencoded.

Esaminiamo questi parametri:

client_id: l’identificatore dell’app Oauth che è stato rilasciato da Frame.io state: il valore di stato che abbiamo incluso nella nostra richiesta di autorizzazione originale al browser e ricevuto nel callback. code: il codice di autorizzazione ricevuto nel callback redirect_uri: lo stesso URI di reindirizzamento registrato con il backend di Frame.io. Se questo valore non è nell’elenco degli URL separati da virgole che Frame.io ha registrato per l’integrazione, questa richiesta non riuscirà. grant type: per il flusso di autorizzazione del dispositivo software, sarà sempre authorization_code. scope: deve corrispondere agli ambiti approvati restituiti nel callback.

Dovremmo ricevere una risposta simile a questa:

1{
2 "access_token": "[access_token]",
3 "expires_in": 3599,
4 "refresh_token": "[refresh_token]",
5 "scope": "offline device.connect asset.create",
6 "token_type": "bearer"
7}

Il dispositivo è ora autorizzato in Frame.io! Tieni a portata di mano questi valori perché serviranno per eseguire il resto delle richieste. Vediamo cosa c’è nel payload:

access_token: questa è la tua chiave per il resto del backend Frame.io.Dovrà essere aggiunto all’intestazione delle altre richieste che faremo in queste esercitazioni.expires_in: il numero di secondi fino alla scadenza di access_token.Una volta scaduto il token, dovrà essere aggiornato. Tratteremo questo argomento in un’esercitazione futura.refresh_token: un token che possiamo utilizzare per gestire il nostro access_token.Verrà utilizzato principalmente per aggiornare l’autorizzazione, ma può anche essere utilizzato per revocarla.token_type: sarà sempre bearer per l’API C2C e non è operativo.

Ci sono ancora alcuni passaggi prima di stabilire effettivamente la connessione a un progetto, perciò continuiamo!

Passaggio 4: elenca gli account

Ora dobbiamo ottenere un elenco degli account a cui l’utente può connettersi. Questa è la prima chiamata che richiede il token di accesso e lo aggiungeremo a un’intestazione:

$curl -X GET https://api.frame.io/v2/devices/accounts \
> --header "x-client-version: 2.0.0" \
> --header "Authorization: Bearer [access_token]" \
> | python -m json.tool
Specifica dell'endpoint API

La documentazione per /v2/devices/accounts è disponibile qui

L'intestazione Authorization

Per ogni endpoint che richiede l’autorizzazione, dobbiamo aggiungere access_token all’intestazione Authorization. Tieni presente che dobbiamo anteporre Bearer (con uno spazio!) al nostro token di accesso come valore.

Questa chiamata dovrebbe restituire un elenco di account a cui l’utente può connettersi:

1[
2 {
3 "_type": "account",
4 "display_name": "Hogwarts General",
5 "id": "46b7ea11-3041-4e2b-97f7-98fbf5c974c9"
6 },
7 {
8 "_type": "account",
9 "display_name": "Gryffindor",
10 "id": "e6007a3d-cad7-4666-9ee3-23c1af032060"
11 },
12 {
13 "_type": "account",
14 "display_name": "QUIDDITCH LEGENDS -- LETS GOOOOOOOOOO",
15 "id": "cc94119d-f957-4d6e-b8cf-0c095211b1b9"
16 }
17]

A questo punto, mostri questo elenco all’utente e gli fai selezionare l’account a cui desidera connettersi. Utilizziamo l’id dell’account nel passaggio successivo per elencare i progetti ai quali l’utente può connettere un dispositivo C2C.

Passaggio 5: elenca i progetti

Ora dobbiamo ottenere un elenco di progetti per l’account che ci interessa:

$curl -X GET https://api.frame.io/v2/devices/accounts/[account_id]/projects \
> --header "x-client-version: 2.0.0" \
> --header "Authorization: Bearer [access_token]" \
> | python -m json.tool
Specifica dell'endpoint API

La documentazione per /v2/devices/accounts/[account_id]/projects è disponibile qui

Dobbiamo aggiungere l’account_id per cui stiamo cercando di elencare i progetti all’URL. Inoltre, nota che il percorso complessivo della risorsa inizia con /devices/.... Qui non stiamo solo elencando progetti, ma stiamo elencando i progetti per i quali l’utente ha autorizzazioni di gestione dei dispositivi C2C. Se un progetto a cui appartiene l’utente non è elencato, significa che non ha autorizzazioni di gestione dispositivi C2C per quel progetto.

Otterremo una risposta simile a quella per gli account:

1[
2 {
3 "_type": "project",
4 "id": "921480ec-1225-424a-9447-19c61a3a1ef2",
5 "name": "Match Recordings"
6 },
7 {
8 "_type": "project",
9 "id": "ed5dbf4a-f146-416b-add0-74de98201876",
10 "name": "Year Book Material"
11 }
12]

Proprio come per gli account, questo elenco dovrebbe essere mostrato all’utente in modo che selezioni il progetto a cui desidera connettersi. Proprio come per gli account, avremo bisogno dell’id del progetto per il passaggio successivo.

Passaggio 6: connessione a un progetto

Ora che l’utente ha selezionato il progetto a cui desidera connettersi, è tutto pronto! C’è solo un ultimo passaggio per completare l’associazione del nostro dispositivo software a un progetto Frame.io:

$curl -X POST https://api.frame.io/v2/devices/connect?project_id={project_id} \
> --header "x-client-version: 2.0.0" \
> --header "Authorization: Bearer [access_token]" \
> | python -m json.tool
Specifica dell'endpoint API

La documentazione per /v2/devices/connect è disponibile qui

L’ID del progetto è un parametro di query dell’URL e dobbiamo ancora passare la nostra intestazione di autorizzazione!

Otteniamo una risposta come questa (alcuni dati sono stati omessi per brevità):

1{
2 "_type": "project_device",
3 "asset_type": "video",
4 "authorization": {
5 "_type": "project_device_authorization",
6 "creator": {
7 "_type": "user",
8 "account_id": "93f872fb-9924-4e31-a430-2574e0742260",
9 "deleted_at": null,
10 "email": "hpotter@hoggyhoggyhogwarts.edu",
11 "id": "d473b5e1-08d2-4842-82ac-a6b01233dc2c",
12 ...
13 "name": "Harry Potter",
14 ...
15 },
16 "creator_id": "d473b5e1-08d2-4842-82ac-a6b01233dc2c",
17 "expires_at": null,
18 "id": "ee9f5949-b7fa-4c71-8480-6d4c60877c51",
19 "inserted_at": "2022-03-09T18:14:21.893283Z",
20 "project_device_id": "6a55d7f6-dfb7-46a1-bff8-a3acb2d3d1aa",
21 "scopes": {
22 ...
23 "asset_create": true,
24 ...
25 "id": "1e174fe9-5b53-48db-b556-c310c0848898",
26 "offline": true,
27 ...
28 }
29 },
30 "channels": [
31 {
32 "_type": "project_device_channel",
33 "asset_type": "video",
34 ...
35 }
36 ],
37 "creator_id": "d473b5e1-08d2-4842-82ac-a6b01233dc2c",
38 "deleted_at": null,
39 "device_id": "a8a4f3bf-196c-4748-832b-28f1d0801515",
40 "id": "93af90e7-ee89-4b47-86e6-c2750f3790b6",
41 ...
42 "name": "MyApp-62f88d2a-1ae1-45e7-a6a0-81954e0cf2ff",
43 "project": {
44 "_type": "project",
45 "id": "921480ec-1225-424a-9447-19c61a3a1ef2",
46 "name": "Testbed"
47 },
48 "project_id": "921480ec-1225-424a-9447-19c61a3a1ef2",
49 "status": "online",
50 ...
51}
Un progetto alla volta

Puoi associare un dispositivo a un solo progetto alla volta ed eseguire un’altra operazione di associazione a un progetto diverso ne rimuoverà la connessione con quello precedentemente connesso.

Se il payload della risposta è simile a questo,Ce l’hai fatta! Hai autorizzato il tuo primo dispositivo Camera to Cloud.È il momento di festeggiare!

Quando hai finito di festeggiare, dovresti mostrare il nome del progetto all’utente per verificare il progetto a cui si è connesso.

Utilizzo di una libreria OAuth di terze parti

Frame.io utilizza il flusso Oauth2.0 standard. Per motivi di sicurezza, applichiamo PKCE. Esistono molte librerie per gestire questa parte dell’integrazione al posto tuo.

Ecco alcune librerie Oauth popolari:

Linguaggio di programmazioneNomeURL
SwiftOAuthSwiftGithub
Pythonrequests-oauthlibGithub
Flutteroauth2_clientGithub
Ricorda che Frame.io aggiunge un campo device_id per identificare un particolare dispositivo. Si tratta di un campo personalizzato aggiuntivo. La libreria che scegli di utilizzare avrà molto probabilmente il supporto per i campi personalizzati, ma assicurati di aggiungerlo!

Risoluzione dei problemi

Se sei qui, allora qualcosa è andato storto!Cosa sarebbe l’integrazione con una terza parte senza qualche tipo di errore?Questa sezione elenca una serie di problemi comuni e ti guida attraverso i passaggi più probabili per risolverli.Dai un’occhiata all’elenco in basso e verifica se qualcosa corrisponde al tuo problema. Anche la guida agli errori è un’ottima risorsa per cercare gli errori dell’API.

Se non trovi una soluzione qui, ci farebbe molto piacere conoscere il problema che hai riscontrato per poterlo aggiungere qui!

L’account o il progetto a cui voglio connettermi non è stato restituito: se stai elencando account e/o progetti e quello a cui vuoi connetterti non è presente nell’elenco, potrebbero essersi verificate una paio di cose. In Frame.io, vai al progetto a cui vuoi connetterti e dai clic sulla scheda Connessioni C2C.Ciò è utile per capire cosa non va.

  • C2C non è abilitato per il tuo account: se la schermata è vuota e compare un messaggio che dice che C2C non è disponibile per il tuo account, il gestore dell’account deve attivarlo per il tuo progetto nelle impostazioni dell’account.
  • Non sei un gestore del dispositivo: se la schermata è vuota e compare un messaggio che dice che non hai le autorizzazioni, il gestore dell’account deve cambiare le autorizzazioni per stabilire chi può connettere i dispositivi C2C oppure aggiungerti a un ruolo che ha quelle autorizzazioni.

Errore di client non valido: viene restituito invalid_client quando le informazioni che ci stai fornendo sul dispositivo non corrispondono a quelle registrate. Molto probabilmente significa che il tuo client_secret, client_id o redirect_uri non corrispondono a quanto registrato da Frame.io negli archivi backend. Errore di richiesta non valida: viene restituito bad_request quando i dati della richiesta sono in un formato errato. Controlla di non aver scritto male il nome di un campo o di non aver dimenticato di aggiungere un campo obbligatorio.

Avanti

Se non l’hai già fatto, ti incoraggiamo a contattare il nostro team, poi continua con la prossima guida.A presto!