# Connect, log in and keep the session

Location: [gRPC API](https://developer.m-files.com/APIs/gRPC-API/index.md) > [Guides](https://developer.m-files.com/APIs/gRPC-API/index.md#guides)

HTML version: https://developer.m-files.com/APIs/gRPC-API/guides/connect/

Do this once at the start of every program: check that the server answers and what it supports,
log in, and close the session when you are done. A long-running program also keeps its session
alive.

## Calls

| Step | Call | Session |
|---|---|---|
| Server version | [QueryVersion](https://developer.m-files.com/APIs/gRPC-API/Reference/MFiles.IRPCQueryVersion/QueryVersion/index.md) | not needed |
| Server features | [GetServerCapabilities](https://developer.m-files.com/APIs/gRPC-API/Reference/MFiles.IRPCLogin/GetServerCapabilities/index.md) | not needed |
| Log in to a vault | [LogIn](https://developer.m-files.com/APIs/gRPC-API/Reference/MFiles.IRPCLogin/LogIn/index.md) | creates one |
| Session and vault | [GetVaultSessionInfo](https://developer.m-files.com/APIs/gRPC-API/Reference/MFiles.IRPCLogin/GetVaultSessionInfo/index.md) | needed |
| Keep the session | [KeepAlive](https://developer.m-files.com/APIs/gRPC-API/Reference/MFiles.IRPCLogin/KeepAlive/index.md) | needed |
| End the session | [LogOut](https://developer.m-files.com/APIs/gRPC-API/Reference/MFiles.IRPCLogin/LogOut/index.md) | needed |

* `QueryVersion` returns versions as one 64-bit number each: four 16-bit parts, major in the
  highest bits. `0x001A000B41050000` is 26.11.16645.0.
* `LogIn` binds the session to the vault in `login_data.vault_guid`. The response's
  `session_data.session_id` (48 bytes) goes into the `mfiles-session-id-bin` metadata of every
  later call; the helpers do that for you. See
  [Authentication and sessions](https://developer.m-files.com/APIs/gRPC-API/runtime/authentication/index.md).
* `session_data.keep_alive_interval_in_seconds` is how often to call `KeepAlive` (450 seconds on
  the server below); the server drops the session after twice that time without one. Other
  calls do not extend the session.
* Many calls return the vault's metadata structure version in the `mfiles-metadata-version-bin`
  trailer; the helpers keep the latest value. See
  [Metadata structure version and caching](https://developer.m-files.com/APIs/gRPC-API/concepts/metadata-structure-version-and-caching/index.md).
* After `LogOut`, calls with the old session ID fail with `UNAUTHENTICATED`.

## Code

### Python

```python
# No session is needed for these calls.
with MFilesClient.from_env(CLIENT_NAME, log_in=False) as client:
    version_service = client.stub(IRPCQueryVersion_pb2_grpc.IRPCQueryVersionStub)
    version = version_service.QueryVersion(IRPCQueryVersion_pb2.QueryVersionRequest())
    print(f"Server version: {decode_version(version.server_version)}")

    login = client.stub(IRPCLogin_pb2_grpc.IRPCLoginStub)
    capabilities = login.GetServerCapabilities(
        IRPCLogin_pb2.GetServerCapabilitiesRequest()).server_capabilities
    print(f"Server capabilities: file_streaming={capabilities.file_streaming}, "
          f"facet_search={capabilities.facet_search}")

    session = client.log_in()
    print(f"Logged in as {session.account_name}; "
          f"keep-alive interval {session.keep_alive_interval_in_seconds} s")

    info = login.GetVaultSessionInfo(
        IRPCLogin_pb2.GetVaultSessionInfoRequest()).vault_session_info
    print(f"Vault: {info.vault_display_name} {info.vault_guid}")
    # From the trailers of the calls so far.
    structure_version = client.metadata_structure_version
    print(f"Metadata structure version: "
          f"{'not reported' if structure_version is None else structure_version}")

    # A long-running program calls KeepAlive within the keep-alive interval.
    login.KeepAlive(IRPCLogin_pb2.KeepAliveRequest())
    print("KeepAlive: ok")

    client.log_out()
    print("Logged out")
```

*Source: [python/recipes/connect.py](https://developer.m-files.com/APIs/gRPC-API/downloads/samples/python/recipes/connect.py)*

### C#

```csharp
// No session is needed for these calls.
await using var connection = MFilesConnection.Open(settings);

var versionService = new IRPCQueryVersion.IRPCQueryVersionClient(connection.CallInvoker);
var version = await versionService.QueryVersionAsync(new QueryVersionRequest());
Console.WriteLine($"Server version: {DecodeVersion(version.ServerVersion)}");

var login = new IRPCLogin.IRPCLoginClient(connection.CallInvoker);
var capabilities = (await login.GetServerCapabilitiesAsync(new GetServerCapabilitiesRequest()))
    .ServerCapabilities;
Console.WriteLine($"Server capabilities: file_streaming={capabilities.FileStreaming}, " +
    $"facet_search={capabilities.FacetSearch}");

var session = await connection.LogInAsync(settings, RecipeHelpers.ClientName);
Console.WriteLine($"Logged in as {session.AccountName}; " +
    $"keep-alive interval {session.KeepAliveIntervalInSeconds} s");

var info = (await login.GetVaultSessionInfoAsync(new GetVaultSessionInfoRequest())).VaultSessionInfo;
Console.WriteLine($"Vault: {info.VaultDisplayName} {info.VaultGuid}");
Console.WriteLine($"Metadata structure version: {connection.MetadataStructureVersion?.ToString() ?? "not reported"}");

// A long-running program calls KeepAlive within the keep-alive interval.
await login.KeepAliveAsync(new KeepAliveRequest());
Console.WriteLine("KeepAlive: ok");

await connection.LogOutAsync();
Console.WriteLine("Logged out");
```

*Source: [csharp/Recipes/Connect.cs](https://developer.m-files.com/APIs/gRPC-API/downloads/samples/csharp/Recipes/Connect.cs)*

### Go

```go
// Dial only creates the channel. Calls without a session work right away.
client, err := mfilesclient.Dial(cfg)
if err != nil {
	return err
}
defer client.Close()

version, err := mfiles.NewIRPCQueryVersionClient(client.Conn).QueryVersion(ctx,
	&mfiles.QueryVersionRequest{})
if err != nil {
	return err
}
fmt.Println("Server version:", mfilesclient.VersionString(version.GetServerVersion()))

login := mfiles.NewIRPCLoginClient(client.Conn)
capabilities, err := login.GetServerCapabilities(ctx, &mfiles.GetServerCapabilitiesRequest{})
if err != nil {
	return err
}
fmt.Printf("Server capabilities: file_streaming=%v, facet_search=%v\n",
	capabilities.GetServerCapabilities().GetFileStreaming(),
	capabilities.GetServerCapabilities().GetFacetSearch())

// Log in. From now on every call carries the session ID.
session, err := client.LogIn(ctx, cfg)
if err != nil {
	return err
}
fmt.Printf("Logged in as %s; keep-alive interval %d s\n",
	session.GetAccountName(), session.GetKeepAliveIntervalInSeconds())

info, err := login.GetVaultSessionInfo(ctx, &mfiles.GetVaultSessionInfoRequest{})
if err != nil {
	return err
}
fmt.Printf("Vault: %s %s\n", info.GetVaultSessionInfo().GetVaultDisplayName(),
	info.GetVaultSessionInfo().GetVaultGuid())
// The latest value from the mfiles-metadata-version-bin trailer of the calls so far.
if metadataStructureVersion, ok := client.MetadataStructureVersion(); ok {
	fmt.Println("Metadata structure version:", metadataStructureVersion)
} else {
	fmt.Println("Metadata structure version: not reported")
}

// Call KeepAlive at least every keep-alive interval on long runs; other calls do not extend
// the session.
if _, err := login.KeepAlive(ctx, &mfiles.KeepAliveRequest{}); err != nil {
	return err
}
fmt.Println("KeepAlive: ok")

if err := client.LogOut(ctx); err != nil {
	return err
}
fmt.Println("Logged out")
```

*Source: [go/recipes/connect/main.go](https://developer.m-files.com/APIs/gRPC-API/downloads/samples/go/recipes/connect/main.go)*

Output against an on-premises server:

```text
Server version: 26.11.16645.0
Server capabilities: file_streaming=True, facet_search=False
Logged in as grpcdocs.user; keep-alive interval 450 s
Vault: gRPC Docs Samples {7BBEA0BC-40D8-4BCB-A67D-8A3ACFBDB575}
Metadata structure version: 1024
KeepAlive: ok
Logged out
```

The two capability flags are examples. `file_streaming` does not mean that the streaming file
transfer service can be used; see [Files](https://developer.m-files.com/APIs/gRPC-API/runtime/files/index.md) for the flags that matter for
uploads.

## Find the vault by its name

`LogIn` needs the vault's GUID. A program that knows only the vault's name, or wants to let the
user pick a vault, finds the GUID first:

1. [LogIn](https://developer.m-files.com/APIs/gRPC-API/Reference/MFiles.IRPCLogin/LogIn/index.md) with `login_data.vault_guid` set to
   `{00000000-0000-0000-0000-000000000000}`. This opens a server-level session.
2. [GetVaults](https://developer.m-files.com/APIs/gRPC-API/Reference/MFiles.IRPCVaults/GetVaults/index.md) with `exclude_vaults_user_cannot_access` true
   lists the vaults the user can log in to. Each has `guid` and `display_name`.
3. [LogInWithSession](https://developer.m-files.com/APIs/gRPC-API/Reference/MFiles.IRPCLogin/LogInWithSession/index.md) with the server-level session in
   `mfiles-session-id-bin` and the chosen vault's GUID in `login_data.vault_guid` returns a vault
   session, without authenticating again. Then log out the server-level session.

Python (the helper `switch_to_vault` does step 3):

```python
client.config.vault = SERVER_LEVEL
client.log_in()
vaults = client.stub(IRPCVaults_pb2_grpc.IRPCVaultsStub).GetVaults(
    IRPCVaults_pb2.GetVaultsRequest(exclude_vaults_user_cannot_access=True)).vaults
for vault in vaults:
    print(f"{vault.display_name}: {vault.guid}")
matches = [v for v in vaults if not name or v.display_name.casefold() == name.casefold()]
if not matches:
    raise SystemExit(f"No vault named '{name}' that this user can access")
session = client.switch_to_vault(matches[0].guid)
```

*Source: [python/recipes/find_vault.py](https://developer.m-files.com/APIs/gRPC-API/downloads/samples/python/recipes/find_vault.py)*

```python
response = self.login.LogInWithSession(IRPCLogin_pb2.LogInWithSessionRequest(
    client_data=self._client_data(),
    login_data=structs_pb2.LoginData(server_hostname=self.config.host,
                                     vault_guid=vault_guid)))
self.log_out()  # The server-level session; the new vault session stays valid.
self.config.vault = vault_guid
self.session_id = response.session_data.session_id
self.session = response.session_data
```

*Source: [python/mfiles_client.py](https://developer.m-files.com/APIs/gRPC-API/downloads/samples/python/mfiles_client.py)*

See [Binding the session to a vault](https://developer.m-files.com/APIs/gRPC-API/runtime/authentication/index.md#binding-the-session-to-a-vault).

## Pitfalls

* The anonymous calls work without logging in, so they are the right first check of address and
  TLS settings. Any call that needs a session and has none fails with `UNAUTHENTICATED`, without
  an M-Files error stack.
* `ServerVaultCapabilities` flags are `false` both when a feature is missing and when the server
  is older than the flag. Check the flag before you use a newer feature. See
  [Versions and compatibility](https://developer.m-files.com/APIs/gRPC-API/runtime/versioning/index.md).
* On M-Files Cloud, keep the `mfilesmsm` cookie and send it back on every call; the helpers do.
  See [Call metadata](https://developer.m-files.com/APIs/gRPC-API/runtime/call-metadata/index.md#cookies-and-stickiness).
* Always log out. A session that is not logged out stays on the server until it times out.

## See also

* [Connecting to the server](https://developer.m-files.com/APIs/gRPC-API/runtime/connecting/index.md), [Cloud and on-premises](https://developer.m-files.com/APIs/gRPC-API/runtime/deployments/index.md)
* [Call metadata](https://developer.m-files.com/APIs/gRPC-API/runtime/call-metadata/index.md)
* Quickstarts: [Python](https://developer.m-files.com/APIs/gRPC-API/guides/quickstart-python/index.md), [C#](https://developer.m-files.com/APIs/gRPC-API/guides/quickstart-csharp/index.md), [Go](https://developer.m-files.com/APIs/gRPC-API/guides/quickstart-go/index.md)
