Introduction

This article explains how to integrate the research data management platform “GakuNin RDM” with a Next.js application using OAuth2. Since GakuNin RDM provides an API compatible with OSF (Open Science Framework), implementation can be based on the OSF OAuth2 flow.

This article provides a detailed explanation of the implementation using next-auth and the pitfall of automatic access token refresh.

What is GakuNin RDM?

GakuNin RDM (Research Data Management) is a research data management service provided by the National Institute of Informatics (NII).

It is a platform where researchers can safely store, share, and publish research data, and through integration with GakuNin authentication, users from Japanese universities and research institutions can use it.

Preparation

1. Registering an OAuth Application

Register an OAuth application from the GakuNin RDM settings screen.

  1. Access https://rdm.nii.ac.jp/settings/applications/
  2. Click “Register a developer application”
  3. Configure the following:
    • Application name: App name
    • Application homepage URL: http://localhost:3000 (for development)
    • Application description: Description
    • Authorization callback URL: http://localhost:3000/api/auth/callback/gakunin

After registration, a Client ID and Client Secret are issued.

2. Setting Environment Variables

#GGNNOAAEES.KKXXFeUUTT_nNNAASvIIUUC.NNTTOl__HHPoCC__EcLLUS=aIIREolEELCsNN=RfTThE.__tTfISt=uDEpyl=C:lyRu_oE/rruTl_er=ora_ycadcoanluldoirhose_omfncs_.tltsf_i:euie3cldn0rlt0e__0twsreictreet

Custom Provider Configuration with next-auth

Since GakuNin RDM is not included in next-auth’s built-in providers, it needs to be configured as a custom provider.

Basic Configuration

