Instruções: Autorizar (aplicativo)

Introdução

Neste guia, aprenderemos como autenticar e autorizar um aplicativo C2C em um projeto Frame.io.

O que vou precisar?

Se você ainda não leu o guia Implementação do C2C: Configuração, dê uma olhada rápida nele antes de continuar!Além disso, você deve ter recebido um client_id da nossa equipe que será usado para identificar sua integração.Se você não recebeu um client_id, consulte esta introdução ao ecossistema C2C e entre em contato com nossa equipe.Se você recebeu um client_secret em vez de um client_id, configuramos você como um dispositivo de hardware em vez de um aplicativo C2C, e você deve seguir o Guia de autenticação de dispositivo de hardware ou entrar em contato com nossa equipe para receber um client_id.

Como funciona o fluxo de autenticação do aplicativo

Vamos garantir que temos um entendimento de alto nível da experiência do usuário esperada para o fluxo de autorização que queremos implementar.Confira os seguintes recursos para ver este fluxo do ponto de vista do usuário, tente baixar o Zoelog e fazer login no Frame.io para ter uma noção do processo de autorização para aplicativos C2C!

Visão geral do OAuth

Aplicativos C2C usam um fluxo OAuth 2.0 para autenticação e autorização.Este é um conjunto padronizado de chamadas que pode ser usado para autenticar e autorizar um aplicativo ou usuário de terceiros para um serviço.Você pode ler mais sobre o fluxo OAuth aqui.

Os URIs de callback/redirecionamento

Como parte do fluxo OAuth, nossos servidores precisarão fazer uma chamada HTTP para um URI/URL que você controla.Depois que um usuário fizer login no Frame.io no navegador, redirecionaremos o navegador para este URI para fornecer ao seu aplicativo algumas informações.Seu URI de redirecionamento deve ser:

  • De sua propriedade
  • Estático

Você pode ter mais de um redirecionamento válido registrado para seu dispositivo, desde que atendam a esses dois critérios.

Durante o fluxo OAuth, verificaremos se o URI de callback que está sendo solicitado pelo aplicativo é um dos URIs que temos em arquivo.Se não for, o fluxo de autorização falhará.Se não fizéssemos essa verificação, um agente mal-intencionado poderia fornecer um redirecionamento para um endereço que ele controla.

Para fins de desenvolvimento, oferecemos suporte a callbacks não-HTTPS em http://localhost.

Identificação do dispositivo

Ao se conectar ao Camera to Cloud, cada instalação de aplicativo individual precisa se identificar exclusivamente, para que possamos listar as conexões de dispositivo no projeto de um usuário.

Para aplicativos C2C, chamamos isso de device_id do dispositivo.Ao configurar sua implementação, você deve pensar em como quer fazer isso.Algumas plataformas oferecem uma API para gerar um identificador específico de dispositivo+aplicativo para este caso de uso exato:

PLATAFORMAREFERÊNCIA
iOSidentifierForVendor
AndroidFID ou GUID
Cuidado para não vazar informações de identificação pessoal

O email do usuário, por exemplo, não é um valor válido para usar como um device_id.Da mesma forma, certifique-se de que você possui o identificador exclusivo.Não use o endereço MAC do dispositivo, por exemplo.O endereço MAC não pertence ao seu software e também pode ser considerado informação de identificação pessoal.

Se você não tiver certeza de qual valor gostaria de usar, podemos discutir essa escolha juntos e garantir que seja escolhido um valor adequado, que torne a integração o mais fácil possível.

Etapa 1: autenticação do usuário

Quando decido que quero me conectar ao Frame.io no YourApp™, vou para a seção de configurações do Frame.io e seleciono “Conectar ao projeto” (ou algo similar).Quando clico no botão, sou redirecionado para o Frame.io para fazer login e autorizar seu aplicativo.

Fazemos isso criando um URL e abrindo-o em um navegador da web.Vamos ver um pseudocódigo similar ao 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)

Nosso “conteúdo” é codificado no próprio url, e quando totalmente codificado, o url ficará assim:

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

Vamos detalhar essas opções um pouco:

response_type: o que o fluxo OAuth deve responder.Este valor deve sempre ser “code”.Isso informa ao nosso servidor OAuth para enviar um código de volta para o URI de redirecionamento, que será usado para buscar os tokens de autorização reais.redirect_uri: o URL/URI para onde o servidor OAuth deve fazer GET ao responder a uma solicitação de autenticação.client_id: identifica seu aplicativo.Para integrações de aplicativo, este valor será fornecido pelo Frame.io.scope: uma lista de permissões delimitadas por espaço que seu aplicativo está solicitando.As seguintes permissões estão disponíveis para aplicativos C2C

  • offline: o aplicativo pode atualizar sua própria autorização quando o token inicial expira.
  • device.connect: o dispositivo pode obter uma lista de contas e projetos que estão disponíveis para conexões C2C pelo usuário.
  • asset.create: o aplicativo pode fazer upload de ativos para projetos aos quais está conectado.

Embora seja possível solicitar e receber um subconjunto desses escopos, você sempre vai querer solicitar os três.

state: um valor aleatório associado a esta solicitação.Usamos state para verificar se as chamadas para nosso URI de redirecionamento são para solicitações válidas.Quando receber um callback no URI registrado, você deve validar se o state é esperado.

state deve ser aleatório”> Se o parâmetro state não for aleatório, você se expõe a ataques CRSF, onde um agente mal-intencionado falsifica seu parâmetro state e faz uma solicitação inadequada para seu callback.Você pode ler mais sobre o parâmetro state neste blog da Auth0

device_id: um identificador exclusivo para este dispositivo/instalação específica.O ID do dispositivo deve ser um valor de sua propriedade (portanto, não endereço MAC/número de série da CPU, etc), e não deve conter informações de identificação pessoal (portanto, nenhum endereço de email, códigos de segurança social, hashes de impressão digital, etc).Consulte a seção acima sobre device_id para mais informações.

Etapa 2: recebimento da resposta OAuth

Depois que o usuário fez login no Frame.io e aceitou os escopos solicitados no navegador, uma solicitação GET é feita para seu URI de callback.A solicitação contém um conteúdo codificado por URL com os seguintes parâmetros de consulta: code: um código que será usado para buscar os tokens de autorização reais do back-end do Frame.io.state: o valor de estado que foi incluído na solicitação de autenticação original na etapa 1.scope: os escopos/permissões concedidos.

O URI completo ficará assim:

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

Analisar URIs pode ser complicado, e sua biblioteca HTTP/servidor provavelmente tem bons recursos para fazer isso, então dê uma olhada antes de decidir tentar analisar esse valor você mesmo!

Para teste, podemos configurar rapidamente um servidor para observar a solicitação GET usando Python.Seu URI de callback precisa ser configurado como http://localhost:8888/callback

$$ python -m http.server 8888

Agora podemos usar o seguinte modelo para solicitar acesso ao Frame.io.Preencha seu [client_id] e um valor [state].Você pode gerar um UUID aleatório aqui para 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

Ao passar pelo fluxo de autenticação, receberemos um erro 404.Isso acontece porque o Python não reconhece o recurso solicitado e não sabe como responder a ele.Mas não se preocupe, a solicitação de autenticação ainda foi bem-sucedida!Devemos ver nosso servidor imprimir algo assim em nosso terminal:

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 -

Devemos verificar se o estado é o mesmo que enviamos, e o authentication_code será importante na próxima etapa para recuperar nossos tokens de acesso.

Em um aplicativo real, um manipulador de callback pode ser algo assim:

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 )

Etapa 3: recuperar nossos tokens de acesso

Agora que temos nosso authorization_code, podemos recuperar nosso token de acesso!Neste momento, nosso token de acesso já foi concedido. Só precisamos solicitá-lo ao back-end.

