Skip to content

API Key usage as alternative for username, password, totp seed#89

Open
janjaeschke wants to merge 11 commits intohm-edu:mainfrom
noSpamProxy:Api-Key_usage
Open

API Key usage as alternative for username, password, totp seed#89
janjaeschke wants to merge 11 commits intohm-edu:mainfrom
noSpamProxy:Api-Key_usage

Conversation

@janjaeschke
Copy link
Contributor

I added a global implementation which allows the usage of API keys for authentication as described here by Harica:
https://guides.harica.gr/docs/Guides/Developer/5.-API-Keys/
The goal of the implementation was to have a global solution which can be used in general.
It is tested with the goal to request S/MIME certificates, those tests where successful.

An API key and an organization id are required to archive this.
The implementation prefers API keys over username, password, totp seed because in my opinion this should be the prefered way for automation and it stops leaking the totp seed.
If no organization id is provided I try to auto discover it, otherwise it is possible to lookup the associated organization ids.

Please let me know if this fits your code structure/base or if you require adjustments :)

@fritterhoff
Copy link
Member

Hi! And sorry for the late response.

Thanks for the PR I will have a look on it the next days. As a little background why I did not implement anything regarding the API keys: As you might have noticed, HARICA does not support anything regarding TLS/Server Certificates so I did not invest too much time to handle this change but I am pretty happy that you did ;-)

@fritterhoff fritterhoff self-requested a review January 31, 2026 06:23
@fritterhoff fritterhoff self-assigned this Jan 31, 2026
Comment on lines +310 to +327
} else {
lastPKCS7Err = err

// Fallback: scan for embedded DER certificates within the PKCS#7 blob.
if scanned := scanDERCertificates(data); len(scanned) > 0 {
chosen := scanned[0]
for _, c := range scanned {
if c != nil && !c.IsCA {
chosen = c
break
}
}
if chosen != nil {
block := &pem.Block{Type: "CERTIFICATE", Bytes: chosen.Raw}
return string(pem.EncodeToMemory(block)), nil
}
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity. Does that really happen?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sadly thats something I cannot tell at all :(
I have no direct access to Harica itself for requesting certificates. Its always a bit try and error so I tried to handle this case "just in case" :)
In the latest example I got it was clearly PEM encoded.

client/apikey.go Outdated
Comment on lines 142 to 160
var enterpriseID string
if v, ok := m["id"]; ok {
if s, ok := v.(string); ok {
enterpriseID = strings.TrimSpace(s)
}
}
var name string
if v, ok := m["name"]; ok {
if s, ok := v.(string); ok {
name = strings.TrimSpace(s)
}
}
if name == "" {
if v, ok := m["enterpriseName"]; ok {
if s, ok := v.(string); ok {
name = strings.TrimSpace(s)
}
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering a bit about these fields. I played with the API some days ago and got the following fields:

[
    {
        "organizationId": "****",
        "domain": "",
        "organization": "Hochschule für angewandte Wissenschaften München",
        "organizationLocalized": "",
        "country": "DE",
        "state": "Bayern",
        "stateLocalized": "",
        "locality": "München",
        "localityLocalized": "",
        "organizationalUnit": "",
        "organizationalUnitLocalized": null,
        "dn": "O=Hochschule für angewandte Wissenschaften München, ST=Bayern, L=München, C=DE",
        "validity": "****",
        "groupId": "****",
        "organizationIdentifier": "GOVDE\\+BY",
        "validityOV": "****",
        "validityEV": "****",
        "jurisdictionCountry": null,
        "jurisdictionState": null,
        "jurisdictionLocality": null,
        "businessCategory": null,
        "serial": null,
        "groupDomains": "****"
    }
]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect, thank you for the full example :)
My current implementation was created really defensive and I tried do align with the style of the API and common choose namings.
As mentioned above, I cannot work directly with the API.

I will update this so that the organizationID is the only used one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code updated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants