Introspect OAuth2 refresh tokens

RFC 7662 lets clients introspect any OAuth2 token, but the endpoint
only resolved access tokens. Look up refresh tokens too, honor the
optional token_type_hint to drive lookup order with a fallback to the
other table, and report revoked or expired refresh tokens as inactive.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
Bryan Frimin
2026-04-28 09:24:06 +02:00
committed by Émile Ré
parent 62f05b3ff2
commit 2418079785
5 changed files with 286 additions and 20 deletions

View File

@@ -252,6 +252,7 @@ func (h *OAuth2Handler) IntrospectHandler(w http.ResponseWriter, r *http.Request
r.Context(),
client.ID,
in.Token,
in.TokenTypeHint,
)
if err != nil || result == nil {
httpserver.RenderJSON(w, http.StatusOK, types.InactiveIntrospectResponse())

View File

@@ -21,6 +21,7 @@ import (
"go.probo.inc/probo/pkg/coredata"
"go.probo.inc/probo/pkg/gid"
"go.probo.inc/probo/pkg/iam/oauth2server"
"go.probo.inc/probo/pkg/uri"
)
@@ -59,7 +60,8 @@ type (
}
OAuth2IntrospectInput struct {
Token string
Token string
TokenTypeHint *coredata.OAuth2TokenTypeHint
}
OAuth2RevokeInput struct {
@@ -138,6 +140,14 @@ func (in *OAuth2IntrospectInput) DecodeForm(r *http.Request) error {
if in.Token == "" {
return fmt.Errorf("missing token parameter")
}
if hint := r.FormValue("token_type_hint"); hint != "" {
h := coredata.OAuth2TokenTypeHint(hint)
if h.IsValid() {
in.TokenTypeHint = &h
}
}
return nil
}
@@ -317,14 +327,14 @@ func InactiveIntrospectResponse() *OAuth2IntrospectResponse {
return &OAuth2IntrospectResponse{Active: false}
}
func ActiveIntrospectResponse(token *coredata.OAuth2AccessToken) *OAuth2IntrospectResponse {
func ActiveIntrospectResponse(result *oauth2server.IntrospectResult) *OAuth2IntrospectResponse {
return &OAuth2IntrospectResponse{
Active: true,
Scope: token.Scopes,
ClientID: token.ClientID,
Sub: token.IdentityID,
Exp: token.ExpiresAt.Unix(),
Iat: token.CreatedAt.Unix(),
TokenType: "Bearer",
Scope: result.Scopes,
ClientID: result.ClientID,
Sub: result.IdentityID,
Exp: result.ExpiresAt.Unix(),
Iat: result.IssuedAt.Unix(),
TokenType: result.TokenType,
}
}