oidc

Generated by tinox doc

tinox.core.oidc, split out of the bundled stdlib as a standalone tinox-central package.

ModuleVersionGroup
crypto1.1.1tinox.core
http_server1.2.1tinox.core
json1.1.1tinox.core
jwt1.1.1tinox.core
oauth21.1.1tinox.core

Verify id token

import tinox.core.oidc

class Main
{
    fnc main() -> Int32
    {
        const client: OidcClient = OidcClient::new(
            "https://accounts.google.com",
            "https://accounts.google.com/o/oauth2/v2/auth",
            "https://oauth2.googleapis.com/token",
            "https://www.googleapis.com/oauth2/v3/certs",
            "my-client-id",
            "my-client-secret",
            "https://myapp.example.com/callback"
        )

        const req: OAuth2AuthorizeRequest = client.buildAuthorizeUrl("openid email")
        println("redirect user to: " + req.url)

        // Callback handler, after the provider redirects back with ?code=...
        const tokens: OidcTokenResponse = client.exchangeCode("the-code-from-callback", req.codeVerifier)
        if (tokens.ok)
        {
            // id_token signature + iss/aud/exp/nbf already verified here
            println("subject: " + tokens.claims["sub"].getString())
        }
        else
        {
            println("login failed: " + tokens.errorMessage)
        }
        return 0
    }
}

Turnkey web login

import tinox.core.oidc
import tinox.core.http_server

class Main
{
    fnc main() -> Int32
    {
        const client: OidcClient = OidcClient::new(
            "https://accounts.google.com",
            "https://accounts.google.com/o/oauth2/v2/auth",
            "https://oauth2.googleapis.com/token",
            "https://www.googleapis.com/oauth2/v3/certs",
            "my-client-id",
            "my-client-secret",
            "https://myapp.example.com/callback"
        )
        const webApp: OidcWebApp = OidcWebApp::new(client, "a-long-random-cookie-sealing-secret")

        const server: HttpServer = HttpServer::new(8080)
        webApp.install(server) // registers /login and /callback

        server.get("/", ctx => {
            if (!webApp.requireLogin(ctx))
            {
                return // already redirected to /login
            }
            const user: Map<String, JsonValue> = webApp.currentUser(ctx)
            ctx.response.text("Welcome, " + user["email"].getString())
        })

        server.listen()
        return 0
    }
}

class OidcClient

Fields

issuerString
jwksUriString
clientIdString
oauthOAuth2Client

Methods

fn new(issuer: String, authorizeUrl: String, tokenUrl: String, jwksUri: String, clientId: String, clientSecret: String, redirectUri: String) → OidcClient
fn buildAuthorizeUrl(scope: String) → OAuth2AuthorizeRequest
fn exchangeCode(code: String, codeVerifier: String) → OidcTokenResponse
fn refresh(refreshToken: String) → OidcTokenResponse
fn verifyAndWrap(tr: OAuth2TokenResponse) → OidcTokenResponse
fn verifyIdToken(idToken: String) → Map<String, JsonValue>

class OidcTokenResponse

Fields

accessTokenString
refreshTokenString
tokenTypeString
expiresInInt64
idTokenString
claimsMap<String, JsonValue>
okBool
errorMessageString

class OidcWebApp

Fields

clientOidcClient
cookieSecretString
loginPathString
callbackPathString
sessionCookieNameString
pendingCookieNameString

Methods

fn new(client: OidcClient, cookieSecret: String) → OidcWebApp
fn install(server: HttpServer) → Nothing
fn installWithSessions(server: HttpServer, sessions: SessionManager) → Nothing
fn requireSession(ctx: HttpContext, sessions: SessionManager) → Bool
fn logoutSession(ctx: HttpContext, sessions: SessionManager) → Nothing
fn requireLogin(ctx: HttpContext) → Bool
fn currentUser(ctx: HttpContext) → Map<String, JsonValue>
fn logout(ctx: HttpContext) → Nothing
fnc sealJson(data: Map<String, JsonValue>, secret: String) → String
fnc unsealJson(sealed: String, secret: String) → Map<String, JsonValue>
fnc readCookie(ctx: HttpContext, name: String) → String

class Session

Fields

validBool
reasonString
idString
claimsMap<String, JsonValue>
issuedAtInt64
expiresAtInt64
seenAtInt64
renewedBool

Methods

fnc invalid(reason: String) → Session

class SessionManager

Fields

secretsList<String>
cookieNameString
cookiePathString
cookieDomainString
cookieSecureBool
cookieSameSiteString
lifetimeSecInt64
idleSecInt64
renewAfterSecInt64
maxRevokedInt64
epochMsInt64
revokedMap<String, Int64>
droppedInt64
lockMutex

Methods

fn create(secrets: List<String>) → SessionManager
fn name(cookieName: String) → SessionManager
fn path(path: String) → SessionManager
fn domain(domain: String) → SessionManager
fn secure(enabled: Bool) → SessionManager
fn sameSite(value: String) → SessionManager
fn lifetime(seconds: Int64) → SessionManager
fn idle(seconds: Int64) → SessionManager
fn renewAfter(seconds: Int64) → SessionManager
fn maxRevocations(count: Int64) → SessionManager
fn start(ctx: HttpContext, claims: Map<String, JsonValue>) → Session
fn load(ctx: HttpContext) → Session
fn touch(ctx: HttpContext) → Session
fn rotate(ctx: HttpContext) → Session
fn end(ctx: HttpContext) → Nothing
fn endAll() → Nothing
fn revocationsDropped() → Int64
fn inspect(ctx: HttpContext, renew: Bool) → Session
fn isRevoked(id: String, issuedAt: Int64) → Bool
fn revoke(id: String, expiresAt: Int64) → Nothing
fn issue(ctx: HttpContext, s: Session) → Nothing
fnc newId() → String
fnc readCookie(ctx: HttpContext, name: String) → String