omerdn1 / otter.ai-api

Unofficial API for Otter.ai
MIT License
38 stars 7 forks source link

Getting 401 unauthorized when trying to getSpeaches #7

Closed Stvad closed 3 years ago

Stvad commented 3 years ago

I've been trying to use the basic example from the readme, and getting an Unauthorized error :(

 Alfred/alfred-otter   master ●✚  node ottetest.mjs
(node:57037) ExperimentalWarning: The ESM module loader is experimental.
[Function: OtterApi]
Error: Request failed with status code 401
    at createError (/Users/sitalov/Dropbox/SoftwareEngineering/Projects/Alfred/otter.ai-api/node_modules/axios/lib/core/createError.js:16:15)
    at settle (/Users/sitalov/Dropbox/SoftwareEngineering/Projects/Alfred/otter.ai-api/node_modules/axios/lib/core/settle.js:17:12)
    at IncomingMessage.handleStreamEnd (/Users/sitalov/Dropbox/SoftwareEngineering/Projects/Alfred/otter.ai-api/node_modules/axios/lib/adapters/http.js:237:11)
    at IncomingMessage.emit (events.js:333:22)
    at endReadableNT (_stream_readable.js:1220:12)
    at processTicksAndRejections (internal/process/task_queues.js:84:21) {
  config: {
    url: 'https://otter.ai/forward/api/v1/speeches',
    method: 'get',
    params: { userid: undefined },
    headers: {
      Accept: 'application/json, text/plain, */*',
      'User-Agent': 'axios/0.19.0'
    },
    transformRequest: [ [Function: transformRequest] ],
    transformResponse: [ [Function: transformResponse] ],
    timeout: 0,
    adapter: [Function: httpAdapter],
    xsrfCookieName: 'XSRF-TOKEN',
    xsrfHeaderName: 'X-XSRF-TOKEN',
    maxContentLength: -1,
    validateStatus: [Function: validateStatus],
    data: undefined
  },
  request: <ref *1> ClientRequest {
    _events: [Object: null prototype] {
      socket: [Function (anonymous)],
      abort: [Function (anonymous)],
      aborted: [Function (anonymous)],
      error: [Function (anonymous)],
      timeout: [Function (anonymous)],
      prefinish: [Function: requestOnPrefinish]
    },
    _eventsCount: 6,
    _maxListeners: undefined,
    outputData: [],
    outputSize: 0,
    writable: true,
    _last: true,
    chunkedEncoding: false,
    shouldKeepAlive: false,
    useChunkedEncodingByDefault: false,
    sendDate: false,
    _removedConnection: false,
    _removedContLen: false,
    _removedTE: false,
    _contentLength: 0,
    _hasBody: true,
    _trailer: '',
    finished: true,
    _headerSent: true,
    socket: TLSSocket {
      _tlsOptions: [Object],
      _secureEstablished: true,
      _securePending: false,
      _newSessionPending: false,
      _controlReleased: true,
      _SNICallback: null,
      servername: 'otter.ai',
      alpnProtocol: false,
      authorized: true,
      authorizationError: null,
      encrypted: true,
      _events: [Object: null prototype],
      _eventsCount: 9,
      connecting: false,
      _hadError: false,
      _parent: null,
      _host: 'otter.ai',
      _readableState: [ReadableState],
      readable: true,
      _maxListeners: undefined,
      _writableState: [WritableState],
      writable: false,
      allowHalfOpen: false,
      _sockname: null,
      _pendingData: null,
      _pendingEncoding: '',
      server: undefined,
      _server: null,
      ssl: [TLSWrap],
      _requestCert: true,
      _rejectUnauthorized: true,
      parser: null,
      _httpMessage: [Circular *1],
      [Symbol(res)]: [TLSWrap],
      [Symbol(asyncId)]: 19,
      [Symbol(kHandle)]: [TLSWrap],
      [Symbol(lastWriteQueueSize)]: 0,
      [Symbol(timeout)]: null,
      [Symbol(kBuffer)]: null,
      [Symbol(kBufferCb)]: null,
      [Symbol(kBufferGen)]: null,
      [Symbol(kCapture)]: false,
      [Symbol(kBytesRead)]: 0,
      [Symbol(kBytesWritten)]: 0,
      [Symbol(connect-options)]: [Object]
    },
    _header: 'GET /forward/api/v1/speeches HTTP/1.1\r\n' +
      'Accept: application/json, text/plain, */*\r\n' +
      'User-Agent: axios/0.19.0\r\n' +
      'Host: otter.ai\r\n' +
      'Connection: close\r\n' +
      '\r\n',
    _onPendingData: [Function: noopPendingOutput],
    agent: Agent {
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      defaultPort: 443,
      protocol: 'https:',
      options: [Object],
      requests: {},
      sockets: [Object],
      freeSockets: {},
      keepAliveMsecs: 1000,
      keepAlive: false,
      maxSockets: Infinity,
      maxFreeSockets: 256,
      maxCachedSessions: 100,
      _sessionCache: [Object],
      [Symbol(kCapture)]: false
    },
    socketPath: undefined,
    method: 'GET',
    maxHeaderSize: undefined,
    path: '/forward/api/v1/speeches',
    _ended: true,
    res: IncomingMessage {
      _readableState: [ReadableState],
      readable: false,
      _events: [Object: null prototype],
      _eventsCount: 3,
      _maxListeners: undefined,
      socket: [TLSSocket],
      httpVersionMajor: 1,
      httpVersionMinor: 1,
      httpVersion: '1.1',
      complete: true,
      headers: [Object],
      rawHeaders: [Array],
      trailers: {},
      rawTrailers: [],
      aborted: false,
      upgrade: false,
      url: '',
      method: null,
      statusCode: 401,
      statusMessage: 'Unauthorized',
      client: [TLSSocket],
      _consuming: false,
      _dumped: false,
      req: [Circular *1],
      responseUrl: 'https://otter.ai/forward/api/v1/speeches',
      redirects: [],
      [Symbol(kCapture)]: false
    },
    aborted: false,
    timeoutCb: null,
    upgradeOrConnect: false,
    parser: null,
    maxHeadersCount: null,
    reusedSocket: false,
    _redirectable: Writable {
      _writableState: [WritableState],
      writable: true,
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      _options: [Object],
      _redirectCount: 0,
      _redirects: [],
      _requestBodyLength: 0,
      _requestBodyBuffers: [],
      _onNativeResponse: [Function (anonymous)],
      _currentRequest: [Circular *1],
      _currentUrl: 'https://otter.ai/forward/api/v1/speeches',
      [Symbol(kCapture)]: false
    },
    [Symbol(kCapture)]: false,
    [Symbol(kNeedDrain)]: false,
    [Symbol(corked)]: 0,
    [Symbol(kOutHeaders)]: [Object: null prototype] {
      accept: [Array],
      'user-agent': [Array],
      host: [Array]
    }
  },
  response: {
    status: 401,
    statusText: 'Unauthorized',
    headers: {
      date: 'Fri, 25 Dec 2020 23:40:41 GMT',
      'content-type': 'application/json',
      'content-length': '58',
      connection: 'close',
      server: 'nginx/1.16.1',
      vary: 'Cookie',
      'x-frame-options': 'SAMEORIGIN'
    },
    config: {
      url: 'https://otter.ai/forward/api/v1/speeches',
      method: 'get',
      params: [Object],
      headers: [Object],
      transformRequest: [Array],
      transformResponse: [Array],
      timeout: 0,
      adapter: [Function: httpAdapter],
      xsrfCookieName: 'XSRF-TOKEN',
      xsrfHeaderName: 'X-XSRF-TOKEN',
      maxContentLength: -1,
      validateStatus: [Function: validateStatus],
      data: undefined
    },
    request: <ref *1> ClientRequest {
      _events: [Object: null prototype],
      _eventsCount: 6,
      _maxListeners: undefined,
      outputData: [],
      outputSize: 0,
      writable: true,
      _last: true,
      chunkedEncoding: false,
      shouldKeepAlive: false,
      useChunkedEncodingByDefault: false,
      sendDate: false,
      _removedConnection: false,
      _removedContLen: false,
      _removedTE: false,
      _contentLength: 0,
      _hasBody: true,
      _trailer: '',
      finished: true,
      _headerSent: true,
      socket: [TLSSocket],
      _header: 'GET /forward/api/v1/speeches HTTP/1.1\r\n' +
        'Accept: application/json, text/plain, */*\r\n' +
        'User-Agent: axios/0.19.0\r\n' +
        'Host: otter.ai\r\n' +
        'Connection: close\r\n' +
        '\r\n',
      _onPendingData: [Function: noopPendingOutput],
      agent: [Agent],
      socketPath: undefined,
      method: 'GET',
      maxHeaderSize: undefined,
      path: '/forward/api/v1/speeches',
      _ended: true,
      res: [IncomingMessage],
      aborted: false,
      timeoutCb: null,
      upgradeOrConnect: false,
      parser: null,
      maxHeadersCount: null,
      reusedSocket: false,
      _redirectable: [Writable],
      [Symbol(kCapture)]: false,
      [Symbol(kNeedDrain)]: false,
      [Symbol(corked)]: 0,
      [Symbol(kOutHeaders)]: [Object: null prototype]
    },
    data: { status: 'Error', message: 'Not logged in', code: 1 }
  },
  isAxiosError: true,
  toJSON: [Function (anonymous)]
}
Successfuly logged in to Otter.ai

looking at the code it seems login is happening async, so if I just try to create client and use it breaks.. let me play with that

Stvad commented 3 years ago

yep, explicitly awaiting on the login helped

omerdn1 commented 3 years ago

@Stvad oh yes, the API methods are async methods. happy you were able to sort it out. I'll update the examples and will redeploy the package to npm.

Stvad commented 3 years ago

@omerdn1 the fact that the api methods are async is not the issue. it's that the login that is called from the constructor is. and api's don't await on login completing. so if you just create a client and try to call an api - you get unauthorized.
So in my fork I made login public and explicitly await it before using the client - https://github.com/Stvad/otter.ai-api/commit/83b3e1c17088394d4d4b1ac185f5de569ca173b7

omerdn1 commented 3 years ago

@Stvad Fixed in https://github.com/omerdn1/otter.ai-api/commit/6feeb79e59c528f86ede4621d47f4b35eec081a4

Thanks again for bringing this to my attention.

Stvad commented 3 years ago

Thank you, @omerdn1 !