nuxt-auth icon indicating copy to clipboard operation
nuxt-auth copied to clipboard

dataType should support passing in an actual type

Open TheDutchCoder opened this issue 5 months ago • 11 comments

Describe the feature

You can currently manually define types on the session.dataType property, but we rely on our back-end for providing the right types.

It would be good if we could leverage this in the config, for 2 reasons:

  1. If the back-end type ever updates/changes, the front-end will now and (potentially) not pass the type checker (which is good)
  2. It would prevent people from having to manually define (and maintain!) the types, potentially getting out-of-sync with their back-ends

How would you implement this?

Allow to import a type and use it as a value for dataType.

Additional information

  • [ ] Would you be willing to help implement this feature?

Provider

  • [ ] AuthJS
  • [x] Local
  • [ ] Refresh
  • [ ] New Provider

TheDutchCoder avatar Jun 20 '25 18:06 TheDutchCoder

You probably meant to introduce a runtime verification for the data type? It should theoretically be possible after #964, where you'd get an "after-response" hook

phoenix-ru avatar Jun 27 '25 09:06 phoenix-ru

Not really. We're just looking for specifying the actual types in SessionData.

Instead of just primitives, we actually want to use certain enums that our backend returns.

On Fri, Jun 27, 2025, 5:33 a.m. Marsel Shaikhin @.***> wrote:

phoenix-ru left a comment (sidebase/nuxt-auth#1031) https://github.com/sidebase/nuxt-auth/issues/1031#issuecomment-3012355183

You probably meant to introduce a runtime verification for the data type? It should theoretically be possible after #964 https://github.com/sidebase/nuxt-auth/issues/964, where you'd get an "after-response" hook

— Reply to this email directly, view it on GitHub https://github.com/sidebase/nuxt-auth/issues/1031#issuecomment-3012355183, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAMXI37SX6I42QY3ZNYZSN33FUFXVAVCNFSM6AAAAAB7Y4IOJSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTAMJSGM2TKMJYGM . You are receiving this because you authored the thread.Message ID: @.***>

TheDutchCoder avatar Jun 27 '25 09:06 TheDutchCoder

Instead of just primitives, we actually want to use certain enums that our backend returns.

Could you please elaborate a bit more on it? Just provide a code sample of how you envision using this?

phoenix-ru avatar Jul 03 '25 09:07 phoenix-ru

In the end, you guys just generate a auth.d.ts with an exported interface, so it might be much easier to just provide the interface/type in the config, instead of manually having to declare it and trying to maintain syncing between the type and the manually defined object.

I'm not 100% sure how you could provide a type easily and ingest it, but there's probably some way to make that happen in TS?

This would also account for any optional properties (which we have quite a few of) and proper enums.

Now we have to cast the SessionData in order to get access to those.

Currently I have to do something like this:

// Nuxt config
import type { UseAuthentication } from '~/types/rental-api-aliases'

// Because type assertions are unsafe, I have to make sure that the sessionData
// is actually mapped correctly to what the endpoint returns.
export default defineNuxtConfig({
  auth: {
    provider: {
      session: {
        dataType = {
          // props
        } satisfies Record<keyof UseAuthentication, unknown>
      }
    }
  }
})

Then somewhere where we use this data:

import type { UseAuthentication } from '~/types/rental-api-aliases'

export default function useAuthentication() {
  const { data, status, token, signIn, signOut, getSession } = useAuth()

  // I have to assert the type here, because sidebase's type is not the real type.
  const properData = computed<UseAuthentication>(() => data.value as UseAuthentication)

  // Now I have access to the real type
  if (properData?.Country === 'US') {}
}

TheDutchCoder avatar Jul 03 '25 12:07 TheDutchCoder

Yeah, it makes sense. I think it might already be possible, have you tried augmenting #auth?

// auth-types.d.ts
declare module '#auth' {
  interface SessionData {
    // your types here
  }
}

// To switch to augmentation instead of ambient module
export {}

phoenix-ru avatar Jul 03 '25 16:07 phoenix-ru

I haven't, but that's actually a good idea. I'll take a look and remove my workaround to see if that's the most elegant solution (and/or if it yields any issues). I'll report back!

TheDutchCoder avatar Jul 03 '25 17:07 TheDutchCoder

Yeah, it makes sense. I think it might already be possible, have you tried augmenting #auth?

// auth-types.d.ts declare module '#auth' { interface SessionData { // your types here } }

// To switch to augmentation instead of ambient module export {}

It looks like the types generated by the module still take precedence unfortunately.

TheDutchCoder avatar Jul 03 '25 17:07 TheDutchCoder

@TheDutchCoder The interfaces should be merged: https://www.typescriptlang.org/docs/handbook/declaration-merging.html#merging-interfaces

Could you share how you're doing it?

phoenix-ru avatar Aug 01 '25 14:08 phoenix-ru

Okay I just retried with the following interface and I think it's working:

import type { UseAuthentication } from '~/types/rental-api-aliases'

declare module '#auth' {
  type SessionData = UseAuthentication
}

// To switch to augmentation instead of ambient module
export {}

Not sure why it didn't work previously for me 🤔 TS is always a struggle with this.

TheDutchCoder avatar Aug 01 '25 15:08 TheDutchCoder

Oh no I spoke too soon, I casted my type in my composable where I use useAuth. Here's an example of the problem:

Image

As you can see, the country is of type string because if the module, but it's actually an enum from the backend.

TheDutchCoder avatar Aug 01 '25 16:08 TheDutchCoder

@TheDutchCoder I am actually able to get it working without much problems.

Here's what I did:

// playground-local/auth-types.d.ts

// One way
interface CustomDeclarations {
  customThing: 'this' | 'that'
}

// Also works with types
type SomeComplexType = { foo: 'bar' }

declare module '#auth' {
  // notice that this is an interface
  interface SessionData extends CustomDeclarations, SomeComplexType {
    // other way
    anotherThing: 42
  }
}

// To switch to augmentation instead of ambient module
export {}


Here's what I get:

Image

phoenix-ru avatar Aug 14 '25 15:08 phoenix-ru