Vamos fazer a seguinte solicitação:

$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
Pontos de acesso OAuth

Note que o host para esta solicitação é applications.frame.io, ao contrário de api.frame.io, que usamos para a maioria das solicitações.Note também que estamos usando dados de formulário aqui em vez de dados JSON.Os pontos de acesso OAuth C2C só aceitam dados de formulário.

Depois de autenticado, outros pontos de acesso aceitarão conteúdo application/json, mas os pontos de acesso de autenticação retornarão um erro se você enviar JSON em vez de dados application/x-www-form-urlencoded.

Vamos analisar esses parâmetros:

client_id: o identificador do aplicativo OAuth que foi emitido pelo Frame.io state: o valor de estado que incluímos em nossa solicitação de autorização original para o navegador e recebemos no callback.code: o código de autorização que recebemos no callback redirect_uri: o mesmo URI de redirecionamento que registramos no back-end do Frame.io.Se este valor não estiver na lista de URLs separados por vírgulas que o Frame.io tem registrado para sua integração, esta solicitação falhará.grant type: para o fluxo de autorização de dispositivo de software, sempre será authorization_code.scope: deve corresponder aos escopos aprovados retornados no callback.

Devemos receber uma resposta que se pareça com isto:

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}

Nosso dispositivo agora está autorizado com sucesso no Frame.io!Mantenha estes valores à mão, pois precisaremos deles para fazer o restante de nossas solicitações.Vamos dar uma olhada no que está no conteúdo:

access_token: esta é sua chave para o restante do back-end do Frame.io.Precisaremos adicionar isto ao cabeçalho do restante das solicitações que faremos nestes tutoriais.expires_in: o número de segundos até o access_token expirar.Após o tempo limite do token acabar, ele precisará ser atualizado, o que abordaremos em um tutorial futuro.refresh_token: um token que podemos usar para gerenciar nosso access_token.Será usado mais comumente para atualizar nossa autorização, mas também pode ser usado para revogá-la.token_type: sempre será bearer para a API C2C e não é acionável.

Ainda temos algumas etapas até estarmos realmente conectados a um projeto, então com isso em mente, vamos continuar!

Passo 4: listar contas

Em seguida, precisamos obter uma lista das contas às quais nosso usuário está autorizado a se conectar.Esta é a primeira chamada que requer nosso token de acesso, e vamos adicioná-lo a um cabeçalho:

$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
Especificação do ponto de acesso da API

A documentação para /v2/devices/accounts pode ser encontrada aqui

O cabeçalho de autorização

Para cada ponto de acesso que requer autorização, precisamos adicionar o access_token ao cabeçalho Authorization.Observe que precisamos adicionar Bearer (com um espaço!)ao nosso token de acesso como o valor.

Esta chamada deve retornar uma lista de contas que o usuário pode conectar:

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]

Neste momento, você mostraria esta lista para o usuário e faria com que ele selecione a conta que deseja conectar.Em seguida, usaremos o id da conta na próxima etapa para listar os projetos para os quais o usuário pode conectar um dispositivo C2C.

Etapa 5: listar projetos

Agora precisamos obter uma lista de projetos para a conta na qual temos interesse:

$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
Especificação do ponto de acesso da API

A documentação para /v2/devices/accounts/[account_id]/projects pode ser encontrada aqui

Precisamos adicionar o account_id para o qual estamos tentando listar projetos ao URL.Além disso, observe que o caminho geral do recurso começa com /devices/.... Não estamos apenas listando projetos aqui, estamos listando projetos para os quais o usuário tem permissões de gerenciamento de dispositivo C2C.Se um projeto ao qual o usuário pertence não estiver listado, isso significa que ele não tem permissões de gerenciamento de dispositivo C2C para esse projeto.

Obteremos uma resposta semelhante à das contas:

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]

Assim como com as contas, esta lista deve ser exibida ao usuário para que ele selecione o projeto que deseja conectar e, assim como as contas, precisaremos do id do projeto para a próxima etapa.

