Tcl Requires Chilkat v11.0.0+
Tcl
OAuth2 Token using IdentityServer4 with Client Credentials
See more OAuth2 Examples
Demonstrates how to get an OAuth2 access token using the client credential flow with IdentityServer4.Chilkat Tcl Downloads
load ./chilkat.dll
set success 0
# This example assumes the Chilkat API to have been previously unlocked.
# See Global Unlock Sample for sample code.
set http [new_CkHttp]
# The first step is to fetch your IdentityServer4's discovery document
# (OpenID Connect defines a discovery mechanism, called OpenID Connect Discovery, where an OpenID server publishes its metadata at a well-known URL,
# typically https://server.com/.well-known/openid-configuration
set resp [new_CkHttpResponse]
set success [CkHttp_HttpNoBody $http "GET" "https://localhost:5000/.well-known/openid-configuration" $resp]
if {$success == 0} then {
puts [CkHttp_lastErrorText $http]
delete_CkHttp $http
delete_CkHttpResponse $resp
exit
}
if {[CkHttpResponse_get_StatusCode $resp] != 200} then {
puts "Received response status code [CkHttpResponse_get_StatusCode $resp]"
puts "Response body containing error text or JSON:"
puts [CkHttpResponse_bodyStr $resp]
delete_CkHttp $http
delete_CkHttpResponse $resp
exit
}
set json [new_CkJsonObject]
set success [CkJsonObject_Load $json [CkHttpResponse_bodyStr $resp]]
# We have the discovery document, which contains something like this:
# You can use this online tool to generate parsing code from sample JSON:
# Generate Parsing Code from JSON
# {
# "issuer": "https://localhost:5000",
# "jwks_uri": "https://localhost:5000/.well-known/openid-configuration/jwks",
# "authorization_endpoint": "https://localhost:5000/connect/authorize",
# "token_endpoint": "https://localhost:5000/connect/token",
# "userinfo_endpoint": "https://localhost:5000/connect/userinfo",
# "end_session_endpoint": "https://localhost:5000/connect/endsession",
# "check_session_iframe": "https://localhost:5000/connect/checksession",
# "revocation_endpoint": "https://localhost:5000/connect/revocation",
# "introspection_endpoint": "https://localhost:5000/connect/introspect",
# "frontchannel_logout_supported": true,
# "frontchannel_logout_session_supported": true,
# "backchannel_logout_supported": true,
# "backchannel_logout_session_supported": true,
# "scopes_supported": [
# "openid",
# "profile",
# "email",
# "MyCompany.profile",
# "MyCompany.Identity.WebApi",
# "MyCompany.TriHub.WebApi",
# "offline_access"
# ],
# "claims_supported": [
# "sub",
# "updated_at",
# "locale",
# "zoneinfo",
# "birthdate",
# "gender",
# "website",
# "profile",
# "preferred_username",
# "nickname",
# "middle_name",
# "given_name",
# "family_name",
# "name",
# "picture",
# "email_verified",
# "email",
# "userId",
# "groups",
# "fullname"
# ],
# "grant_types_supported": [
# "authorization_code",
# "client_credentials",
# "refresh_token",
# "implicit",
# "password"
# ],
# "response_types_supported": [
# "code",
# "token",
# "id_token",
# "id_token token",
# "code id_token",
# "code token",
# "code id_token token"
# ],
# "response_modes_supported": [
# "form_post",
# "query",
# "fragment"
# ],
# "token_endpoint_auth_methods_supported": [
# "client_secret_basic",
# "client_secret_post"
# ],
# "subject_types_supported": [
# "public"
# ],
# "id_token_signing_alg_values_supported": [
# "RS256"
# ],
# "code_challenge_methods_supported": [
# "plain",
# "S256"
# ]
# }
#
# The next steps are to (1) get the token_endpoint,
# and (2) verify that the client_credentials grant type is supported.
set tokenEndpoint [CkJsonObject_stringOf $json "token_endpoint"]
# grantTypes is a CkJsonArray
set grantTypes [CkJsonObject_ArrayOf $json "grant_types_supported"]
set clientCredentialsIdx [CkJsonArray_FindString $grantTypes "client_credentials" 1]
delete_CkJsonArray $grantTypes
# If clientCredentialsIdx is less then zero (-1) then the "client_credentials" string was not found.
if {$clientCredentialsIdx < 0} then {
puts "The client credentials grant type is not supported."
delete_CkHttp $http
delete_CkHttpResponse $resp
delete_CkJsonObject $json
exit
}
# Request the access token using our Client ID and Client Secret.
# We're going to duplicate this CURL statement:
# curl --request POST \
# --url '<tokenEndpoint>' \
# --header 'content-type: application/x-www-form-urlencoded' \
# --data 'grant_type=client_credentials&client_id=CLIENT_ID&client_secret=CLIENT_SECRET'
set req [new_CkHttpRequest]
CkHttpRequest_put_HttpVerb $req "POST"
CkHttpRequest_put_ContentType $req "application/x-www-form-urlencoded"
CkHttpRequest_AddParam $req "grant_type" "client_credentials"
CkHttpRequest_AddParam $req "client_id" "CLIENT_ID"
CkHttpRequest_AddParam $req "client_secret" "CLIENT_SECRET"CkHttpRequest_put_HttpVerb $req "POST"
set success [CkHttp_HttpReq $http $tokenEndpoint $req $resp]
if {$success == 0} then {
puts [CkHttp_lastErrorText $http]
delete_CkHttp $http
delete_CkHttpResponse $resp
delete_CkJsonObject $json
delete_CkHttpRequest $req
exit
}
# Make sure we got a 200 response status code, otherwise it's an error.
if {[CkHttpResponse_get_StatusCode $resp] != 200} then {
puts "POST to token endpoint failed."
puts "Received response status code [CkHttpResponse_get_StatusCode $resp]"
puts "Response body containing error text or JSON:"
puts [CkHttpResponse_bodyStr $resp]
delete_CkHttp $http
delete_CkHttpResponse $resp
delete_CkJsonObject $json
delete_CkHttpRequest $req
exit
}
set success [CkJsonObject_Load $json [CkHttpResponse_bodyStr $resp]]
# Our JSON response should contain this:
# {
# "access_token":"eyJz93a...k4laUWw",
# "token_type":"Bearer",
# "expires_in":86400
# }
# Get the access token:
set accessToken [CkJsonObject_stringOf $json "access_token"]
# The access token is what gets added to "Authorization: Bearer <access_token>"
# for the subsequent REST API calls..
delete_CkHttp $http
delete_CkHttpResponse $resp
delete_CkJsonObject $json
delete_CkHttpRequest $req