ie}mx;ppp]loor,irro{}bttv,/iintcca}t}up}atcddayllu,o,sr,uyoe:mpiitup}kua}eor}tpnreeeehra,ers,rfe;hess"::nnolrcsrrnlyc}c)ci}riitine.t:gttr:alcee::no)o;ofenludamt{a""ISimiosdcncccgr;n"{}nttfer:masa[kGodez"seppi{"slloreshs(huo(neiNuuaa:cah:neorhrtiidadttmh}bt!rr:pp:letnkurttt:neteeeenitee,oronr{r:xhiutpeit{_sctqbnn:trrpta"djew"ooptOnNhrtopipetpuott_eeshdCyss{hffrpAp"i"o:nsdr__sed__ctcs:oeo,o.ntiiorut,n,c:::otu:syisoyt/drnnoettllfotiep/cyr/tdenp_=/:stkwopeeifhoRsr{/pepi/(=:cteua:e=)ks).liOnDsoarse:acre:rac"nEe:delpsM.ccos:conpexiwcP{ta{rn/{a.et:"eecc.`cnertt":aoO-wrs/td.i,nsoee"$otwo:.aiuSTao:aaadoNvsusnc{uecpu`tnTyirp.tane..nsvopnxUepat$t"pt(jiiatsxGet..drttRsrrh{fs,e`s.d.atAnseOeos)Lsoaope."rTor,a.}AKv.nS"c.S.cmrrtr:eondtauU.rvF,er{eeesiocdskmttftNGd._sdans.zchm".e}.rtrhIAmGSsmrvscae(.ajn;niroONK.AC..c..otsnpsibimp_UnKOenhGedisiporiubtCNiUPniPAneo.ilne.tu"iLIiNEviaKvne.i(qaetnoIN.I..rU.a_nac)ucseenE_aNNaaNGscvca;e..sxsNCc_EcmIAo..tsjf.tTL.CX.sNKsdNjitpue-=_IjL"Tj(_UteEpo/lmaIEpIoAp{CNr"X/nfvlau{DN/EsU/LIi,To/a2_it,ToNfToINnAaxi/nlh_aT.HaE_gUu-lua,"Su_f_uNC,Ttwesm;EtIuUtTLHhwdeeChDlRh_I_2w:r,R2,lL2IEU/-sE/_}/DNRtf$/Tar/t!TLoo{m,ueao,_}krretapkS/eme/hdieEan-s"o/nCp"u.,roa"Ri,rsisu,E/ltzftTaeae.h!unt"f/,tcu,uchosla/dTllcee_ladxwbl"tral,}icb`tka)e/c;"gk,a/kguankiunn`i,n`,

Key Points

  1. Customizing token.request: Since GakuNin RDM expects token requests in application/x-www-form-urlencoded format, a custom request function is implemented
  2. Parsing userinfo: Since the OSF API returns responses in { data: { id, attributes: { ... } } } structure, mapping is done in the profile function

Pitfall: Automatic Token Refresh

Problem

OAuth2 access tokens have an expiration time (approximately 1 hour for GakuNin RDM).

In the default implementation of next-auth, token refresh is not performed. Therefore, after being logged in for a while, the following error occurs:

Failedtofetchprojects:401-{"errors":[{"detail":"UserprovidedaninvalidOAuth2accesstoken"}]}

This creates a confusing situation where the user is logged in but the API returns a 401 error.

Solution

Manage the token expiration in the JWT callback and automatically refresh before expiration.

d}d}a}e}eesx;ci}ci}yt}}pc}lTlnlnRnrAa,iyataeataraeecyc}c)ci}r}cr}drla}a}bprecrrececrfo)o;ofe;ae;dtls,s,/eercrercfcrrf{nccrg;n"{}nttaarttebyi}i}ryssrafeofereoeusllershs(huccecurccanffeneeeudmasrmasesrsntiifattmh}bt!rr.ccfhr.raoccr}rtcsstteocs?ocsss?hceerntee,oronteerntolnpkO(e;I(eTussuhfdeT:deThT:tbnnetrpta"drewosse(orlsrsjnataraufttorsiir.iuouoTofiotts_eshdCyes{kssse{k:bto:wcucecsoukneoontnlSkslJkoksuod__hts:oeo,fpneTThreavticr.cfcetkresnnsieeeteWeketnnyis_ypdrnroenooTrn"cai{(nontereroennrs..stsnrTnenrcdetp/:stenw,kkoo,Rkud{iuosesIkneiaeei"s?i"?nEitr=:coena:esseekrestetn{ksssde.tefocrsoni:nn{:?xnierk:sc"nheEnne)fhrtiteThT:naoxrncrsneoge:pgofnpeeecP{te.r:EnrtOsoa)noTockpe(eoixns;xsi;nrertn"oO-dorx:{eopkl,kokuiceis{sroettttsrewo::r=uSTTkorpstce{ekessenrhsnx-{r-rtescenTyo)reirhaionsnenes;eAsT=;taiairshUeptfat"pk(freAuon,i:nErssdceoeununi?ARsrorws,ee{"refctnfg:x?tTcsktntgtgn:cLsokea."nResrchsianap.ioeseosh;h;gcS.cesir:ses:eeO:gc-caiilksinki"/;neeeenhtdfhsspuciccrdlesoeojusans._m"=reDhstNronoce,nrTn=nn{wmsrvsrtf.aedaeTieauuosvEeo,.stbTc..eoenpasTtdooxtnnu:axfkte"eohGefktipwhoeTkntittnlpretorrkPAnrecilaAk.oesAo,.tDiienokr{;eaKvenh.iicenknuna.adrs(keonrU.s"(actcnoeEtucrtehtenr(aNGh,caeswnrhscee(son.;tmIAT.trs.(srOeef.wkaosNKojiesa).oprsrni&e}ck(_UkposTcrrtseot&n)ce{CNe/npoc+e"i}_swh)enLIno/okef,o)th(D;{s:IN!axnesrrno_)6asE_,u-snsees{kt0tTJNCtweE_fseo-eoWTLhw.rtrh=nks.kT_I2wjroe_,e(ene)IE/-sokst{naconDNtforeho,cow;{!Toon"nekcn(,_kr(),deod)Sem);TnuEn-;onb<C"uk?tuR,re?.ftElnefoTestxek!n.opre,ceki)noxer.dpneaei.scdrr_c"eeie,sfns_rsieaTnssohkTneoun1kmE0ebx0nep0,ri,)res1-00600,000){

Flow Diagram

aarcceccfoerusYNenNseostoTshoAekcxecinesEstxsspT?iorkeesnY(e>)JsWnTo>>w>CRaI---+eRolnterliSSS6utbtaaa0rusaivvvsnrecaeee?ntkltaraonesceckericfcewrgerenonsestr-sssaoiThTsknoTo-ekokinekesnennExpires

Client-Side Error Handling

If the refresh token has also expired, session.error is set to "RefreshAccessTokenError". This can be detected to prompt re-sign-in.

"iie}ummxspppcu}rceoooos,eorrrnei}tmctttsEf[upltfssroi{{ff(ienneu{esgsenuunceTnsntsscdtsoIi>t"eeta(skno{s;SEit(ie(nc/efoa)on"]hSsfn:ng)iese=?ra;lsicSs>.ekdsoteeefurinss{rrneo,}ssreinniiosn}Gsfoorh"<uirnn)/agoG=f;>rnmu}=a;dIa=i.n"r=ltrd"es}e(uRdxa{sefcefrtcSro"heem;issplshr"diAonrocmeencpxn(ett)s-};sra:Teuo-t{kshei/cngrhEneir-alricdontrr"e";n):{React.ReactNode}){

API Usage Example

iiie}mmmxppppci}c}craooooofo)oeprrrrnr)nh};ntptttts(e;Use,su/t!t{{staAtra{{{asuedunpsseresretdiNgayesnrtaerhaN/eeunssraussoterxttcsiNottp:raxdtShioeruooitmReOfonx:s-n{z=R/erpun?t:rsaepsvtn.R"eetasrpeic=aeN4fiwpoorotcso0r=oaojnSniacpt1eninesesoweosa:tscesnasna}hwets}issuea`r.s}iGtTetdiBej/ofEo.htessrfnrTgkjeaapooro(eesncfronuo}m)tnotceen(tmS)nietrsdef"{e(cscea."r@r{ash$.ttno/vtT({jasemleeo"ss)xirdkheo;t"bS"etsn/n/ents(seas}pi)exus,so;rtti:nv-ho/.ea"n/aru;(ac"tapc;huie"t.s;hrsOdTpmot.kineoinni}s.`)a,;c.jp/v2/users/me/nodes/",{

Summary

Key points when integrating GakuNin RDM with next-auth:

  1. Configuration as a custom provider is required
  2. Token requests must be in application/x-www-form-urlencoded format
  3. Without implementing automatic access token refresh, 401 errors will occur even when logged in
  4. Implement client-side error handling for cases when the refresh token also expires

The third point, token refresh, is easy to overlook, so be sure to consider it when implementing OAuth2 integration.

References