Etapa 6: conectar-se a um projeto

Agora que o usuário selecionou o projeto ao qual deseja se conectar, estamos prontos para começar!Há apenas uma última etapa para finalizar o emparelhamento do nosso dispositivo de software a um projeto do 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
Especificação do ponto de acesso da API

A documentação para /v2/devices/connect pode ser encontrada aqui

O id do projeto é um parâmetro de consulta do URL, e ainda precisamos passar nosso cabeçalho de autorização!

Recebemos uma resposta como esta (alguns dados omitidos para maior brevidade):

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}
Um projeto por vez

Você só pode emparelhar um dispositivo com um projeto por vez e executar outra operação de emparelhamento com um projeto diferente removerá sua conexão com o projeto conectado anteriormente.

Se seu conteúdo de resposta for assim: Uhu!Você conseguiu!Você autorizou seu primeiro dispositivo Camera to Cloud.Aproveite para comemorar!

Quando terminar de comemorar, você deve exibir o nome do projeto para o usuário verificar o projeto ao qual se conectou.

Usar uma biblioteca OAuth de terceiros

O Frame.io usa o fluxo OAuth2.0 padrão.Por segurança, aplicamos o PKCE.Há várias bibliotecas disponíveis para gerenciar essa parte de uma integração.

Aqui estão algumas bibliotecas OAuth populares:

Linguagem de programaçãoNomeURL
SwiftOAuthSwiftGithub
Pythonrequests-oauthlibGithub
Flutteroauth2_clientGithub
Lembre-se de que o Frame.io adiciona um campo device_id para identificar um dispositivo específico.Este é um campo personalizado adicional.É muito provável que a biblioteca que você escolher ofereça suporte a campos personalizados, mas não se esqueça de adicioná-los!

Solução de problemas

Se você chegou até aqui, algo deu errado!O que seria uma integração com terceiros sem algum tipo de erro?Esta seção lista um conjunto de problemas comuns e orienta você nas etapas mais prováveis de resolvê-los.Veja a lista a seguir e verifique se algo corresponde ao seu problema.O guia de erros também é um ótimo recurso para pesquisar erros da API.

Se você não encontrar uma solução aqui, adoraríamos saber qual problema encontrou para que possamos adicioná-lo aqui!

A conta ou o projeto ao qual quero me conectar não foi retornado: se você estiver listando contas e/ou projetos e aquele ao qual deseja se conectar não estiver listado, então algumas coisas podem estar acontecendo.No Frame.io, acesse o projeto ao qual deseja se conectar e clique na guia C2C Connections.Isso ajudará você a descobrir o que está dando errado.

  • C2C não está habilitado para sua conta: se a tela estiver em branco e houver uma mensagem informando que o C2C não está disponível para a sua conta, o gerente de conta precisará habilitá-lo para o seu projeto nas configurações da conta!
  • Você não é um gerenciador de dispositivos: se a tela estiver em branco e houver uma mensagem informando que você não tem permissões, o gerente de contas precisará alterar as permissões para definir quem tem permissão para conectar dispositivos C2C ou adicioná-lo a uma função que possua essas permissões.

Erro de cliente inválido: invalid_client é retornado quando as informações que você nos fornece sobre o dispositivo não correspondem a nenhum registro que tenhamos em nossos arquivos.Isso provavelmente significa que seu client_secret, client_id, ou redirect_uri não correspondem aos dados que o Frame.io tem registrados em nosso back-end.Erro de solicitação inválida: bad_request é retornado quando os dados da solicitação apresentam algum tipo de formato incorreto.Verifique novamente se você não escreveu incorretamente um nome de campo ou esqueceu de adicionar um campo obrigatório.

Próximas etapas

Se ainda não o fez, recomendamos que entre em contato com nossa equipe e, em seguida, siga para o próximo guia.Estamos ansiosos para ter notícias suas!