Different authorization approaches for HTTPS endpoint vs GraphQL endpoint

To confirm my understanding (because the documentation is unclear to me at least):

GraphQL requests are authenticated using a Realm Access Token (passed as “Authorization: Bearer” header) or using one of the less recommended approaches: “api-key” header, basic authentication with email / password, or passing “jwtTokenString” header with the full JWT token

Calls to functions using Application Authentication via HTTPS endpoints can only be authenticated using “api-key” header, basic authentication with email / password, or passing the JWT with the “jwtTokenString” header

If this understanding is correct, why can’t the authentication approach be aligned between GraphQL and HTTPS endpoints? Why require me to get an access_token for GraphQL queries if I can’t use it for HTTPS endpoint requests?

Hello @Nick_Olson

Thank you for joining the MongoDB Forum community - My name is Josman and I am happy to assist you with your question.

GraphQL requests are authenticated using a Realm Access Token (passed as “Authorization: Bearer” header) or using one of the less recommended approaches: “api-key” header, basic authentication with email/password, or passing “jwtTokenString” header with the full JWT token

Under the hood, when you use the recommended way to authenticate GraphQL requests, you need to generate an access_token first. Therefore, you will need to use one of the authentication providers Realm offers to issue an access_token.

Following my previous example, if I use the email/password provider, I would need to generate a user token:

async function authenticate() {
    try {
        const credentials = Realm.Credentials.emailPassword("<email>", "<password>");
        const user = await app.logIn(credentials);
        console.log(`access token: ${user.accessToken}`);
        return user.id;
    } catch (err) {
        console.error(err);
    }
}

And use that access_token to perform a GraphQL request:

curl --location --request POST 'https://eu-west-1.aws.realm.mongodb.com/api/client/v2.0/app/<app_id>/graphql' \
--header 'Authorization: Bearer <access_token>' \
--header 'Content-Type: application/json' \
--data-raw '{"query":"query ... }'

Calls to functions using Application Authentication via HTTPS endpoints can only be authenticated using “api-key” header, basic authentication with email / password, or passing the JWT with the “jwtTokenString” header

When calling a Realm Function with application authentication, i.e, execute with the permissions of the user calling the function, we need to be authenticated first by using one of the authentication providers previously mentioned and using the authenticated user to call the Realm Function which will have the inherited access_token:

async function authenticate() {
    console.log("AUTHENTICATE");
    try {
        const credentials = Realm.Credentials.emailPassword("<email>", "<password>");
        const user = await app.logIn(credentials);
        const resultOfCallFunction = await user.callFunction("<function name>",[arg1, arg2]);
        return user.id;
    } catch (err) {
        console.error(err);
    }
}

If this understanding is correct, why can’t the authentication approach be aligned between GraphQL and HTTPS endpoints? Why require me to get an access_token for GraphQL queries if I can’t use it for HTTPS endpoint requests?

In the end, both authentication methods are aligned. Thus, both will benefit from the authentication providers you are enabling in your Realm App.

Please let me know if you have any additional questions or concerns regarding the details above.

Kind Regards,
Josman

Josman - thank you for taking the time to respond, I appreciate it!

Your response lays out where the confusion is, at least for me. As I understand it, making a GraphQL request is a two step process - step 1 is to authenticate, step 2 is to use the user token (access_token) for all future queries (i.e., you have to already be authenticated). Whereas calling a function through an HTTPS endpoint is a one step process - you authenticate (via email/pass, api-key, JWT) and call the function all together.

For context, my app has an authentication package (nuxt auth) that can be configured to query an endpoint after authentication to get user information. I am able to authenticate into Mongo using a JWT, however, a subsequent call to an HTTPS Endpoint uses the access token as the authentication header in that request.

I guess my main question is whether there is a way to use Bearer authentication in calls to HTTPS Endpoint functions (i.e., whether Application Authentication supports Bearer authentication) or if I need to pass in the entire JWT whenever I want to hit the endpoint.

Thanks again for the help!

Hello @Nick_Olson

Whereas calling a function through an HTTPS endpoint is a one step process - you authenticate (via email/pass, api-key, JWT) and call the function all together.

Could you please share with me an example of the above? Currently, you can call a function from within:

// difference: subtracts b from a using the sum function
exports = function(a, b) {
    return context.functions.execute("sum", a, -1 * b);
};
  • From a JSON Expression:
{
  "numGamesPlayed": {
    "%function": {
      "name": "sum",
      "arguments": [
        "%%root.numWins",
        "%%root.numLosses"
      ]
    }
  }
}
  • From the Realm CLI:
realm-cli function run \
 --function=sum \
 --user=61a50d82532cbd0de95c7c89 \
 --args=1 --args=2
  • From a Client Application

When you are referring to an HTTPS endpoint, could you please share with me an example?

Looking forward to your response.

Regards,
Josman

Sure - I am trying to call the function from a client application via HTTPS Endpoint. My client app is built with nuxt/vue and queries data from my Mongo Atlas instance using the GraphQL interface exposed by Realm.

I log in using Sign in with Google, so I get a JWT from Google, which I then pass to Realm to authenticate (using Custom JWT Authentication). I take the resulting user token (access_token) and use it for all my GraphQL queries.

For this thread, the HTTPS Endpoint in question would just respond back with the user’s information from context.user. I.e., I would like to take my authenticated user in my client web app (who has an access_token), query /userinfo, and get back that user’s info (which was populated into Realm through the Google JWT payload).

I recognize that I could potentially use the Web SDK but my intent is to keep the front end as decoupled as possible from the backend and I want to minimize the number of packages since I’m already using nuxt.

Hopefully this helps clarify. Basically I am trying to understand how I will need to configure the axios instance in my app to correctly hit Realm HTTPS Endpoints - do I need to pass the full JWT or can I just use an access_token header.

Hello @Nick_Olson

Hopefully this helps clarify. Basically I am trying to understand how I will need to configure the axios instance in my app to correctly hit Realm HTTPS Endpoints - do I need to pass the full JWT or can I just use an access_token header.

Thank you for clarifying your use case. Unfortunately, at this moment you can’t use access tokens with https endpoints yet, which is why they are not recommended for the client-side. We are working on this but I do not have an ETA yet of when this is going to be available.

I am so sorry for the inconvenience this might cause on your application.

Please let me know if you have any additional questions or concerns regarding the details above.

Kind Regards,
Josman

@Josman_Perez_Exposit - I appreciate you confirming this. I suspected as much once I figured out that I could authenticate using the full JWT string but I wanted to make sure I wasn’t missing anything obvious.

Thank you for your help!

1 Like

Hi @Josman_Perez_Exposit , sorry to ask here instead of creating a new post - I actually did but haven’t got any response :slight_smile:

I’m trying to call HTTPS endpoint using JWT - but unfortunately, I keep getting the following error
{"error":"invalid session: error finding user for endpoint","error_code":"InvalidSession","link":"https://realm.mongodb.com/groups/error_log"}

@Mustafa_Al_Ani - do you have Custom JWT set up as an authentication provider in Realm → Data Access → Authentication?

If so, do you have an App User configured for that JWT token?

@Nick_Olson - I do have a custom JWT setup as a provider.

I don’t have a specific user for JWT, can’t I use the existing (email/pass provider) users ids?

You might need to configure the Custom JWT authentication to create the user if they haven’t previously logged in. I would also double check your user permissions.

I am pretty sure you can map the user entry that’s created by the Custom JWT capability to existing users (e.g., those create through email / pass or in a separate DB). I think you have to set a UUID key for the user doc though.