1- import { oidcSpa } from "oidc-spa/server" ;
1+ import { oidcSpa , extractRequestAuthContext } from "oidc-spa/server" ;
22import { z } from "zod" ;
33import { HTTPException } from "hono/http-exception" ;
44import type { HonoRequest } from "hono" ;
@@ -9,7 +9,7 @@ const { bootstrapAuth, validateAndDecodeAccessToken } = oidcSpa
99 sub : z . string ( ) ,
1010 realm_access : z . object ( {
1111 roles : z . array ( z . string ( ) )
12- } )
12+ } ) . optional ( )
1313 } )
1414 } )
1515 . createUtils ( ) ;
@@ -24,39 +24,46 @@ export async function getUser(
2424 req : HonoRequest ,
2525 requiredRole ?: "realm-admin" | "support-staff"
2626) : Promise < User > {
27+ const requestAuthContext = extractRequestAuthContext ( {
28+ request : req ,
29+ trustProxy : true
30+ } ) ;
2731
28- const { isSuccess, errorCause, debugErrorMessage, decodedAccessToken } =
29- await validateAndDecodeAccessToken ( {
30- request : {
31- url : req . url ,
32- method : req . method ,
33- getHeaderValue : headerName => req . header ( headerName )
34- }
35- } ) ;
32+ if ( ! requestAuthContext ) {
33+ // Demo shortcut: we return 401 on missing Authorization, but a mixed
34+ // public/private endpoint could instead return undefined here and let
35+ // the caller decide whether to process an anonymous request.
36+ console . warn ( "Anonymous request" ) ;
37+ throw new HTTPException ( 401 ) ; // Unauthorized
38+ }
3639
37- if ( ! isSuccess ) {
40+ if ( ! requestAuthContext . isWellFormed ) {
41+ console . warn ( requestAuthContext . debugErrorMessage ) ;
42+ throw new HTTPException ( 400 ) ; // Bad Request
43+ }
3844
39- if ( errorCause === "missing Authorization header" ) {
40- // Demo shortcut: we return 401 on missing Authorization, but a mixed
41- // public/private endpoint could instead return undefined here and let
42- // the caller decide whether to process an anonymous request.
43- console . warn ( "Anonymous request" ) ;
44- } else {
45- console . warn ( debugErrorMessage ) ;
46- }
45+ const { isSuccess, debugErrorMessage, decodedAccessToken } =
46+ await validateAndDecodeAccessToken (
47+ requestAuthContext . accessTokenAndMetadata
48+ ) ;
4749
48- throw new HTTPException ( 401 ) ;
50+ if ( ! isSuccess ) {
51+ console . warn ( debugErrorMessage ) ;
52+ throw new HTTPException ( 401 ) ; // Unauthorized
4953 }
5054
51- if (
52- requiredRole !== undefined &&
53- ! decodedAccessToken . realm_access . roles . includes ( requiredRole )
54- ) {
55- console . warn ( `User missing role: ${ requiredRole } ` ) ;
56- throw new HTTPException ( 403 ) ;
55+ // Your custom Authorization logic: Grant per request access depending
56+ // on the access token claim.
57+ if ( requiredRole ) {
58+ if ( ! decodedAccessToken . realm_access ?. roles . includes ( requiredRole ) ) {
59+ console . warn ( `User missing role: ${ requiredRole } ` ) ;
60+ throw new HTTPException ( 403 ) ; // Forbidden
61+ }
5762 }
5863
59- return {
64+ const user : User = {
6065 id : decodedAccessToken . sub
6166 } ;
67+
68+ return user ;
6269}
0 commit comments