# Passwordless OTP Login ( With nonce )

**URL:** <https://community.auth0.com/t/passwordless-otp-login-with-nonce/196340>\
**Category:** Get Help\
**Tags:** new-universal-login-experience, login-experience\
**Created:** [January 16, 2026, 3:13pm UTC](https://community.auth0.com/t/passwordless-otp-login-with-nonce/196340 "2026-01-16T15:13:44Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![chiratna](https://sea1.discourse-cdn.com/auth0/user_avatar/community.auth0.com/chiratna/32/73235_2.png) [@chiratna](https://community.auth0.com/u/chiratna)\
**Post date:** [January 16, 2026, 3:13pm UTC](https://community.auth0.com/t/passwordless-otp-login-with-nonce/196340/1 "2026-01-16T15:13:44Z")

</div>

I am trying to integrate sms otp login experience for an application that we are building. The end goal is to create an onchain federated keyless account in aptos with the help of the id token that auth0 returns. The requirement on aptos side is that, the idtoken should have an nonce claim in the payload.

I am aware that if I utilize the _ **/authorize** _ request, basically universal login experience allows me passing nonce params. But I dont want to do that. We have dedicated mobile number input and otp input screen and we want to use that.

_ **/paswordless/start** _ and _ **/oauth/token** _ endpoints ( authentication apis ) can help me do that, but I could not find any way of passing custom nonce which i would expect in my id token payload.

Is there any way I can achieve this or is following Universal Login Flow the only solution ?

Our app is in react native btw.

---

<div class="post-metadata">

**Author:** ![nik.baleca](https://sea1.discourse-cdn.com/auth0/user_avatar/community.auth0.com/nik.baleca/32/68749_2.png) [@nik.baleca](https://community.auth0.com/u/nik.baleca)\
**Post date:** [January 20, 2026, 4:38pm UTC](https://community.auth0.com/t/passwordless-otp-login-with-nonce/196340/3 "2026-01-20T16:38:18Z")

</div>

Hi @chiratna

Welcome to the Auth0 Community!

If you are using the passwordless endpoint, you should be able to pass in the `nonce` in the authorization parameters of the request as such:

```auto
authParams: {
        nonce: nonce
      }

```

Once you have done that, you will be able to use a PostLogin Action to set the nonce as a custom claim inside the ID Token:

```auto
exports.onExecutePostLogin = async (event, api) => {
  // Check if the custom nonce exists in the transaction.
  const nonce = event.transaction.protocol_details?.authParams?.nonce;

  if (nonce) {
    // If the nonce exists, add it as a custom claim to the ID Token.
    const namespace = 'https://some_cool_namespace/claims';
    api.idToken.setCustomClaim(`${namespace}/nonce`, nonce);
    }
};

```

Let me know if the following works for you and if you have any other issues regarding the matter.

Kind Regards,  
Nik

---

<div class="post-metadata">

**Author:** ![chiratna](https://sea1.discourse-cdn.com/auth0/user_avatar/community.auth0.com/chiratna/32/73235_2.png) [@chiratna](https://community.auth0.com/u/chiratna)\
**Post date:** [January 21, 2026, 2:30pm UTC](https://community.auth0.com/t/passwordless-otp-login-with-nonce/196340/4 "2026-01-21T14:30:07Z")

</div>

Hi Nik,  
Thanks for replying back..  
``￼event: {￼ transaction: { protocol: 'oauth2-password', metadata: {} },￼``

It seems like i am not receiving any `protocol_details` payload in the postLogin event.

this is what my passwordless/start api payload looks like

```json
{

“client_id”: “<client_id>”,

“client_secret”: “<client_secret>”, // For Regular Web Applications

“connection”: “sms”,

“phone_number”: “<phone_number>”,

“send”: “code”, //if left null defaults to link

“authParams”: { // any authentication parameters that you would like to add

“nonce”: “123456654321223455”

}

}

```

any reason why ? Am i missing anything ?

---

<div class="post-metadata">

**Author:** ![nik.baleca](https://sea1.discourse-cdn.com/auth0/user_avatar/community.auth0.com/nik.baleca/32/68749_2.png) [@nik.baleca](https://community.auth0.com/u/nik.baleca)\
**Post date:** [January 21, 2026, 4:41pm UTC](https://community.auth0.com/t/passwordless-otp-login-with-nonce/196340/5 "2026-01-21T16:41:45Z")

</div>

Thanks for the update!

What I am noticing in the provided information, it appears that the protocol you are using for the transaction is `oauth2-password` and not `oidc-basic-profile`. This would indicate that by the time that the transaction reaches the PostLogin Action, it is considered a new login process which does not include the initial `authParams` which you have provided to the `/passwordless/start` endpoint.

If you are making a POST to the `/oauth/token` endpoint, you might need to specify that you are using the `oauth/grant-type/passwordless/otp` grant type. To provide you more insight, a typical flow would be:

- The initial POST to the `/passwordless/start` endpoint

```auto
{
  "client_id": "...",
  "connection": "sms",
  "phone_number": "...",
  "send": "code",
  "authParams": {
    "nonce": "123456654321223455"
  }
}

```

- Post Request to the `/oauth/token` endpoint

```auto
{
    "grant_type": "http://auth0.com/oauth/grant-type/passwordless/otp", 
    "client_id": "...",
    "client_secret": "...",
    "username": "THE_PHONE_NUMBER",
    "otp": "THE_USER_ENTERED_CODE",
    "realm": "sms"
}

```

The `authParams` object from `/passwordless/start` is specifically tied to the passwordless authentication pipeline. When you exchange the OTP for tokens, you must use a `grant_type` that tells Auth0 to look for that pending passwordless transaction.

If you use a different `grant_type` , like `password` , Auth0 treats it as a completely new login attempt via the ROPG flow, which has no knowledge of the preceding `/passwordless/start` call or its `authParams` .

The most likely cause is that your `/oauth/token` request is using `grant_type: 'password'` instead of the correct grant type for this flow.

Please let me know if this fixes your issue. If not, could you share how exactly are you making these calls and what does the flow look like?

Kind Regards,  
Nik

---

<div class="post-metadata">

**Author:** ![chiratna](https://sea1.discourse-cdn.com/auth0/user_avatar/community.auth0.com/chiratna/32/73235_2.png) [@chiratna](https://community.auth0.com/u/chiratna)\
**Post date:** [January 27, 2026, 11:20am UTC](https://community.auth0.com/t/passwordless-otp-login-with-nonce/196340/6 "2026-01-27T11:20:28Z")

</div>

> [@nik.baleca](#):
>
> `http://auth0.com/oauth/grant-type/passwordless/otp`

Hey Nik,  
I really appreciate you taking out time, and helping me out with this. Apologies for the late reply here, I was off.  
I am trying to onboard users to our app, using their mobile number. And as mentioned earlier, we would need to have custom screens for the login experience.

The first api call `/passwordless/start` with payload

```json
{
  "client_id": "...",
  "client_secret": "....",
  "connection": "sms",
  "phone_number": "...", 
  "send": "code", 
  "authParams": { 
    "nonce": "123456654321223455"
  }
}

```

I can confirm i receive the otp in the supplied mobile number

the second api call i am doing is `/oauth/token` with payload

```json
{
  "grant_type" : "http://auth0.com/oauth/grant-type/passwordless/otp",
  "client_id": "....",
  "client_secret": "....",
  "username":"...",
  "otp": "...",
  "realm": "sms", 
  "audience": "https://<domain>/api/v2/",
  "scope": "openid profile email"
}

```

The protocol of the transaction always comes out to be `oauth2-password` and not `oidc-basic-profile` , and the `protocol_details` metadata is missing.

---

<div class="post-metadata">

**Author:** ![nik.baleca](https://sea1.discourse-cdn.com/auth0/user_avatar/community.auth0.com/nik.baleca/32/68749_2.png) [@nik.baleca](https://community.auth0.com/u/nik.baleca)\
**Post date:** [January 27, 2026, 7:23pm UTC](https://community.auth0.com/t/passwordless-otp-login-with-nonce/196340/7 "2026-01-27T19:23:25Z")

</div>

Hi again @chiratna

It appears that there was a mistake I have made during the reproduction of the issue I was using the standard flow of Auth0 instead of the API flow completely overlooking the requirement of using your own custom UI.

Since the `nonce` claim is a a security feature of the OpenID Connect **Implicit** and **Authorization Code** flows meaning that it is **not supported** in the direct Resource Owner Password Grant (ROPG) or **Passwordless API** flows (in the case of the `/oauth/token` ) that you are using for your native UI. Also, any attempts to use `api.idToken.setCustomClaim('nonce', ...)` will be ignored or throw an error since it is expected to be passed through the normal `/authorize` flow.

If switching to Universal Login by using a web browser login approach and if Aptos allows the usage of custom claims, you can bass the nonce in the body of your `/oauth/token` call as such:

```auto
{
  "grant_type" : "http://auth0.com/oauth/grant-type/passwordless/otp",
  "client_id": "....",
  "client_secret": "....",
  "username":"...",
  "otp": "...",
  "realm": "sms", 
  "audience": "https://<domain>/api/v2/",
  "scope": "openid profile email",
  "my_nonce": "custom_nonce"
}

```

This can be set inside the ID or Access Tokens as such using a PostLogin Action trigger:

```auto
 if (event.request.body.my_nonce) {
    api.idToken.setCustomClaim('https://myapp.com/aptos_nonce', event.request.body.my_nonce);
  }

```

If I can help with anything else, let me know!

Kind Regards,  
Nik

---

<div class="post-metadata">

**Author:** ![system](https://global.discourse-cdn.com/auth0/original/3X/b/5/b560f266932fcce5d57f09a6595bd50518cae3f3.jpeg) [@system](https://community.auth0.com/u/system)\
**Post date:** [February 10, 2026, 7:24pm UTC](https://community.auth0.com/t/passwordless-otp-login-with-nonce/196340/8 "2026-02-10T19:24:07Z")

</div>

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.
